allthingssecurity opened a new pull request, #29440: URL: https://github.com/apache/camel/pull/29440
# Description [CAMEL-26736](https://issues.apache.org/jira/browse/CAMEL-26736) The same two fixes as CAMEL-26708 (#29405) for `JdbcKeyValueRepository`, here for `JpaKeyValueRepository` in camel-jpa. **putIfAbsent.** When two repositories on one database inserted the same key, the `persist` + `flush` of the loser failed with a constraint violation, and the key was read again with `findByKey` in the same transaction. The failed flush had marked that transaction for rollback, so the loser's `putIfAbsent` failed on commit (`DataIntegrityViolationException` with the Spring based `DefaultTransactionStrategy`) instead of returning the value of the winner. An expired entry was updated in place with `merge`; `KeyValueEntry` has no version, so two callers that both read it as expired both updated it and both returned `null`: both won. **Lazy expiry.** `get`, `contains` and `delete` removed an expired entry with `entityManager.remove`, which deletes by primary key. An entry that another node stored for the key after it was read was deleted with it. Change: - `putIfAbsent` lets the constraint violation roll back the transaction and reads the key again in a new transaction, which returns the stored value or inserts again; after 3 failed inserts the `PersistenceException` is thrown. A constraint violation is also recognised by its SQL state (class `23`), as the PostgreSQL and SQL Server drivers report a duplicate key with a plain `SQLException` that the JPA provider wraps. An expired entry is deleted (only while it is still expired) and the key inserted, so the primary key decides between callers for an expired entry as well. - An expired entry is deleted with a JPQL `delete ... where e.itemKey = ?1 and e.expiresAt > 0 and e.expiresAt <= ?2`, so an entry stored again meanwhile is kept. - No reference to Spring classes is added to `JpaKeyValueRepository` (CAMEL-26106). In a transaction of the caller, the failed insert marks that transaction for rollback (as on main), so the caller's transaction fails. Unlike #29405, which throws at once when it joined a transaction of the caller, `putIfAbsent` cannot tell that here: `TransactionStrategy` exposes no transaction status, and this class must not reference Spring classes (CAMEL-26106). So attempts 2 and 3 run in that transaction and may return the winner's value or fail; the caller's commit fails either way, as on main. Docs: the `JpaKeyValueRepository` row and note of `keyValueRepository.adoc` (and its catalog copy), and an entry in the 4.24 upgrade guide. #29405 rewords the same note, so whichever of the two is merged second needs a small rebase of that paragraph. Tests: `JpaKeyValueRepositoryConcurrencyTest` runs two repositories on one embedded H2 database (OpenJPA, as `JpaKeyValueRepositoryTest`). The entity manager operations of node A go through a proxy that can pause them, so the calls of both nodes interleave in a given order (no sleeps): - the loser of an insert race gets the value of the winner, also when the driver reports the duplicate key only by its SQL state; - if the winner's entry is deleted before the loser reads the key again, the loser stores its value; - of two callers that read the same expired entry, one wins and the other gets its value; - reading an expired entry keeps the entry another node stored meanwhile; - `putIfAbsent` gives up after 3 constraint violations. On main all 6 fail (`DataIntegrityViolationException` for the insert races, `null` / both winning for the expiry tests). Mutants: `remove` back in `get` → only the read-expiry test fails; 1 attempt instead of 3 → the five tests that need a second attempt fail; no SQL state check → only the SQL state test fails. With the fix 6/6, and 600/600 over 20 runs together with `JpaKeyValueRepositoryTest`. camel-jpa module tests: 139 run, 0 failures, 1 skipped (offline). # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it): [CAMEL-26736](https://issues.apache.org/jira/browse/CAMEL-26736). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (I built the core modules and camel-jpa with the formatter and import-sort plugins and ran the module tests; no generated file changes, and the catalog copy of `keyValueRepository.adoc` is identical. I did not run the full root build.) # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a `Co-Authored-By` trailer. _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
