@@ -19,7 +19,15 @@ class ConcurrentART : public ART {
1919 }
2020
2121 void insertCC (uint8_t key[], uintptr_t value) {
22- ConcurrentART::insert (this , root, &root, key, 0 , value, maxPrefixLength, nullptr , 0 );
22+ while (true ) { // Retry loop
23+ try {
24+ insert (this , root, &root, key, 0 , value, maxPrefixLength, nullptr , 0 );
25+ return ; // Success - exit retry loop
26+ } catch (const RestartException&) {
27+ // Conflict detected - loop will retry from beginning
28+ continue ;
29+ }
30+ }
2331 }
2432
2533 private:
@@ -83,11 +91,12 @@ class ConcurrentART : public ART {
8391 if (!*child) {
8492 // Insert leaf into inner node
8593 ArtNode* newNode = makeLeaf (value);
94+ uint8_t keyByte = key[depth];
95+
8696 switch (node->type ) {
8797 case NodeType4: {
8898 // Cast node to Node4 to access its members
8999 Node4* node4 = static_cast <Node4*>(node);
90- uint8_t keyByte = key[depth];
91100 // Insert leaf into inner node
92101 if (node4->count < 4 ) {
93102
@@ -125,18 +134,50 @@ class ConcurrentART : public ART {
125134 newNode16->key [i] = flipSign (node4->key [i]);
126135 memcpy (newNode16->child , node4->child , node4->count * sizeof (uintptr_t ));
127136
137+ // Shouldn't be deleted, other threads might still be reading it
138+ // delete node;
139+
140+ // INSERT NODE 16 PART
141+
142+ // Flip the sign bit of the key byte for correct ordering in signed
143+ // comparisons
144+ uint8_t keyByteFlipped = flipSign (keyByte);
145+
146+ // SIMD: Compare keyByteFlipped with all keys in the node in parallel
147+ // _mm_set1_epi8 sets all 16 bytes of an SSE register to keyByteFlipped
148+ // _mm_loadu_si128 loads the node's keys into an SSE register
149+ // _mm_cmplt_epi8 does a signed comparison of each byte
150+ __m128i cmp = _mm_cmplt_epi8 (
151+ _mm_set1_epi8 (keyByteFlipped),
152+ _mm_loadu_si128 (reinterpret_cast <__m128i*>(newNode16->key )));
153+
154+ // _mm_movemask_epi8 creates a 16-bit mask from the comparison results
155+ // Only consider the bits for the active keys (node16->count)
156+ uint16_t bitfield =
157+ _mm_movemask_epi8 (cmp) & (0xFFFF >> (16 - newNode16->count ));
158+
159+ // Find the position of the first set bit (i.e., where keyByteFlipped <
160+ // key[i])
161+ unsigned pos = bitfield ? ctz (bitfield) : newNode16->count ;
162+
163+ // Shift keys and children to the right to make space for the new
164+ // key/child. This preserves the sorted order of keys in the node.
165+ memmove (newNode16->key + pos + 1 , newNode16->key + pos, newNode16->count - pos);
166+ memmove (newNode16->child + pos + 1 , newNode16->child + pos,
167+ (newNode16->count - pos) * sizeof (uintptr_t ));
168+ newNode16->key [pos] = keyByteFlipped;
169+ newNode16->child [pos] = newNode;
170+ newNode16->count ++;
171+
128172 writeUnlockObsolete (node);
129173 if (parent) { writeUnlock (parent); }
130-
131- delete node4;
132- return newNode16->insertNode16 (tree, nodeRef, keyByte, newNode);
174+
133175 }
134176 break ;
135177 }
136178 case NodeType16: {
137179 // Cast node to Node16 to access its members
138180 Node16* node16 = static_cast <Node16*>(node);
139- uint8_t keyByte = key[depth];
140181
141182 // Insert leaf into inner node
142183 if (node16->count < 16 ) {
@@ -185,26 +226,38 @@ class ConcurrentART : public ART {
185226 upgradeToWriteLockOrRestart (node, version, parent);
186227
187228 // Grow to Node48
188- Node48* newNode = new Node48 ();
189- *nodeRef = newNode ;
190- memcpy (newNode ->child , node16->child , node16->count * sizeof (uintptr_t ));
229+ Node48* newNode48 = new Node48 ();
230+ *nodeRef = newNode48 ;
231+ memcpy (newNode48 ->child , node16->child , node16->count * sizeof (uintptr_t ));
191232 for (unsigned i = 0 ; i < node16->count ; i++)
192- newNode->childIndex [flipSign (node16->key [i])] = i;
193- copyPrefix (node16, newNode);
194- newNode->count = node16->count ;
233+ newNode48->childIndex [flipSign (node16->key [i])] = i;
234+ copyPrefix (node16, newNode48);
235+ newNode48->count = node16->count ;
236+
237+ // Shouldn't be deleted, other threads might still be reading it
238+ // delete node;
239+
240+ // INSERT NODE 48 PART
241+
242+ // Insert element
243+ unsigned pos = newNode48->count ;
244+ if (newNode48->child [pos])
245+ for (pos = 0 ; newNode48->child [pos] != NULL ; pos++)
246+ ;
247+ // No memmove needed here because Node48 uses a mapping (childIndex) and
248+ // a dense array.
249+ newNode48->child [pos] = newNode;
250+ newNode48->childIndex [keyByte] = pos;
251+ newNode48->count ++;
195252
196253 writeUnlockObsolete (node);
197254 if (parent) { writeUnlock (parent); }
198-
199- delete node16;
200- return newNode->insertNode48 (tree, nodeRef, keyByte, newNode);
201255 }
202256 break ;
203257 }
204258 case NodeType48: {
205259 // Cast node to Node48 to access its members
206260 Node48* node48 = static_cast <Node48*>(node);
207- uint8_t keyByte = key[depth];
208261
209262 // Insert leaf into inner node
210263 if (node48->count < 48 ) {
@@ -233,26 +286,35 @@ class ConcurrentART : public ART {
233286 }
234287 upgradeToWriteLockOrRestart (node, version, parent);
235288
236- Node256* newNode = new Node256 ();
289+ Node256* newNode256 = new Node256 ();
237290 for (unsigned i = 0 ; i < 256 ; i++)
238291 if (node48->childIndex [i] != 48 )
239- newNode->child [i] = node48->child [node48->childIndex [i]];
240- newNode->count = node48->count ;
241- copyPrefix (node48, newNode);
242- *nodeRef = newNode;
292+ newNode256->child [i] = node48->child [node48->childIndex [i]];
293+ newNode256->count = node48->count ;
294+ copyPrefix (node48, newNode256);
295+ *nodeRef = newNode256;
296+
297+ // tree->printTree();
298+
299+ // Shouldn't be deleted, other threads might still be reading it
300+ // delete node;
301+
302+ // INSERT NODE 256 PART
303+
304+ // Insert leaf into inner node
305+ // No memmove needed here because Node256 uses a direct mapping for all
306+ // possible keys.
307+ newNode256->count ++;
308+ newNode256->child [keyByte] = newNode;
243309
244310 writeUnlockObsolete (node);
245311 if (parent) { writeUnlock (parent); }
246-
247- delete node48;
248- return newNode->insertNode256 (tree, nodeRef, keyByte, newNode);
249312 }
250313 break ;
251314 }
252315 case NodeType256: {
253316 // Cast node to Node256 to access its members
254317 Node256* node256 = static_cast <Node256*>(node);
255- uint8_t keyByte = key[depth];
256318
257319 upgradeToWriteLockOrRestart (node, version);
258320 if (parent) { readUnlockOrRestart (parent, parentVersion, node); }
0 commit comments