@@ -57,6 +57,7 @@ class LmdbRecordIterator implements RecordIterator {
5757
5858 private boolean matchValues ;
5959 private GroupMatcher groupMatcher ;
60+ private GroupMatcher matcherForEvaluation ;
6061
6162 /**
6263 * True when late-bound variables exist beyond the contiguous prefix of the chosen index order, requiring
@@ -131,7 +132,7 @@ void initialize(TripleIndex index, KeyBuilder keyBuilder, boolean rangeSearch, l
131132 long context , boolean explicit , Txn txnRef , long [] quadReuse , ByteBuffer minKeyBufParam ,
132133 ByteBuffer maxKeyBufParam ) throws IOException {
133134 if (initialized && !closed ) {
134- throw new IllegalStateException ( "Cannot initialize LMDB record iterator while it is open" );
135+ // prepareForReuse( );
135136 }
136137 initializeInternal (index , keyBuilder , rangeSearch , subj , pred , obj , context , explicit , txnRef , quadReuse ,
137138 minKeyBufParam , maxKeyBufParam );
@@ -141,12 +142,27 @@ void initialize(TripleIndex index, KeyBuilder keyBuilder, boolean rangeSearch, l
141142 private void initializeInternal (TripleIndex index , KeyBuilder keyBuilder , boolean rangeSearch , long subj ,
142143 long pred , long obj , long context , boolean explicit , Txn txnRef , long [] quadReuse ,
143144 ByteBuffer minKeyBufParam , ByteBuffer maxKeyBufParam ) throws IOException {
145+
146+ // if (!initialized) {
147+ // System.out.println();
148+ // } else {
149+ // System.out.println();
150+ // }
151+
144152 this .index = index ;
153+ long prevSubj = this .subj ;
154+ long prevPred = this .pred ;
155+ long prevObj = this .obj ;
156+ long prevContext = this .context ;
157+
145158 this .subj = subj ;
146159 this .pred = pred ;
147160 this .obj = obj ;
148161 this .context = context ;
149162
163+ boolean prevExternalMinKeyBuf = this .externalMinKeyBuf ;
164+ boolean prevExternalMaxKeyBuf = this .externalMaxKeyBuf ;
165+
150166 if (quadReuse != null && quadReuse .length >= 4 ) {
151167 this .quad = quadReuse ;
152168 } else if (this .quad == null || this .quad .length < 4 ) {
@@ -166,20 +182,36 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
166182
167183 if (rangeSearch ) {
168184 this .externalMinKeyBuf = minKeyBufParam != null ;
169- this .minKeyBuf = externalMinKeyBuf ? minKeyBufParam : pool .getKeyBuffer ();
185+ if (externalMinKeyBuf ) {
186+ this .minKeyBuf = minKeyBufParam ;
187+ } else {
188+ if (this .minKeyBuf == null || prevExternalMinKeyBuf ) {
189+ this .minKeyBuf = pool .getKeyBuffer ();
190+ } else {
191+ this .minKeyBuf .clear ();
192+ }
193+ }
170194 minKeyBuf .clear ();
171195 if (keyBuilder != null ) {
172196 keyBuilder .writeMin (minKeyBuf );
173197 } else {
174- index .getMinKey (minKeyBuf , subj , pred , obj , context );
198+ index .getMinKey (minKeyBuf , subj , pred , obj , context , prevSubj , prevPred , prevObj , prevContext );
175199 }
176200 minKeyBuf .flip ();
177201
178202 if (this .maxKey == null ) {
179203 this .maxKey = pool .getVal ();
180204 }
181205 this .externalMaxKeyBuf = maxKeyBufParam != null ;
182- this .maxKeyBuf = externalMaxKeyBuf ? maxKeyBufParam : pool .getKeyBuffer ();
206+ if (externalMaxKeyBuf ) {
207+ this .maxKeyBuf = maxKeyBufParam ;
208+ } else {
209+ if (this .maxKeyBuf == null || prevExternalMaxKeyBuf ) {
210+ this .maxKeyBuf = pool .getKeyBuffer ();
211+ } else {
212+ this .maxKeyBuf .clear ();
213+ }
214+ }
183215 maxKeyBuf .clear ();
184216 if (keyBuilder != null ) {
185217 keyBuilder .writeMax (maxKeyBuf );
@@ -193,24 +225,38 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
193225 pool .free (maxKey );
194226 this .maxKey = null ;
195227 }
196- if (this .maxKeyBuf != null && !externalMaxKeyBuf ) {
228+ if (this .maxKeyBuf != null && !prevExternalMaxKeyBuf ) {
197229 pool .free (maxKeyBuf );
230+ this .maxKeyBuf = null ;
198231 }
199232 this .externalMaxKeyBuf = maxKeyBufParam != null ;
200233 this .maxKeyBuf = externalMaxKeyBuf ? maxKeyBufParam : null ;
201234
202235 if (subj > 0 || pred > 0 || obj > 0 || context >= 0 ) {
203236 this .externalMinKeyBuf = minKeyBufParam != null ;
204- this .minKeyBuf = externalMinKeyBuf ? minKeyBufParam : pool .getKeyBuffer ();
237+ if (externalMinKeyBuf ) {
238+ this .minKeyBuf = minKeyBufParam ;
239+ } else {
240+ if (this .minKeyBuf == null || prevExternalMinKeyBuf ) {
241+ this .minKeyBuf = pool .getKeyBuffer ();
242+ } else {
243+ this .minKeyBuf .clear ();
244+ }
245+ }
205246 minKeyBuf .clear ();
206- index .getMinKey (minKeyBuf , subj , pred , obj , context );
247+ index .getMinKey (minKeyBuf , subj , pred , obj , context , prevSubj , prevPred , prevObj , prevContext );
207248 minKeyBuf .flip ();
208249 } else {
209- if (this .minKeyBuf != null && !externalMinKeyBuf ) {
250+ if (this .minKeyBuf != null && !prevExternalMinKeyBuf ) {
210251 pool .free (minKeyBuf );
252+ this .minKeyBuf = null ;
211253 }
212254 this .externalMinKeyBuf = minKeyBufParam != null ;
213- this .minKeyBuf = externalMinKeyBuf ? minKeyBufParam : null ;
255+ if (externalMinKeyBuf ) {
256+ this .minKeyBuf = minKeyBufParam ;
257+ } else {
258+ this .minKeyBuf = null ;
259+ }
214260 }
215261 }
216262
@@ -219,13 +265,16 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
219265 int boundCount = (subj > 0 ? 1 : 0 ) + (pred > 0 ? 1 : 0 ) + (obj > 0 ? 1 : 0 ) + (context >= 0 ? 1 : 0 );
220266 this .needMatcher = boundCount > prefixLen ;
221267 this .groupMatcher = null ;
268+ this .matcherForEvaluation = null ;
222269 this .fetchNext = false ;
223270 this .lastResult = MDB_SUCCESS ;
224271 this .closed = false ;
225272
226- this .dbi = index .getDB (explicit );
227- this .txnRef = txnRef ;
228- this .txnLockManager = txnRef .lockManager ();
273+ if (!initialized ) {
274+ this .dbi = index .getDB (explicit );
275+ this .txnRef = txnRef ;
276+ this .txnLockManager = txnRef .lockManager ();
277+ }
229278
230279 long readStamp ;
231280 try {
@@ -239,9 +288,12 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
239288
240289 // Try to reuse a pooled cursor only for read-only transactions; otherwise open a new one
241290 if (txnRef .isReadOnly ()) {
242- long pooled = pool .getCursor (dbi , index );
243- if (pooled != 0L ) {
244- long c = pooled ;
291+ if (cursor == 0L ) {
292+ cursor = pool .getCursor (dbi , index );
293+ }
294+
295+ if (cursor != 0L ) {
296+ long c = cursor ;
245297 try {
246298 E (mdb_cursor_renew (txn , c ));
247299 } catch (IOException renewEx ) {
@@ -262,6 +314,11 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
262314 }
263315 }
264316 } else {
317+ if (cursor != 0L ) {
318+ pool .freeCursor (dbi , index , cursor );
319+ cursor = 0L ;
320+ }
321+
265322 try (MemoryStack stack = MemoryStack .stackPush ()) {
266323 PointerBuffer pp = stack .mallocPointer (1 );
267324 E (mdb_cursor_open (txn , dbi , pp ));
@@ -276,7 +333,6 @@ private void initializeInternal(TripleIndex index, KeyBuilder keyBuilder, boolea
276333 @ Override
277334 public long [] next () {
278335 if (closed ) {
279- log .debug ("Calling next() on an LmdbRecordIterator that is already closed, returning null" );
280336 return null ;
281337 }
282338 StampedLongAdderLockManager manager = txnLockManager ;
@@ -345,7 +401,7 @@ public long[] next() {
345401 return quad ;
346402 }
347403 }
348- closeInternal (false );
404+ // closeInternal(false);
349405 return null ;
350406 } finally {
351407 manager .unlockRead (readStamp );
@@ -358,16 +414,39 @@ private boolean matches() {
358414 return false ;
359415 }
360416
361- if (groupMatcher != null ) {
362- return !this . groupMatcher .matches (keyData .mv_data ());
417+ if (matcherForEvaluation != null ) {
418+ return !matcherForEvaluation .matches (keyData .mv_data ());
363419 } else if (matchValues ) {
364- this .groupMatcher = index .createMatcher (subj , pred , obj , context );
365- return !this .groupMatcher .matches (keyData .mv_data ());
420+ matcherForEvaluation = index .createMatcher (subj , pred , obj , context );
421+ groupMatcher = matcherForEvaluation ;
422+ return !matcherForEvaluation .matches (keyData .mv_data ());
366423 } else {
367424 return false ;
368425 }
369426 }
370427
428+ private void prepareForReuse () {
429+ if (cursor != 0L && txnRef != null ) {
430+ if (txnRef .isReadOnly ()) {
431+ pool .freeCursor (dbi , index , cursor );
432+ } else {
433+ mdb_cursor_close (cursor );
434+ }
435+ }
436+ cursor = 0L ;
437+ groupMatcher = null ;
438+ matcherForEvaluation = null ;
439+ fetchNext = false ;
440+ lastResult = MDB_SUCCESS ;
441+ matchValues = false ;
442+ needMatcher = false ;
443+ txnRef = null ;
444+ txn = 0L ;
445+ txnRefVersion = 0L ;
446+ txnLockManager = null ;
447+ closed = true ;
448+ }
449+
371450 private void closeInternal (boolean maybeCalledAsync ) {
372451 StampedLongAdderLockManager manager = this .txnLockManager ;
373452 if (closed ) {
@@ -414,7 +493,10 @@ private void closeInternal(boolean maybeCalledAsync) {
414493 maxKeyBuf = null ;
415494 externalMinKeyBuf = false ;
416495 externalMaxKeyBuf = false ;
417- groupMatcher = null ;
496+ if (maybeCalledAsync ) {
497+ groupMatcher = null ;
498+ }
499+ matcherForEvaluation = null ;
418500 fetchNext = false ;
419501 lastResult = 0 ;
420502 matchValues = false ;
0 commit comments