@@ -54,26 +54,26 @@ RecordIterator get(long[] quadReuse, ByteBuffer minKeyBuf, ByteBuffer maxKeyBuf,
5454 /** Size in bytes of one (v3,v4) tuple. */
5555 private static final int DUP_PAIR_BYTES = Long .BYTES * 2 ;
5656
57- private final Pool pool ;
58- private final DupIndex index ;
59- private final int dupDbi ;
60- private final long cursor ;
57+ private final Pool pool = Pool . get () ;
58+ private DupIndex index ;
59+ private int dupDbi ;
60+ private long cursor ;
6161
62- private final Txn txnRef ;
62+ private Txn txnRef ;
6363 private long txn ; // refreshed on txn version changes
6464 private long txnRefVersion ;
65- private final StampedLongAdderLockManager txnLockManager ;
65+ private StampedLongAdderLockManager txnLockManager ;
6666 private final Thread ownerThread = Thread .currentThread ();
6767
68- private final MDBVal keyData ;
69- private final MDBVal valueData ;
68+ private MDBVal keyData ;
69+ private MDBVal valueData ;
7070
7171 /** Reused output buffer required by the RecordIterator API. */
72- private final long [] quad ;
72+ private long [] quad ;
7373
7474 /** Scalars defining the prefix to scan (subject, predicate). */
75- private final long prefixSubj ;
76- private final long prefixPred ;
75+ private long prefixSubj ;
76+ private long prefixPred ;
7777
7878 private ByteBuffer prefixKeyBuf ;
7979
@@ -83,33 +83,67 @@ RecordIterator get(long[] quadReuse, ByteBuffer minKeyBuf, ByteBuffer maxKeyBuf,
8383 private int dupLimit ;
8484
8585 private int lastResult ;
86- private boolean closed = false ;
86+ private boolean closed = true ;
8787
88- private final RecordIterator fallback ;
89- private final FallbackSupplier fallbackSupplier ;
88+ private RecordIterator fallback ;
89+ private FallbackSupplier fallbackSupplier ;
9090
9191 LmdbDupRecordIterator (DupIndex index , long subj , long pred ,
9292 boolean explicit , Txn txnRef , FallbackSupplier fallbackSupplier ) throws IOException {
93+ initialize (index , subj , pred , explicit , txnRef , null , fallbackSupplier );
94+ }
95+
96+ LmdbDupRecordIterator (DupIndex index , long subj , long pred ,
97+ boolean explicit , Txn txnRef , long [] quadReuse , FallbackSupplier fallbackSupplier ) throws IOException {
98+ initialize (index , subj , pred , explicit , txnRef , quadReuse , fallbackSupplier );
99+ }
100+
101+ void initialize (DupIndex index , long subj , long pred , boolean explicit , Txn txnRef , long [] quadReuse ,
102+ FallbackSupplier fallbackSupplier ) throws IOException {
103+ if (!closed || fallback != null ) {
104+ throw new IllegalStateException ("Cannot initialize LMDB dup iterator while it is open" );
105+ }
106+
93107 this .index = index ;
108+ this .dupDbi = index .getDupDB (explicit );
109+ this .txnRef = txnRef ;
110+ this .txnLockManager = txnRef .lockManager ();
111+ this .fallbackSupplier = fallbackSupplier ;
112+ this .fallback = null ;
113+
114+ this .prefixSubj = subj ;
115+ this .prefixPred = pred ;
94116
95- // Output buffer (s,p are constant for the life of this iterator)
96- this .quad = new long [4 ];
117+ if (quadReuse != null && quadReuse .length >= 4 ) {
118+ this .quad = quadReuse ;
119+ } else if (this .quad == null || this .quad .length < 4 ) {
120+ this .quad = new long [4 ];
121+ }
97122 this .quad [0 ] = subj ;
98123 this .quad [1 ] = pred ;
99124 this .quad [2 ] = -1L ;
100125 this .quad [3 ] = -1L ;
101126
102- this .prefixSubj = subj ;
103- this .prefixPred = pred ;
127+ if (this .keyData == null ) {
128+ this .keyData = pool .getVal ();
129+ }
130+ if (this .valueData == null ) {
131+ this .valueData = pool .getVal ();
132+ }
104133
105- this .fallbackSupplier = fallbackSupplier ;
134+ if (this .prefixKeyBuf == null ) {
135+ this .prefixKeyBuf = pool .getKeyBuffer ();
136+ }
137+ prefixKeyBuf .clear ();
138+ Varint .writeUnsigned (prefixKeyBuf , prefixSubj );
139+ Varint .writeUnsigned (prefixKeyBuf , prefixPred );
140+ prefixKeyBuf .flip ();
106141
107- this .pool = Pool .get ();
108- this .keyData = pool .getVal ();
109- this .valueData = pool .getVal ();
110- this .dupDbi = index .getDupDB (explicit );
111- this .txnRef = txnRef ;
112- this .txnLockManager = txnRef .lockManager ();
142+ this .dupBuf = null ;
143+ this .dupPos = 0 ;
144+ this .dupLimit = 0 ;
145+ this .lastResult = MDB_SUCCESS ;
146+ this .closed = false ;
113147
114148 RecordIterator fallbackIterator = null ;
115149
@@ -125,13 +159,6 @@ RecordIterator get(long[] quadReuse, ByteBuffer minKeyBuf, ByteBuffer maxKeyBuf,
125159
126160 cursor = openCursor (txn , dupDbi , txnRef .isReadOnly ());
127161
128- prefixKeyBuf = pool .getKeyBuffer ();
129- prefixKeyBuf .clear ();
130- Varint .writeUnsigned (prefixKeyBuf , prefixSubj );
131- Varint .writeUnsigned (prefixKeyBuf , prefixPred );
132- // index.toDupKeyPrefix(prefixKeyBuf, subj, pred, 0, 0);
133- prefixKeyBuf .flip ();
134-
135162 boolean positioned = positionOnPrefix ();
136163 if (positioned ) {
137164 positioned = primeDuplicateBlock ();
@@ -340,22 +367,35 @@ private void closeInternal(boolean maybeCalledAsync) {
340367 }
341368 try {
342369 if (!closed ) {
343- if (txnRef .isReadOnly ()) {
344- pool .freeCursor (dupDbi , index , cursor );
345- } else {
346- mdb_cursor_close (cursor );
370+ if (cursor != 0L && txnRef != null ) {
371+ if (txnRef .isReadOnly ()) {
372+ pool .freeCursor (dupDbi , index , cursor );
373+ } else {
374+ mdb_cursor_close (cursor );
375+ }
376+ }
377+ cursor = 0L ;
378+ if (keyData != null ) {
379+ pool .free (keyData );
380+ keyData = null ;
381+ }
382+ if (valueData != null ) {
383+ pool .free (valueData );
384+ valueData = null ;
347385 }
348- pool .free (keyData );
349- pool .free (valueData );
350386 if (prefixKeyBuf != null ) {
351387 pool .free (prefixKeyBuf );
388+ prefixKeyBuf = null ;
352389 }
353390 }
354391 } finally {
355392 closed = true ;
356393 if (writeLocked ) {
357394 txnLockManager .unlockWrite (writeStamp );
358395 }
396+ txnRef = null ;
397+ dupBuf = null ;
398+ dupPos = dupLimit = 0 ;
359399 }
360400 }
361401 }
@@ -364,9 +404,14 @@ private void closeInternal(boolean maybeCalledAsync) {
364404 public void close () {
365405 if (fallback != null ) {
366406 fallback .close ();
407+ fallback = null ;
408+ fallbackSupplier = null ;
367409 } else {
368410 closeInternal (true );
411+ fallbackSupplier = null ;
369412 }
413+ txnLockManager = null ;
414+ txnRef = null ;
370415 }
371416
372417 private long openCursor (long txn , int dbi , boolean tryReuse ) throws IOException {
0 commit comments