I have a query where I'd like to retrieve a huge amount of rows based on their pk ids, and use select .... where id in (<ids>) via the fluent api in JDBI like this:
jdbi(db).withHandle(h --> handle.createQuery(SQL).bindList("ids", listOfIds).mapToMap().list();
This works for as long as the number of ids doesn't exceed what the database (DB2) can handle in an in-clause. Obviously, in my case, the list of id's gets longer than Db2 can handle. So I split it into many in a List<List<Integer>> listOfIdLists and create a List<Map<String, Object>> result.
Now I have to somehow iterate over listOfIdLists and for each iteration add the result to result. Here is one of many tested variants:
List<Map<String, Object>> result = new ArrayList<>();
List<List<Integer>> listOfIdLists = chopListToLists(ids, 10);
Iterator<List<Integer>> oneChopIterator = listOfIdLists.iterator();
while (oneChopIterator.hasNext()) {
result.addAll(jdbi(db).withHandle(handle --> handle.createQuery(SQL).bindList("id", oneChopIterator.next()).mapToMap().list()));
}
Obviously variants with chops.forEach and try (Handle h = jdbi(db).open();) { /* iterate and addAll */ } has been tried also.
All of this run in a Quarkus app, and I get exceptions from Arjuna when iterating. For testing, I can add to result without errors when there is no iterating, and I instead just pick the first element/list in chops.
The exception is:
2022-11-02 00:13:15,219 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check processing TX 0:ffff7f000101:925d:6361a7cf:0 in state RUN
2022-11-02 00:13:15,239 WARN [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012095: Abort of action id 0:ffff7f000101:925d:6361a7cf:0 invoked while multiple threads active within it.
2022-11-02 00:13:15,242 WARN [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012381: Action id 0:ffff7f000101:925d:6361a7cf:0 completed with multiple threads - thread Quarkus Main Thread was in progress with [email protected]/sun.nio.ch.SocketDispatcher.read0(Native Method)
[email protected]/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:47)
[email protected]/sun.nio.ch.NioSocketImpl.tryRead(NioSocketImpl.java:261)
...
2022-11-02 00:13:15,244 WARN [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012108: CheckedAction::check - atomic action 0:ffff7f000101:925d:6361a7cf:0 aborting with 1 threads active!
2022-11-02 00:13:15,315 WARN [io.agr.pool] (Transaction Reaper Worker 0) Datasource 'fs': JDBC resources leaked: 0 ResultSet(s) and 1 Statement(s)
2022-11-02 00:13:15,340 ERROR [no.cen.bat.dbs.Runner] (Quarkus Main Thread) dbsync 2 failed with throwable Unable to advance result set [statement:"select ...
...
2022-11-02 00:13:15,360 ERROR [no.cen.bat.dbs.Runner] (Quarkus Main Thread) org.jdbi.v3.core.result.ResultSetException: Unable to advance result set [statement:"select ...
...
Caused by: com.ibm.db2.jcc.am.SqlException: [jcc][t4][10120][10898][4.31.10] Invalid operation: result set is closed. ERRORCODE=-4470, SQLSTATE=null
at com.ibm.db2.jcc.am.b7.a(b7.java:794)
...
2022-11-02 00:13:15,739 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check processing TX 0:ffff7f000101:925d:6361a7cf:0 in state CANCEL
2022-11-02 00:13:15,741 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012378: ReaperElement appears to be wedged: [email protected]/sun.nio.ch.SocketDispatcher.read0(Native Method)
[email protected]/sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:47)
...
2022-11-02 00:13:16,242 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check processing TX 0:ffff7f000101:925d:6361a7cf:0 in state CANCEL_INTERRUPTED
2022-11-02 00:13:16,244 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012120: TransactionReaper::check worker Thread[Transaction Reaper Worker 0,5,main] not responding to interrupt when cancelling TX 0:ffff7f000101:925d:6361a7cf:0 -- worker marked as zombie and TX scheduled for mark-as-rollback
2022-11-02 00:13:21,478 WARN [com.arj.ats.arjuna] (Transaction Reaper) ARJUNA012110: TransactionReaper::check successfuly marked TX 0:ffff7f000101:925d:6361a7cf:0 as rollback only
2022-11-02 00:13:21,479 WARN [com.arj.ats.arjuna] (Quarkus Main Thread) ARJUNA012077: Abort called on already aborted atomic action 0:ffff7f000101:925d:6361a7cf:0
2022-11-02 00:13:21,480 WARN [com.arj.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012113: TransactionReaper::doCancellations worker Thread[Transaction Reaper Worker 0,5,main] missed interrupt when cancelling TX 0:ffff7f000101:925d:6361a7cf:0 -- exiting as zombie (zombie count decremented to 0)
This runs on Java 17 with latest Quarkus (2.13.3) and the ibm-drivers that come with quarkus-jdbc-db2. Jdbi version 3.34.0. Not running a native image.
The reason for the parameterized jdbi(db) is that the application has two datasources. It is replacing a db-job where two databases are linked and stuff copied from one database to the other with statements like insert into db1.mytable(a,b,c...) select a,b,c ... from db2.mytable where not exists (...);
The source db is on linux and the target on zOs. The app runs on Ubuntu 20.04.
So basically what the code do, is to retrieve all pk ids from each table in each database, use CollectionUtils.subtract(list1, list2) to identify ids missing from the target table, and then use the resulting list of ids to retrive the full rows via a select ... from ... where ids in (<ids>) query as described above. The list of Map<String, Object> which would be the result rows, would then be inserted into the other table where they are missing.
The question is; How to get this working without exceptions? I can brute-force this by deleting and inserting all rows, but I'd rather not.
The stacktrace element:
shows the narayana Transaction Reaper thread, it's responsible for timing out transactions, attempting to rollback the transaction. The text "atomic action 0:ffff7f000101:925d:6361a7cf:0 aborting with 1 threads active!" is saying that there is an application thread still running with the transaction context bound to the application thread. This is normal application behavior and the usual fix for this problem is to either extend the timeout, do less work inside the transaction add more compute/networking resources to the setup.