From 6011a45677a87b54789041460a69589a1f9a80f7 Mon Sep 17 00:00:00 2001 From: Ken Wenzel Date: Mon, 20 May 2024 14:55:13 +0200 Subject: [PATCH] Wrap logic of gcIds into read txn to fix problem with read lock. --- .../eclipse/rdf4j/sail/lmdb/ValueStore.java | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java index b1a39c7e08..c25c6f12b2 100644 --- a/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java +++ b/core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/ValueStore.java @@ -558,10 +558,7 @@ private void resizeMap(long txn, long requiredSize) throws IOException { if (autoGrow) { if (LmdbUtil.requiresResize(mapSize, pageSize, txn, requiredSize)) { // map is full, resize - boolean suspendReadTxn = txn != writeTxn; - if (suspendReadTxn) { - txnLock.readLock().unlock(); - } + txnLock.readLock().unlock(); txnLock.writeLock().lock(); try { boolean activeWriteTxn = writeTxn != 0; @@ -582,9 +579,7 @@ private void resizeMap(long txn, long requiredSize) throws IOException { } } finally { txnLock.writeLock().unlock(); - if (suspendReadTxn) { - txnLock.readLock().lock(); - } + txnLock.readLock().lock(); } } } @@ -904,37 +899,41 @@ public long getId(Value value, boolean create) throws IOException { public void gcIds(Collection ids, Collection nextIds) throws IOException { if (!ids.isEmpty()) { - // contains IDs for data types and namespaces which are freed by garbage collecting literals and URIs - resizeMap(writeTxn, 2 * ids.size() * (1 + Long.BYTES + 2 + Long.BYTES)); - - final Collection finalIds = ids; - final Collection finalNextIds = nextIds; - writeTransaction((stack, writeTxn) -> { - MDBVal revIdVal = MDBVal.calloc(stack); - MDBVal idVal = MDBVal.calloc(stack); - MDBVal dataVal = MDBVal.calloc(stack); - - ByteBuffer revIdBb = stack.malloc(1 + Long.BYTES + 2 + Long.BYTES); - Varint.writeUnsigned(revIdBb, revision.getRevisionId()); - int revLength = revIdBb.position(); - for (Long id : finalIds) { - revIdBb.position(revLength).limit(revIdBb.capacity()); - revIdVal.mv_data(id2data(revIdBb, id).flip()); - // check if id has internal references and therefore cannot be deleted - idVal.mv_data(revIdBb.slice().position(revLength)); - if (mdb_get(writeTxn, refCountsDbi, idVal, dataVal) == 0) { - continue; + // wrap into read txn as resizeMap expects an active surrounding read txn + readTransaction(env, (stack1, txn1) -> { + // contains IDs for data types and namespaces which are freed by garbage collecting literals and URIs + resizeMap(writeTxn, 2 * ids.size() * (1 + Long.BYTES + 2 + Long.BYTES)); + + final Collection finalIds = ids; + final Collection finalNextIds = nextIds; + writeTransaction((stack, writeTxn) -> { + MDBVal revIdVal = MDBVal.calloc(stack); + MDBVal idVal = MDBVal.calloc(stack); + MDBVal dataVal = MDBVal.calloc(stack); + + ByteBuffer revIdBb = stack.malloc(1 + Long.BYTES + 2 + Long.BYTES); + Varint.writeUnsigned(revIdBb, revision.getRevisionId()); + int revLength = revIdBb.position(); + for (Long id : finalIds) { + revIdBb.position(revLength).limit(revIdBb.capacity()); + revIdVal.mv_data(id2data(revIdBb, id).flip()); + // check if id has internal references and therefore cannot be deleted + idVal.mv_data(revIdBb.slice().position(revLength)); + if (mdb_get(writeTxn, refCountsDbi, idVal, dataVal) == 0) { + continue; + } + // mark id as unused + E(mdb_put(writeTxn, unusedDbi, revIdVal, dataVal, 0)); } - // mark id as unused - E(mdb_put(writeTxn, unusedDbi, revIdVal, dataVal, 0)); - } - deleteValueToIdMappings(stack, writeTxn, finalIds, finalNextIds); + deleteValueToIdMappings(stack, writeTxn, finalIds, finalNextIds); - invalidateRevisionOnCommit = true; - if (nextValueEvictionTime < 0) { - nextValueEvictionTime = System.currentTimeMillis() + VALUE_EVICTION_INTERVAL; - } + invalidateRevisionOnCommit = true; + if (nextValueEvictionTime < 0) { + nextValueEvictionTime = System.currentTimeMillis() + VALUE_EVICTION_INTERVAL; + } + return null; + }); return null; }); }