shashank created CAMEL-26736:
--------------------------------
Summary: camel-jpa - JpaKeyValueRepository putIfAbsent: the loser
of an insert race fails, two callers can win an expired entry, and reading an
expired entry can delete a live one
Key: CAMEL-26736
URL: https://issues.apache.org/jira/browse/CAMEL-26736
Project: Camel
Issue Type: Bug
Components: camel-jpa
Reporter: shashank
Assignee: shashank
CAMEL-26708 fixes two patterns in {{JdbcKeyValueRepository}} (camel-sql).
{{JpaKeyValueRepository}} has the same two patterns; it is a different module,
so it was left out of that PR (apache/camel#29405).
*putIfAbsent*: when {{persist}} + {{flush}} fails with a constraint violation
(another node inserted the key), the key is read again with {{findByKey}} in
the same transaction. The failed flush has marked that transaction for
rollback, so the commit fails and the losing caller gets an exception
({{DataIntegrityViolationException}} with the Spring based
{{DefaultTransactionStrategy}}) instead of the value of the winner. When the
entry is expired, {{putIfAbsent}} updates it in place with {{merge}};
{{KeyValueEntry}} has no {{@Version}}, so two nodes that both read the expired
entry both update it and both return {{null}}: both win, and
{{KeyValueIdempotentRepository.add}} lets the same message through on both.
*Lazy expiry*: {{get}} (and {{contains}}, {{delete}}) finds an expired entry
and deletes it with {{entityManager.remove}}, which deletes by primary key. If
another node stored the key between the read and the delete, its live entry is
deleted.
*Expected*: one winner per key across nodes, and an expired entry is deleted
only while it is still expired.
*Suggested fix*, as in CAMEL-26708: let the constraint violation roll back the
transaction and read the key again in a new transaction (bounded attempts), let
the primary key decide for an expired entry as well (delete it while it is
still expired, then insert), and delete an expired entry with a JPQL {{DELETE
... WHERE itemKey = ?1 AND expiresAt > 0 AND expiresAt <= ?2}} instead of
{{remove}}. Tests can use two repositories on one embedded database, as
{{JdbcKeyValueRepositoryConcurrencyTest}} in apache/camel#29405 does.
*Affected*: main (reproduced with H2 and OpenJPA, two repositories on one
database) and 4.23.0 (read; the class is new in 4.23).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)