@@ -75,8 +75,7 @@ public class VectorMemoryIndex extends MemoryIndex
7575 private final Memtable memtable ;
7676 private final LongAdder writeCount = new LongAdder ();
7777
78- private PrimaryKey minimumKey ;
79- private PrimaryKey maximumKey ;
78+ private volatile KeyBounds keyBounds ;
8079
8180 private final NavigableSet <PrimaryKey > primaryKeys = new ConcurrentSkipListSet <>();
8281
@@ -88,7 +87,7 @@ public VectorMemoryIndex(StorageAttachedIndex index, Memtable memtable)
8887 }
8988
9089 @ Override
91- public synchronized long add (DecoratedKey key , Clustering <?> clustering , ByteBuffer value )
90+ public long add (DecoratedKey key , Clustering <?> clustering , ByteBuffer value )
9291 {
9392 if (value == null || value .remaining () == 0 || !index .validateTermSize (key , value , false , null ))
9493 return 0 ;
@@ -100,11 +99,11 @@ public synchronized long add(DecoratedKey key, Clustering<?> clustering, ByteBuf
10099
101100 private long index (PrimaryKey primaryKey , ByteBuffer value )
102101 {
103- updateKeyBounds (primaryKey );
104-
102+ long bytesUsed = graph .add (value , primaryKey , OnHeapGraph .InvalidVectorBehavior .FAIL );
105103 writeCount .increment ();
106104 primaryKeys .add (primaryKey );
107- return graph .add (value , primaryKey , OnHeapGraph .InvalidVectorBehavior .FAIL );
105+ updateKeyBounds (primaryKey );
106+ return bytesUsed ;
108107 }
109108
110109 @ Override
@@ -131,9 +130,6 @@ public long update(DecoratedKey key, Clustering<?> clustering, ByteBuffer oldVal
131130 {
132131 PrimaryKey primaryKey = index .hasClustering () ? index .keyFactory ().create (key , clustering )
133132 : index .keyFactory ().create (key );
134- // update bounds because only rows with vectors are included in the key bounds,
135- // so if the vector was null before, we won't have included it
136- updateKeyBounds (primaryKey );
137133
138134 // make the changes in this order, so we don't have a window where the row is not in the index at all
139135 if (newRemaining > 0 )
@@ -144,20 +140,18 @@ public long update(DecoratedKey key, Clustering<?> clustering, ByteBuffer oldVal
144140 // remove primary key if it's no longer indexed
145141 if (newRemaining <= 0 && oldRemaining > 0 )
146142 primaryKeys .remove (primaryKey );
143+
144+ // update bounds because only rows with vectors are included in the key bounds,
145+ // so if the vector was null before, we won't have included it
146+ updateKeyBounds (primaryKey );
147147 }
148148 return bytesUsed ;
149149 }
150150
151- private void updateKeyBounds (PrimaryKey primaryKey )
151+ private synchronized void updateKeyBounds (PrimaryKey key )
152152 {
153- if (minimumKey == null )
154- minimumKey = primaryKey ;
155- else if (primaryKey .compareTo (minimumKey ) < 0 )
156- minimumKey = primaryKey ;
157- if (maximumKey == null )
158- maximumKey = primaryKey ;
159- else if (primaryKey .compareTo (maximumKey ) > 0 )
160- maximumKey = primaryKey ;
153+ KeyBounds current = keyBounds ;
154+ keyBounds = current == null ? new KeyBounds (key , key ) : current .withUpdated (key );
161155 }
162156
163157 @ Override
@@ -213,15 +207,15 @@ public CloseableIterator<PrimaryKeyWithScore> orderBy(QueryContext queryContext,
213207 @ Override
214208 public CloseableIterator <PrimaryKeyWithScore > orderResultsBy (QueryContext queryContext , List <PrimaryKey > results , Expression orderer )
215209 {
216- if ( minimumKey == null )
217- // This case implies maximumKey is empty too.
210+ KeyBounds bounds = keyBounds ;
211+ if ( bounds == null )
218212 return CloseableIterator .empty ();
219213
220214 int limit = queryContext .limit ();
221215
222216 List <PrimaryKey > resultsInRange = results .stream ()
223- .dropWhile (k -> k .compareTo (minimumKey ) < 0 )
224- .takeWhile (k -> k .compareTo (maximumKey ) <= 0 )
217+ .dropWhile (k -> k .compareTo (bounds . minimum ) < 0 )
218+ .takeWhile (k -> k .compareTo (bounds . maximum ) <= 0 )
225219 .collect (Collectors .toList ());
226220
227221 int maxBruteForceRows = maxBruteForceRows (limit , resultsInRange .size (), graph .size ());
@@ -420,4 +414,25 @@ public void close()
420414 FileUtils .closeQuietly (nodeScores );
421415 }
422416 }
417+
418+ private static final class KeyBounds
419+ {
420+ final PrimaryKey minimum ;
421+ final PrimaryKey maximum ;
422+
423+ KeyBounds (PrimaryKey minimum , PrimaryKey maximum )
424+ {
425+ this .minimum = minimum ;
426+ this .maximum = maximum ;
427+ }
428+
429+ KeyBounds withUpdated (PrimaryKey key )
430+ {
431+ PrimaryKey newMin = minimum .compareTo (key ) > 0 ? key : minimum ;
432+ PrimaryKey newMax = maximum .compareTo (key ) < 0 ? key : maximum ;
433+
434+ // Avoid allocation if nothing changed
435+ return newMin == minimum && newMax == maximum ? this : new KeyBounds (newMin , newMax );
436+ }
437+ }
423438}
0 commit comments