Federico Mariani created CAMEL-24093:
----------------------------------------

             Summary: camel-file: idempotent read-lock strategies compute the 
release key from the post-preMove path - keys leak and same-named files are 
never consumed again
                 Key: CAMEL-24093
                 URL: https://issues.apache.org/jira/browse/CAMEL-24093
             Project: Camel
          Issue Type: Bug
          Components: camel-file
    Affects Versions: 4.21.0
            Reporter: Federico Mariani
         Attachments: FileIdempotentReadLockPreMoveRollbackIssueTest.java

h3. Problem
{{FileIdempotentRepositoryReadLockStrategy.asKey}} 
(FileIdempotentRepositoryReadLockStrategy.java:278-287) - and the same pattern 
in {{FileIdempotentChangedRepositoryReadLockStrategy}} (315-324) and 
{{FileIdempotentRenameRepositoryReadLockStrategy}} (229-238) - uses 
{{file.getAbsoluteFilePath()}} directly. {{acquireExclusiveReadLock}} stores 
key = *original* absolute path; {{GenericFileRenameProcessStrategy.begin}} 
({{preMove}}) then renames the file and rebinds the exchange to the renamed 
{{GenericFile}}, so release on commit/rollback computes the key from the 
*pre-moved* path: {{remove}}/{{confirm}} target a key that was never added, and 
the original-path key stays in the repository forever.

h3. Failure scenario
{{readLock=idempotent}} (or {{idempotent-changed}}/{{idempotent-rename}}) + 
{{preMove}}: after any rollback (default {{readLockRemoveOnRollback=true}}), a 
new file arriving later under the same original name is silently never consumed 
({{idempotentRepository.add()}} fails -> "Cannot acquire read lock. Will skip 
the file"). With {{readLockRemoveOnCommit=true}}, keys accumulate unbounded and 
same-name files are blocked too.

h3. History
The sibling strategies were explicitly fixed for exactly this scenario: 
{{MarkerFileExclusiveReadLockStrategy.asReadLockKey}} and 
{{GenericFileHelper.asExclusiveReadLockKey}} both fall back to 
{{getCopyFromAbsoluteFilePath()}} with a comment naming preMove ("use the copy 
from absolute path as that was the original path of the file when the lock was 
acquired"). The idempotent trio (CAMEL-10087 era) never received that handling. 
No test in the repo combines {{preMove}} with {{readLock=idempotent*}}.

Secondary defect in the same classes: {{releaseExclusiveReadLockOnAbort}} is a 
no-op, so an acquire-succeeded-then-begin-threw sequence (e.g. the preMove 
rename itself fails) also leaks the key even without a path mismatch.

h3. Suggested fix
Apply the {{copyFromAbsoluteFilePath}} fallback pattern in {{asKey}} of all 
three strategies (and evaluate the expression-based key against the original 
file, mirroring {{GenericFileHelper.asExclusiveReadLockKey}}).

h3. Reproducer
Attached failing JUnit test (place in 
{{core/camel-core/src/test/java/org/apache/camel/component/file/}}, where the 
file component tests live). Consumer with 
{{readLock=idempotent&preMove=work/...}} and an always-failing route; asserts 
the original-path key is removed from the repository on rollback - on current 
main it remains (the wrong key was removed).

----
_This issue was researched and filed by Claude Code on behalf of [~croway] 
(GitHub: Croway), as part of a deep code review of camel-file and camel-ftp. A 
failing JUnit reproducer is attached; it fails deterministically on current 
main (4.22.0-SNAPSHOT)._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to