26
26
#include "list.h"
27
27
#include "memory.h"
28
28
#include "overflow_helpers.h"
29
+ #include "smp.h"
29
30
#include "term.h"
30
31
#include "utils.h"
31
32
#include <assert.h>
@@ -252,38 +253,70 @@ static inline bool has_key_at(term tuple, size_t key_index)
252
253
return key_index < (size_t ) term_get_tuple_arity (tuple );
253
254
}
254
255
255
- static EtsErrorCode insert (struct EtsTable * ets_table , term tuple , Context * ctx )
256
+ static struct HNode * tuple_to_insertion_node (struct EtsTable * ets_table , term tuple , GlobalContext * global )
256
257
{
258
+ bool is_duplicate_bag = ets_table -> table_type == EtsTableDuplicateBag ;
257
259
size_t key_index = ets_table -> key_index ;
258
- if (UNLIKELY (!has_key_at (tuple , key_index ))) {
259
- return EtsBadEntry ;
260
- }
261
260
262
- bool is_duplicate_bag = ets_table -> table_type == EtsTableDuplicateBag ;
263
- struct HNode * node = NULL ;
264
261
if (is_duplicate_bag ) {
265
262
term key = term_get_tuple_element (tuple , key_index );
266
- term old_tuples = ets_hashtable_lookup (ets_table -> hashtable , key , ctx -> global );
263
+ term old_tuples = ets_hashtable_lookup (ets_table -> hashtable , key , global );
267
264
assert (term_is_list (old_tuples ));
268
265
bool is_new = term_is_nil (old_tuples );
269
- node = ets_hashtable_new_node_from_list (is_new ? term_nil () : old_tuples , tuple , key_index );
270
- } else {
271
- node = ets_hashtable_new_node (tuple , key_index );
266
+ return ets_hashtable_new_node_from_list (is_new ? term_nil () : old_tuples , tuple , key_index );
267
+ }
268
+ return ets_hashtable_new_node (tuple , key_index );
269
+ }
270
+
271
+ static struct HNode * * list_to_insertion_nodes (struct EtsTable * ets_table , term list , size_t size , GlobalContext * global )
272
+ {
273
+ size_t last_i = 0 ;
274
+ struct HNode * * nodes = malloc (size * sizeof (struct HNode * ));
275
+ if (IS_NULL_PTR (nodes )) {
276
+ goto oom ;
277
+ }
278
+
279
+ while (term_is_nonempty_list (list )) {
280
+ term tuple = term_get_list_head (list );
281
+ nodes [last_i ] = tuple_to_insertion_node (ets_table , tuple , global );
282
+ if (IS_NULL_PTR (nodes [last_i ])) {
283
+ goto oom ;
284
+ }
285
+ ++ last_i ;
286
+ list = term_get_list_tail (list );
287
+ }
288
+ return nodes ;
289
+ oom :
290
+ // skip last node, it's NULL
291
+ for (size_t i = 0 ; i < last_i ; ++ i ) {
292
+ ets_hashtable_free_node (nodes [i ], global );
272
293
}
294
+ free (nodes );
295
+ return NULL ;
296
+ }
297
+
298
+ static EtsErrorCode insert_tuple (struct EtsTable * ets_table , term tuple , GlobalContext * global )
299
+ {
300
+ size_t key_index = ets_table -> key_index ;
301
+ if (UNLIKELY (!has_key_at (tuple , key_index ))) {
302
+ return EtsBadEntry ;
303
+ }
304
+
305
+ struct HNode * node = tuple_to_insertion_node (ets_table , tuple , global );
273
306
if (IS_NULL_PTR (node )) {
274
307
return EtsAllocationFailure ;
275
308
}
276
309
277
- EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , node , EtsHashtableAllowOverwrite , ctx -> global );
310
+ EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , node , EtsHashtableAllowOverwrite , global );
278
311
if (UNLIKELY (res != EtsHashtableOk )) {
279
- ets_hashtable_free_node (node , ctx -> global );
312
+ ets_hashtable_free_node (node , global );
280
313
return EtsAllocationFailure ;
281
314
}
282
315
283
316
return EtsOk ;
284
317
}
285
318
286
- static EtsErrorCode insert_multiple (struct EtsTable * ets_table , term list , Context * ctx )
319
+ static EtsErrorCode insert_tuple_list (struct EtsTable * ets_table , term list , GlobalContext * global )
287
320
{
288
321
term iter = list ;
289
322
size_t size = 0 ;
@@ -296,32 +329,19 @@ static EtsErrorCode insert_multiple(struct EtsTable *ets_table, term list, Conte
296
329
}
297
330
++ size ;
298
331
}
299
- if (!term_is_nil (iter )) {
332
+ bool improper = !term_is_nil (iter );
333
+ if (UNLIKELY (improper )) {
300
334
return EtsBadEntry ;
301
335
}
302
336
303
- struct HNode * * nodes = malloc ( size * sizeof ( struct HNode * ) );
337
+ struct HNode * * nodes = list_to_insertion_nodes ( ets_table , list , size , global );
304
338
if (IS_NULL_PTR (nodes )) {
305
339
return EtsAllocationFailure ;
306
340
}
307
341
308
- size_t i = 0 ;
309
- while (term_is_nonempty_list (list )) {
310
- term tuple = term_get_list_head (list );
311
- nodes [i ] = ets_hashtable_new_node (tuple , ets_table -> key_index );
312
- if (IS_NULL_PTR (nodes [i ])) {
313
- for (size_t it = 0 ; it < i ; ++ it ) {
314
- ets_hashtable_free_node (nodes [it ], ctx -> global );
315
- }
316
- free (nodes );
317
- return EtsAllocationFailure ;
318
- }
319
- ++ i ;
320
- list = term_get_list_tail (list );
321
- }
322
-
323
342
for (size_t i = 0 ; i < size ; ++ i ) {
324
- EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , nodes [i ], EtsHashtableAllowOverwrite , ctx -> global );
343
+ EtsHashtableStatus res = ets_hashtable_insert (ets_table -> hashtable , nodes [i ], EtsHashtableAllowOverwrite , global );
344
+ // insert can fail when comparing keys
325
345
assert (res == EtsHashtableOk );
326
346
}
327
347
@@ -338,9 +358,9 @@ EtsErrorCode ets_insert(term name_or_ref, term entry, Context *ctx)
338
358
339
359
EtsErrorCode result ;
340
360
if (term_is_tuple (entry )) {
341
- result = insert (ets_table , entry , ctx );
361
+ result = insert_tuple (ets_table , entry , ctx -> global );
342
362
} else if (term_is_list (entry )) {
343
- result = insert_multiple (ets_table , entry , ctx );
363
+ result = insert_tuple_list (ets_table , entry , ctx -> global );
344
364
} else {
345
365
result = EtsBadEntry ;
346
366
}
@@ -596,7 +616,7 @@ EtsErrorCode ets_update_counter_maybe_gc(term ref, term key, term operation, ter
596
616
597
617
term final_value = term_from_int (elem_value );
598
618
term_put_tuple_element (to_insert , elem_index , final_value );
599
- EtsErrorCode insert_result = insert (ets_table , to_insert , ctx );
619
+ EtsErrorCode insert_result = insert_tuple (ets_table , to_insert , ctx -> global );
600
620
if (insert_result == EtsOk ) {
601
621
* ret = final_value ;
602
622
}
0 commit comments