@@ -43,10 +43,12 @@ public abstract class AbstractIndexReader implements BitmapIndexReader {
4343 protected int blockCapacity ;
4444 protected int blockValueCountMod ;
4545 protected MillisecondClock clock ;
46+ protected long columnTop ;
4647 protected int keyCount ;
4748 protected long spinLockTimeoutMs ;
48- protected long unindexedNullCount ;
4949 private int keyCountIncludingNulls ;
50+ private long keyFileSequence = -1 ;
51+ private long valueMemSize = -1 ;
5052
5153 @ Override
5254 public void close () {
@@ -56,6 +58,10 @@ public void close() {
5658 Misc .free (valueMem );
5759 }
5860
61+ public long getColumnTop () {
62+ return columnTop ;
63+ }
64+
5965 public long getKeyBaseAddress () {
6066 return keyMem .addressOf (0 );
6167 }
@@ -69,10 +75,6 @@ public long getKeyMemorySize() {
6975 return keyMem .size ();
7076 }
7177
72- public long getUnIndexedNullCount () {
73- return unindexedNullCount ;
74- }
75-
7678 public long getValueBaseAddress () {
7779 return valueMem .addressOf (0 );
7880 }
@@ -91,13 +93,13 @@ public boolean isOpen() {
9193 }
9294
9395 @ Override
94- public void of (CairoConfiguration configuration , Path path , CharSequence name , long columnNameTxn , long unIndexedNullCount ) {
95- this .unindexedNullCount = unIndexedNullCount ;
96+ public void of (CairoConfiguration configuration , Path path , CharSequence columnName , long columnNameTxn , long columnTop ) {
97+ this .columnTop = columnTop ;
9698 final int plen = path .size ();
9799 this .spinLockTimeoutMs = configuration .getSpinLockTimeout ();
98100
99101 try {
100- keyMem .wholeFile (configuration .getFilesFacade (), BitmapIndexUtils .keyFileName (path , name , columnNameTxn ), MemoryTag .MMAP_INDEX_READER );
102+ keyMem .wholeFile (configuration .getFilesFacade (), BitmapIndexUtils .keyFileName (path , columnName , columnNameTxn ), MemoryTag .MMAP_INDEX_READER );
101103 this .clock = configuration .getMillisecondClock ();
102104
103105 // key file should already be created at least with header
@@ -113,45 +115,13 @@ public void of(CairoConfiguration configuration, Path path, CharSequence name, l
113115 throw CairoException .critical (0 ).put ("Unknown format: " ).put (path );
114116 }
115117
116- // Triple check atomic read. We read first and last sequences. If they match - there is a chance at stable
117- // read. Confirm start sequence hasn't changed after values read. If it has changed - retry the whole thing.
118- int blockValueCountMod ;
119- int keyCount ;
120- long valueMemSize ;
121- final long deadline = clock .getTicks () + spinLockTimeoutMs ;
122- while (true ) {
123- long seq = keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE );
124-
125- Unsafe .getUnsafe ().loadFence ();
126- if (keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE_CHECK ) == seq ) {
127- blockValueCountMod = keyMem .getInt (BitmapIndexUtils .KEY_RESERVED_OFFSET_BLOCK_VALUE_COUNT ) - 1 ;
128- keyCount = keyMem .getInt (BitmapIndexUtils .KEY_RESERVED_OFFSET_KEY_COUNT );
129- valueMemSize = keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_VALUE_MEM_SIZE );
130-
131- Unsafe .getUnsafe ().loadFence ();
132- if (keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE ) == seq ) {
133- break ;
134- }
135- }
136-
137- if (clock .getTicks () > deadline ) {
138- LOG .error ().$ (INDEX_CORRUPT ).$ (" [timeout=" ).$ (spinLockTimeoutMs ).$ ("ms]" ).$ ();
139- throw CairoException .critical (0 ).put (INDEX_CORRUPT );
140- }
141-
142- Os .pause ();
143- }
118+ readIndexMetadataAtomically ();
144119
145120 // Resize key memory eagerly to avoid doing that when searching keys.
146- keyMem .extend (BitmapIndexUtils .getKeyEntryOffset (keyCount ));
147-
148- this .blockValueCountMod = blockValueCountMod ;
149- this .blockCapacity = (blockValueCountMod + 1 ) * 8 + BitmapIndexUtils .VALUE_BLOCK_FILE_RESERVED ;
150- this .keyCount = keyCount ;
151- this .keyCountIncludingNulls = unIndexedNullCount > 0 ? keyCount + 1 : keyCount ;
121+ keyMem .extend (BitmapIndexUtils .getKeyEntryOffset (this .keyCount ));
152122 this .valueMem .of (
153123 configuration .getFilesFacade (),
154- BitmapIndexUtils .valueFileName (path .trimTo (plen ), name , columnNameTxn ),
124+ BitmapIndexUtils .valueFileName (path .trimTo (plen ), columnName , columnNameTxn ),
155125 valueMemSize ,
156126 valueMemSize ,
157127 MemoryTag .MMAP_INDEX_READER
@@ -164,6 +134,24 @@ public void of(CairoConfiguration configuration, Path path, CharSequence name, l
164134 }
165135 }
166136
137+ /**
138+ * Reloads index by extending value memory. There are several assumptions here:
139+ * - index reader is open and memory objects are not null
140+ * - memory object can be read
141+ * - key file sequence value and "value memory size" are both updated
142+ * - we can resize key memory using only keyCount
143+ * - we can resize value memory using the "value memory size" we read from the key header
144+ */
145+ public void reloadConditionally () {
146+ long seq = keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE_CHECK );
147+ if (seq != keyFileSequence ) {
148+ readIndexMetadataAtomically ();
149+ // extend memory objects
150+ this .keyMem .extend (BitmapIndexUtils .getKeyEntryOffset (keyCount ));
151+ this .valueMem .extend (valueMemSize );
152+ }
153+ }
154+
167155 public void updateKeyCount () {
168156 int keyCount ;
169157 final long deadline = clock .getTicks () + spinLockTimeoutMs ;
@@ -190,7 +178,44 @@ public void updateKeyCount() {
190178
191179 if (keyCount > this .keyCount ) {
192180 this .keyCount = keyCount ;
193- this .keyCountIncludingNulls = unindexedNullCount > 0 ? keyCount + 1 : keyCount ;
181+ this .keyCountIncludingNulls = columnTop > 0 ? keyCount + 1 : keyCount ;
182+ }
183+ }
184+
185+ private void readIndexMetadataAtomically () {
186+ // Triple check atomic read. We read first and last sequences. If they match - there is a chance at stable
187+ // read. Confirm start sequence hasn't changed after values read. If it has changed - retry the whole thing.
188+ final long deadline = clock .getTicks () + spinLockTimeoutMs ;
189+ while (true ) {
190+ long seq = keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE );
191+ int keyCount ;
192+ long valueMemSize ;
193+ int blockValueCountMod ;
194+
195+ Unsafe .getUnsafe ().loadFence ();
196+ if (keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE_CHECK ) == seq ) {
197+ blockValueCountMod = keyMem .getInt (BitmapIndexUtils .KEY_RESERVED_OFFSET_BLOCK_VALUE_COUNT ) - 1 ;
198+ keyCount = keyMem .getInt (BitmapIndexUtils .KEY_RESERVED_OFFSET_KEY_COUNT );
199+ valueMemSize = keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_VALUE_MEM_SIZE );
200+
201+ Unsafe .getUnsafe ().loadFence ();
202+ if (keyMem .getLong (BitmapIndexUtils .KEY_RESERVED_OFFSET_SEQUENCE ) == seq ) {
203+ this .keyFileSequence = seq ;
204+ this .valueMemSize = valueMemSize ;
205+ this .keyCount = keyCount ;
206+ this .blockValueCountMod = blockValueCountMod ;
207+ this .blockCapacity = (blockValueCountMod + 1 ) * 8 + BitmapIndexUtils .VALUE_BLOCK_FILE_RESERVED ;
208+ this .keyCountIncludingNulls = columnTop > 0 ? keyCount + 1 : keyCount ;
209+ break ;
210+ }
211+ }
212+
213+ if (clock .getTicks () > deadline ) {
214+ LOG .error ().$ (INDEX_CORRUPT ).$ (" [timeout=" ).$ (spinLockTimeoutMs ).$ ("ms]" ).$ ();
215+ throw CairoException .critical (0 ).put (INDEX_CORRUPT );
216+ }
217+
218+ Os .pause ();
194219 }
195220 }
196221}
0 commit comments