CUBRID Engine  latest
lock_free.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * lock_free.c : Lock-free structures.
22  */
23 
24 #include "config.h"
25 
26 #include <assert.h>
27 
28 #include "porting.h"
29 #include "lock_free.h"
30 #include "error_manager.h"
31 #include "error_code.h"
32 #include "memory_alloc.h"
33 
34 #if !defined(SERVER_MODE)
35 #define pthread_mutex_init(a, b)
36 #define pthread_mutex_destroy(a)
37 #define pthread_mutex_lock(a) 0
38 #define pthread_mutex_trylock(a) 0
39 #define pthread_mutex_unlock(a)
40 static int rv;
41 #endif /* not SERVER_MODE */
42 
43 /*
44  * Global lock free transaction systems systems
45  */
57 
58 static bool tran_systems_initialized = false;
59 
60 /*
61  * Macro definitions
62  */
63 #define OF_GET_REF(p,o) (void * volatile *) (((char *)(p)) + (o))
64 #define OF_GET_PTR(p,o) (void *) (((char *)(p)) + (o))
65 #define OF_GET_PTR_DEREF(p,o) (*OF_GET_REF (p,o))
66 
67 /*
68  * Address mark macros
69  */
70 #define ADDR_HAS_MARK(p) (((long long volatile) (p)) & 0x1)
71 #define ADDR_WITH_MARK(p) ((void * volatile) (((long long volatile) (p)) | 0x1))
72 #define ADDR_STRIP_MARK(p) ((void * volatile) (((long long volatile) (p)) & (~((long long) 0x1))))
73 
74 // Suppress -Wignored-qualifiers GCC warnings generated by address mark macros
75 #if defined (__GNUC__)
76 #pragma GCC diagnostic ignored "-Wignored-qualifiers"
77 #endif
78 #if defined (WINDOWS)
79 #pragma warning (disable : 4197)
80 #endif
81 
82 static INT64 lf_hash_size = 0;
83 
84 static INT64 lf_inserts = 0;
85 static INT64 lf_inserts_restart = 0;
86 static INT64 lf_list_inserts = 0;
87 static INT64 lf_list_inserts_found = 0;
88 static INT64 lf_list_inserts_save_temp_1 = 0;
89 static INT64 lf_list_inserts_save_temp_2 = 0;
90 static INT64 lf_list_inserts_claim = 0;
91 static INT64 lf_list_inserts_fail_link = 0;
93 
94 static INT64 lf_deletes = 0;
95 static INT64 lf_deletes_restart = 0;
96 static INT64 lf_list_deletes = 0;
97 static INT64 lf_list_deletes_found = 0;
99 static INT64 lf_list_deletes_fail_unlink = 0;
101 static INT64 lf_list_deletes_not_found = 0;
102 static INT64 lf_list_deletes_not_match = 0;
103 
104 static INT64 lf_clears = 0;
105 
106 static INT64 lf_retires = 0;
107 static INT64 lf_claims = 0;
108 static INT64 lf_claims_temp = 0;
109 static INT64 lf_transports = 0;
110 static INT64 lf_temps = 0;
111 
112 #if defined (UNITTEST_LF)
113 #define LF_UNITTEST_INC(lf_stat, incval) ATOMIC_INC_64 (lf_stat, incval)
114 #else /* !UNITTEST_LF */
115 #define LF_UNITTEST_INC(lf_stat, incval)
116 #endif
117 
118 #if defined (UNITTEST_LF) || defined (UNITTEST_CQ)
119 #if defined (NDEBUG)
120 /* Abort when calling assert even if it is not debug */
121 #define assert(cond) if (!(cond)) abort ()
122 #define assert_release(cond) if (!(cond)) abort ()
123 #endif /* NDEBUG */
124 #endif /* UNITTEST_LF || UNITTEST_CQ */
125 
126 static int lf_list_insert_internal (LF_TRAN_ENTRY * tran, void **list_p, void *key, int *behavior_flags,
127  LF_ENTRY_DESCRIPTOR * edesc, LF_FREELIST * freelist, void **entry, int *inserted);
128 static int lf_hash_insert_internal (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, int bflags, void **entry,
129  int *inserted);
130 static int lf_hash_delete_internal (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void *locked_entry,
131  int bflags, int *success);
132 
133 /*
134  * lf_callback_vpid_hash () - hash a VPID
135  * returns: hash value
136  * vpid(in): VPID to hash
137  * htsize(in): hash table size
138  */
139 unsigned int
140 lf_callback_vpid_hash (void *vpid, int htsize)
141 {
142  VPID *lvpid = (VPID *) vpid;
143 
144  return ((lvpid->pageid | ((unsigned int) lvpid->volid) << 24) % htsize);
145 }
146 
147 /*
148  * lf_callback_vpid_compare () - compare two vpids
149  * returns: 0 if equal, non-zero otherwise
150  * vpid_1(in): first VPID
151  * vpid_2(in): second vpid
152  */
153 int
154 lf_callback_vpid_compare (void *vpid_1, void *vpid_2)
155 {
156  VPID *lvpid_1 = (VPID *) vpid_1;
157  VPID *lvpid_2 = (VPID *) vpid_2;
158 
159  return !((lvpid_1->pageid == lvpid_2->pageid) && (lvpid_1->volid == lvpid_2->volid));
160 }
161 
162 /*
163  * lf_callback_vpid_copy () - copy a vpid
164  * returns: error code or NO_ERROR
165  * src(in): source VPID
166  * dest(in): destination to copy to
167  */
168 int
169 lf_callback_vpid_copy (void *src, void *dest)
170 {
171  ((VPID *) dest)->pageid = ((VPID *) src)->pageid;
172  ((VPID *) dest)->volid = ((VPID *) src)->volid;
173 
174  return NO_ERROR;
175 }
176 
177 /*
178  * lf_tran_system_init () - initialize a transaction system
179  * returns: error code or NO_ERROR
180  * sys(in): tran system to initialize
181  * max_threads(in): maximum number of threads that will use this system
182  */
183 int
184 lf_tran_system_init (LF_TRAN_SYSTEM * sys, int max_threads)
185 {
186  int i;
187  int error = NO_ERROR;
188 
189  assert (sys != NULL);
190 
191  sys->entry_count = LF_BITMAP_COUNT_ALIGN (max_threads);
193 
194  /* initialize entry array */
195  sys->entries = (LF_TRAN_ENTRY *) malloc (sizeof (LF_TRAN_ENTRY) * sys->entry_count);
196  if (sys->entries == NULL)
197  {
199 
200  sys->entry_count = 0;
201  sys->lf_bitmap.destroy ();
202  return ER_FAILED;
203  }
204 
205  memset (sys->entries, 0, sys->entry_count * sizeof (LF_TRAN_ENTRY));
206 
207  for (i = 0; i < sys->entry_count; i++)
208  {
209  sys->entries[i].tran_system = sys;
210  sys->entries[i].entry_idx = i;
212  sys->entries[i].did_incr = false;
213  sys->entries[i].last_cleanup_id = 0;
214  sys->entries[i].retired_list = NULL;
215  sys->entries[i].temp_entry = NULL;
216 
217 #if defined (UNITTEST_LF)
218  sys->entries[i].locked_mutex = NULL;
219  sys->entries[i].locked_mutex_line = -1;
220 #endif /* UNITTEST_LF */
221  }
222 
223  sys->used_entry_count = 0;
224  sys->global_transaction_id = 0;
225  sys->min_active_transaction_id = 0;
226  sys->mati_refresh_interval = 100;
227 
228  return NO_ERROR;
229 }
230 
231 /*
232  * lf_tran_system_destroy () - destroy a tran system
233  * sys(in): tran system
234  *
235  * NOTE: If (edesc == NULL) then there may be some memory leaks. Make sure the
236  * function is called with NULL edesc only at shutdown, or after collecting all
237  * retired entries.
238  */
239 void
241 {
242  int i;
243 
244  assert (sys != NULL);
245 
246  if (sys->entry_desc != NULL)
247  {
248  for (i = 0; i < sys->entry_count; i++)
249  {
250  lf_tran_destroy_entry (&sys->entries[i]);
251  }
252  }
253  sys->entry_count = 0;
254 
255  if (sys->entries != NULL)
256  {
257  free_and_init (sys->entries);
258  }
259 
260  sys->lf_bitmap.destroy ();
261 
262  return;
263 }
264 
265 /*
266  * lf_dtran_request_entry () - request a tran "entry"
267  * returns: entry or NULL on error
268  * sys(in): tran system
269  */
272 {
273  LF_TRAN_ENTRY *entry;
274  int entry_idx;
275 
276  assert (sys != NULL);
277  assert (sys->entry_count > 0);
278  assert (sys->entries != NULL);
279 
280  entry_idx = sys->lf_bitmap.get_entry ();
281  if (entry_idx < 0)
282  {
283  assert (false);
284  return NULL;
285  }
286 
287  /* done; clear and serve */
288  ATOMIC_INC_32 (&sys->used_entry_count, 1);
289  entry = &sys->entries[entry_idx];
290 
292 
293 #if defined (UNITTEST_LF)
294  entry->locked_mutex = NULL;
295  entry->locked_mutex_line = -1;
296 #endif /* UNITTEST_LF */
297 
298  return entry;
299 }
300 
301 /*
302  * lf_tran_return_entry () - return a previously requested entry
303  * returns: error code or NO_ERROR
304  * sys(in): tran system
305  * entry(in): tran entry
306  *
307  * NOTE: Only entries requested from this system should be returned.
308  */
309 void
311 {
312  LF_TRAN_SYSTEM *sys;
313 
314  assert (entry != NULL);
315  assert (entry->entry_idx >= 0);
317  assert (entry->tran_system != NULL);
318 
319  /* fetch system */
320  sys = entry->tran_system;
321 
322  /* clear bitfield so slot may be reused */
323  sys->lf_bitmap.free_entry (entry->entry_idx);
324 
325  /* decrement use counter */
326  ATOMIC_INC_32 (&sys->used_entry_count, -1);
327 }
328 
329 /*
330  * lf_tran_destroy_entry () - destroy a tran entry
331  ** return : NULL
332  * entry(in): tran entry
333  */
334 
335 void
337 {
338  LF_ENTRY_DESCRIPTOR *edesc = NULL;
339 
340  assert (entry != NULL);
341  assert (entry->tran_system != NULL);
342 
343  edesc = entry->tran_system->entry_desc;
344  if (edesc != NULL)
345  {
346  void *curr = entry->retired_list, *next = NULL;
347  while (curr != NULL)
348  {
349  next = (void *) OF_GET_PTR_DEREF (curr, edesc->of_local_next);
350  if (edesc->f_uninit != NULL)
351  {
352  edesc->f_uninit (curr);
353  }
354  edesc->f_free (curr);
355  curr = next;
356  }
357 
358  entry->retired_list = NULL;
359  }
360 }
361 
362 /*
363  * lf_dtran_compute_minimum_delete_id () - compute minimum delete id of all
364  * used entries of a tran system
365  * return: error code or NO_ERROR
366  * sys(in): tran system
367  */
368 void
370 {
371  UINT64 minvalue = LF_NULL_TRANSACTION_ID;
372  int i, j;
373 
374  /* determine minimum value of all min_cdi fields in system entries */
375  for (i = 0; i < sys->entry_count / LF_BITFIELD_WORD_SIZE; i++)
376  {
377  if (sys->lf_bitmap.bitfield[i])
378  {
379  for (j = 0; j < LF_BITFIELD_WORD_SIZE; j++)
380  {
381  int pos = i * LF_BITFIELD_WORD_SIZE + j;
382  UINT64 fetch = sys->entries[pos].transaction_id;
383 
384  if (minvalue > fetch)
385  {
386  minvalue = fetch;
387  }
388  }
389  }
390  }
391 
392  /* store new minimum for later fetching */
393  ATOMIC_TAS_64 (&sys->min_active_transaction_id, minvalue);
394 }
395 
396 /*
397  * lf_tran_start_op () - start operation in entry
398  * returns: error code or NO_ERROR
399  * entry(in): tran entry
400  * incr(in): increment global counter?
401  */
402 void
403 lf_tran_start (LF_TRAN_ENTRY * entry, bool incr)
404 {
405  LF_TRAN_SYSTEM *sys;
406 
407  assert (entry != NULL);
408  assert (entry->tran_system != NULL);
409  assert (entry->transaction_id == LF_NULL_TRANSACTION_ID || (!entry->did_incr && incr));
410 
411  sys = entry->tran_system;
412 
413  if (incr && !entry->did_incr)
414  {
415  entry->transaction_id = ATOMIC_INC_64 (&sys->global_transaction_id, 1);
416  entry->did_incr = true;
417 
418  if (entry->transaction_id % entry->tran_system->mati_refresh_interval == 0)
419  {
421  }
422  }
423  else
424  {
425  entry->transaction_id = VOLATILE_ACCESS (sys->global_transaction_id, UINT64);
426  }
427 }
428 
429 /*
430  * lf_tran_end_op () - end operation in entry
431  * returns: error code or NO_ERROR
432  * sys(in): tran system
433  * entry(in): tran entry
434  */
435 void
437 {
438  /* maximum value of domain */
441  entry->did_incr = false;
442 }
443 
444 /*
445  * lf_initialize_transaction_systems () - initialize global transaction systems
446  */
447 int
449 {
451  {
453  /* reinitialize */
454  }
455 
456  if (lf_tran_system_init (&spage_saving_Ts, max_threads) != NO_ERROR)
457  {
458  goto error;
459  }
460  if (lf_tran_system_init (&obj_lock_res_Ts, max_threads) != NO_ERROR)
461  {
462  goto error;
463  }
464  if (lf_tran_system_init (&obj_lock_ent_Ts, max_threads) != NO_ERROR)
465  {
466  goto error;
467  }
468  if (lf_tran_system_init (&catalog_Ts, max_threads) != NO_ERROR)
469  {
470  goto error;
471  }
472  if (lf_tran_system_init (&sessions_Ts, max_threads) != NO_ERROR)
473  {
474  goto error;
475  }
476  if (lf_tran_system_init (&free_sort_list_Ts, max_threads) != NO_ERROR)
477  {
478  goto error;
479  }
480  if (lf_tran_system_init (&global_unique_stats_Ts, max_threads) != NO_ERROR)
481  {
482  goto error;
483  }
484 
485  if (lf_tran_system_init (&hfid_table_Ts, max_threads) != NO_ERROR)
486  {
487  goto error;
488  }
489 
490  if (lf_tran_system_init (&xcache_Ts, max_threads) != NO_ERROR)
491  {
492  /* TODO: Could we not use an array for tran systems? */
493  goto error;
494  }
495 
496  if (lf_tran_system_init (&fpcache_Ts, max_threads) != NO_ERROR)
497  {
498  /* TODO: Could we not use an array for tran systems? */
499  goto error;
500  }
501 
502  if (lf_tran_system_init (&dwb_slots_Ts, max_threads) != NO_ERROR)
503  {
504  /* TODO: Could we not use an array for tran systems? */
505  goto error;
506  }
507 
509  return NO_ERROR;
510 
511 error:
513  return ER_FAILED;
514 }
515 
516 /*
517  * lf_destroy_transaction_systems () - destroy global transaction systems
518  */
519 void
521 {
522  lf_tran_system_destroy (&spage_saving_Ts);
523  lf_tran_system_destroy (&obj_lock_res_Ts);
524  lf_tran_system_destroy (&obj_lock_ent_Ts);
525  lf_tran_system_destroy (&catalog_Ts);
526  lf_tran_system_destroy (&sessions_Ts);
527  lf_tran_system_destroy (&free_sort_list_Ts);
528  lf_tran_system_destroy (&global_unique_stats_Ts);
529  lf_tran_system_destroy (&hfid_table_Ts);
530  lf_tran_system_destroy (&xcache_Ts);
531  lf_tran_system_destroy (&fpcache_Ts);
532  lf_tran_system_destroy (&dwb_slots_Ts);
533 
534  tran_systems_initialized = false;
535 }
536 
537 /*
538  * lf_stack_push () - push an entry on a lock free stack
539  * returns: error code or NO_ERROR
540  * top(in/out): top of stack
541  * entry(in): entry to push
542  * edesc(in): descriptor for entry
543  */
544 int
545 lf_stack_push (void **top, void *entry, LF_ENTRY_DESCRIPTOR * edesc)
546 {
547  void *rtop = NULL;
548  assert (top != NULL && entry != NULL && edesc != NULL);
549 
550  do
551  {
552  rtop = *((void *volatile *) top);
553  OF_GET_PTR_DEREF (entry, edesc->of_local_next) = rtop;
554  }
555  while (!ATOMIC_CAS_ADDR (top, rtop, entry));
556 
557  /* done */
558  return NO_ERROR;
559 }
560 
561 /*
562  * lf_stack_pop () - pop an entry off a lock free stack
563  * returns: entry or NULL on empty stack
564  * top(in/out): top of stack
565  * edesc(in): descriptor for entry
566  *
567  * NOTE: This function is vulnerable to an ABA problem in the following
568  * scenario:
569  * (1) Thread_1 executes POP and is suspended exactly after MARK
570  * (2) Thread_2 executes: t := POP, POP, PUSH (t)
571  * (3) Thread_1 is continued; CAS will succeed but prev is pointing to the
572  * wrong address
573  */
574 void *
575 lf_stack_pop (void **top, LF_ENTRY_DESCRIPTOR * edesc)
576 {
577  void *rtop = NULL, *prev = NULL;
578  assert (top != NULL && edesc != NULL);
579 
580  while (true)
581  {
582  rtop = *top;
583  if (rtop == NULL)
584  {
585  /* at this time the stack is empty */
586  return NULL;
587  }
588 
589  prev = OF_GET_PTR_DEREF (rtop, edesc->of_local_next); /* MARK */
590  if (ATOMIC_CAS_ADDR (top, rtop, prev))
591  {
592  /* clear link */
593  OF_GET_PTR_DEREF (rtop, edesc->of_local_next) = NULL;
594 
595  /* return success */
596  return rtop;
597  }
598  }
599 
600  /* impossible case */
601  assert (false);
602  return NULL;
603 }
604 
605 /*
606  * lf_freelist_alloc_block () - allocate a block of entries in the freelist
607  * returns: error code or NO_ERROR
608  * freelist(in): freelist to allocate to
609  */
610 static int
612 {
613  void *head = NULL, *tail = NULL, *new_entry = NULL, *top = NULL;
614  LF_ENTRY_DESCRIPTOR *edesc;
615  int i;
616 
617  assert (freelist != NULL && freelist->entry_desc != NULL);
618  edesc = freelist->entry_desc;
619 
620  /* allocate a block */
621  for (i = 0; i < freelist->block_size; i++)
622  {
623  new_entry = edesc->f_alloc ();
624  if (new_entry == NULL)
625  {
626  /* we use a decoy size since we don't know it */
629  }
630 
631  /* of_prev of new entry points to tail; new entry becomes tail */
632  OF_GET_PTR_DEREF (new_entry, edesc->of_local_next) = tail;
633  tail = new_entry;
634 
635  /* store first entry as head */
636  if (head == NULL)
637  {
638  head = new_entry;
639  }
640  }
641 
642  /* append block to freelist */
643  do
644  {
645  top = VOLATILE_ACCESS (freelist->available, void *);
646  OF_GET_PTR_DEREF (head, edesc->of_local_next) = top;
647  }
648  while (!ATOMIC_CAS_ADDR (&freelist->available, top, tail));
649 
650  /* increment allocated count */
651  ATOMIC_INC_32 (&freelist->alloc_cnt, freelist->block_size);
652  ATOMIC_INC_32 (&freelist->available_cnt, freelist->block_size);
653 
654  /* operation successful, block appended */
655  return NO_ERROR;
656 }
657 
658 /*
659  * lf_freelist_init () - initialize a freelist
660  * returns: error code or NO_ERROR
661  * freelist(in): freelist to initialize
662  * initial_blocks(in): number of blocks to allocate at initialisation
663  * block_size(in): number of entries allocated in a block
664  */
665 int
666 lf_freelist_init (LF_FREELIST * freelist, int initial_blocks, int block_size, LF_ENTRY_DESCRIPTOR * edesc,
667  LF_TRAN_SYSTEM * tran_system)
668 {
669  int i;
670 
671  assert (freelist != NULL && edesc != NULL);
672  assert (tran_system != NULL);
673  assert (initial_blocks >= 1);
674 
675  if (freelist->available != NULL)
676  {
677  /* already initialized */
678  return NO_ERROR;
679  }
680 
681  /* initialize fields */
682  freelist->available = NULL;
683 
684  freelist->available_cnt = 0;
685  freelist->retired_cnt = 0;
686  freelist->alloc_cnt = 0;
687 
688  freelist->block_size = block_size;
689  freelist->entry_desc = edesc;
690  freelist->tran_system = tran_system;
691 
692  tran_system->entry_desc = edesc;
693 
694  for (i = 0; i < initial_blocks; i++)
695  {
696  if (lf_freelist_alloc_block (freelist) != NO_ERROR)
697  {
698  return ER_FAILED;
699  }
700  }
701 
702  /* all ok */
703  return NO_ERROR;
704 }
705 
706 /*
707  * lf_freelist_destroy () - destroy the freelist
708  * freelist(in): freelist
709  */
710 void
712 {
713  LF_ENTRY_DESCRIPTOR *edesc;
714  void *entry, *next;
715 
716  assert (freelist != NULL);
717 
718  if (freelist->available == NULL)
719  {
720  return;
721  }
722 
723  edesc = freelist->entry_desc;
724  entry = freelist->available;
725  if (entry != NULL)
726  {
727  do
728  {
729  /* save next entry */
730  next = OF_GET_PTR_DEREF (entry, edesc->of_local_next);
731 
732  /* discard current entry */
733  edesc->f_free (entry);
734 
735  /* advance */
736  entry = next;
737  }
738  while (entry != NULL);
739  }
740 
741  freelist->available = NULL;
742 }
743 
744 /*
745  * lf_freelist_claim () - claim an entry from the available list
746  * returns: entry or NULL on error
747  * tran_entry(in): lock free transaction entry
748  * freelist(in): freelist to claim from
749  */
750 void *
751 lf_freelist_claim (LF_TRAN_ENTRY * tran_entry, LF_FREELIST * freelist)
752 {
753  LF_ENTRY_DESCRIPTOR *edesc;
754  void *entry;
755  bool local_tran = false;
756 
757  assert (tran_entry != NULL);
758  assert (freelist != NULL);
759  assert (freelist->entry_desc != NULL);
760 
761  edesc = freelist->entry_desc;
762 
764 
765  /* first check temporary entry */
766  if (tran_entry->temp_entry != NULL)
767  {
768  entry = tran_entry->temp_entry;
769  tran_entry->temp_entry = NULL;
770  OF_GET_PTR_DEREF (entry, edesc->of_next) = NULL;
771 
773  LF_UNITTEST_INC (&lf_temps, -1);
774  return entry;
775  }
776 
777  /* We need a transaction. Careful: we cannot increment transaction ID! */
778  if (tran_entry->transaction_id == LF_NULL_TRANSACTION_ID)
779  {
780  local_tran = true;
781  lf_tran_start_with_mb (tran_entry, false);
782  }
783 
784  /* clean retired list, if possible */
785  if (LF_TRAN_CLEANUP_NECESSARY (tran_entry))
786  {
787  if (lf_freelist_transport (tran_entry, freelist) != NO_ERROR)
788  {
789  if (local_tran)
790  {
791  lf_tran_end_with_mb (tran_entry);
792  }
793  return NULL;
794  }
795  }
796 
797  /* claim an entry */
798  while (true)
799  {
800  /* try to get a new entry form the safe stack */
801  entry = lf_stack_pop (&freelist->available, edesc);
802 
803  if (entry != NULL)
804  {
805  /* adjust counter */
806  ATOMIC_INC_32 (&freelist->available_cnt, -1);
807 
808  if ((edesc->f_init != NULL) && (edesc->f_init (entry) != NO_ERROR))
809  {
810  /* can't initialize it */
811  if (local_tran)
812  {
813  lf_tran_end_with_mb (tran_entry);
814  }
815  return NULL;
816  }
817 
818  /* initialize next */
819  OF_GET_PTR_DEREF (entry, edesc->of_next) = NULL;
820 
821  /* done! */
822  if (local_tran)
823  {
824  lf_tran_end_with_mb (tran_entry);
825  }
826  return entry;
827  }
828  else
829  {
830  /* NOTE: as you can see, more than one thread can start allocating a new freelist_entry block at the same
831  * time; this behavior is acceptable given that the freelist has a _low_ enough value of block_size; it sure
832  * beats synchronizing the operations */
833  if (lf_freelist_alloc_block (freelist) != NO_ERROR)
834  {
835  if (local_tran)
836  {
837  lf_tran_end_with_mb (tran_entry);
838  }
839  return NULL;
840  }
841 
842  /* retry a stack pop */
843  continue;
844  }
845  }
846 
847  /* impossible! */
848  assert (false);
849  if (local_tran)
850  {
851  lf_tran_end_with_mb (tran_entry);
852  }
853  return NULL;
854 }
855 
856 /*
857  * lf_freelist_retire () - retire an entry
858  * returns: error code or NO_ERROR
859  * tran_entry(in): tran entry to store local retired entries
860  * freelist(in): freelist to use
861  * entry(in): entry to retire
862  */
863 int
864 lf_freelist_retire (LF_TRAN_ENTRY * tran_entry, LF_FREELIST * freelist, void *entry)
865 {
866  LF_ENTRY_DESCRIPTOR *edesc;
867  UINT64 *tran_id;
868  int ret = NO_ERROR;
869  bool local_tran = false;
870 
871  assert (entry != NULL && tran_entry != NULL);
872  assert (freelist != NULL);
873  edesc = freelist->entry_desc;
874  assert (edesc != NULL);
875 
876  /* see if local transaction is required */
877  if (tran_entry->transaction_id == LF_NULL_TRANSACTION_ID)
878  {
879  local_tran = true;
880  lf_tran_start_with_mb (tran_entry, true);
881  }
882  else if (!tran_entry->did_incr)
883  {
884  lf_tran_start_with_mb (tran_entry, true);
885  }
886 
887  /* do a retired list cleanup, if possible */
888  if (LF_TRAN_CLEANUP_NECESSARY (tran_entry))
889  {
890  if (lf_freelist_transport (tran_entry, freelist) != NO_ERROR)
891  {
892  return ER_FAILED;
893  }
894  }
895 
896  /* set transaction index of entry */
897  tran_id = (UINT64 *) OF_GET_PTR (entry, edesc->of_del_tran_id);
898  *tran_id = tran_entry->transaction_id;
899 
900  /* push to local list */
901  ret = lf_stack_push (&tran_entry->retired_list, entry, edesc);
902  if (ret == NO_ERROR)
903  {
904  /* for stats purposes */
905  ATOMIC_INC_32 (&freelist->retired_cnt, 1);
906 
908  }
909  else
910  {
911  assert (false);
912  }
913 
914  /* end local transaction */
915  if (local_tran)
916  {
917  lf_tran_end_with_mb (tran_entry);
918  }
919 
920  return ret;
921 }
922 
923 /*
924  * lf_freelist_transport () - transport local retired entries to freelist
925  * returns: error code or NO_ERROR
926  * tran_entry(in): transaction entry to use
927  * freelist(in): freelist
928  */
929 int
931 {
932  LF_TRAN_SYSTEM *tran_system;
933  LF_ENTRY_DESCRIPTOR *edesc;
934  UINT64 min_tran_id = 0;
935  int transported_count = 0;
936  void *list = NULL, *list_trailer = NULL;
937  void *aval_first = NULL, *aval_last = NULL;
938  void *old_head;
939 
940  assert (freelist != NULL);
941  assert (tran_entry != NULL);
942  tran_system = tran_entry->tran_system;
943  assert (tran_system != NULL);
944  edesc = freelist->entry_desc;
945  assert (edesc != NULL);
946 
947  /* check if cleanup is actually necessary */
948  min_tran_id = tran_system->min_active_transaction_id;
949  if (min_tran_id <= tran_entry->last_cleanup_id)
950  {
951  /* nothing to do */
952  return NO_ERROR;
953  }
954 
955  /* walk private list and unlink old entries */
956  for (list = tran_entry->retired_list; list != NULL; list = OF_GET_PTR_DEREF (list, edesc->of_local_next))
957  {
958 
959  if (aval_first == NULL)
960  {
961  UINT64 *del_id = (UINT64 *) OF_GET_PTR (list, edesc->of_del_tran_id);
962  assert (del_id != NULL);
963 
964  if (*del_id < min_tran_id)
965  {
966  /* found first reusable entry - since list is ordered by descending transaction id, entries that follow
967  * are also reusable */
968  aval_first = list;
969  aval_last = list;
970 
971  /* uninit the reusable entry */
972  if (edesc->f_uninit != NULL)
973  {
974  edesc->f_uninit (list);
975  }
976 
977  transported_count = 1;
978  }
979  else
980  {
981  /* save trailer */
982  list_trailer = list;
983  }
984  }
985  else
986  {
987  /* continue until we get to tail */
988  aval_last = list;
989 
990  /* uninit the reusable entry */
991  if (edesc->f_uninit != NULL)
992  {
993  edesc->f_uninit (list);
994  }
995 
996  transported_count++;
997  }
998  }
999 
1000  if (aval_first != NULL)
1001  {
1002  if (list_trailer != NULL)
1003  {
1004  /* unlink found part of list */
1005  OF_GET_PTR_DEREF (list_trailer, edesc->of_local_next) = NULL;
1006  }
1007  else
1008  {
1009  /* whole list can be reused */
1010  tran_entry->retired_list = NULL;
1011  }
1012 
1013  /* make sure we don't append an unlinked sublist */
1014  MEMORY_BARRIER ();
1015 
1016  /* link part of list to available */
1017  do
1018  {
1019  old_head = VOLATILE_ACCESS (freelist->available, void *);
1020  OF_GET_PTR_DEREF (aval_last, edesc->of_local_next) = old_head;
1021  }
1022  while (!ATOMIC_CAS_ADDR (&freelist->available, old_head, aval_first));
1023 
1024  /* update counters */
1025  ATOMIC_INC_32 (&freelist->available_cnt, transported_count);
1026  ATOMIC_INC_32 (&freelist->retired_cnt, -transported_count);
1027 
1028  LF_UNITTEST_INC (&lf_transports, transported_count);
1029  }
1030 
1031  /* register cleanup */
1032  tran_entry->last_cleanup_id = min_tran_id;
1033 
1034  /* all ok */
1035  return NO_ERROR;
1036 }
1037 
1038 /*
1039  * lf_io_list_find () - find in an insert-only list
1040  * returns: error code or NO_ERROR
1041  * list_p(in): address of list head
1042  * key(in): key to search for
1043  * edesc(in): entry descriptor
1044  * entry(out): found entry or NULL
1045  */
1046 int
1047 lf_io_list_find (void **list_p, void *key, LF_ENTRY_DESCRIPTOR * edesc, void **entry)
1048 {
1049  pthread_mutex_t *entry_mutex;
1050  void **curr_p;
1051  void *curr;
1052  int rv;
1053 
1054  assert (list_p != NULL && edesc != NULL);
1055  assert (key != NULL && entry != NULL);
1056 
1057  /* by default, not found */
1058  (*entry) = NULL;
1059 
1060  curr_p = list_p;
1061  curr = *((void *volatile *) curr_p);
1062 
1063  /* search */
1064  while (curr != NULL)
1065  {
1066  if (edesc->f_key_cmp (key, OF_GET_PTR (curr, edesc->of_key)) == 0)
1067  {
1068  /* found! */
1069  if (edesc->using_mutex)
1070  {
1071  /* entry has a mutex protecting it's members; lock it */
1072  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (curr, edesc->of_mutex);
1073  rv = pthread_mutex_lock (entry_mutex);
1074  }
1075 
1076  (*entry) = curr;
1077  return NO_ERROR;
1078  }
1079 
1080  /* advance */
1081  curr_p = (void **) OF_GET_REF (curr, edesc->of_next);
1082  curr = *((void *volatile *) curr_p);
1083  }
1084 
1085  /* all ok but not found */
1086  return NO_ERROR;
1087 }
1088 
1089 /*
1090  * lf_io_list_find_or_insert () - find an entry in an insert only list or insert
1091  * new entry if not found
1092  * returns: error code or NO_ERROR
1093  * list_p(in): address of list head
1094  * new_entry(in): new entry to insert if entry with same key does not exist
1095  * edesc(in): entry descriptor
1096  * entry(out): found entry or "new_entry" if inserted
1097  *
1098  * NOTE: key is extracted from new_entry
1099  */
1100 int
1101 lf_io_list_find_or_insert (void **list_p, void *new_entry, LF_ENTRY_DESCRIPTOR * edesc, void **entry)
1102 {
1103  pthread_mutex_t *entry_mutex;
1104  void **curr_p;
1105  void *curr;
1106  void *key;
1107  int rv;
1108 
1109  assert (list_p != NULL && edesc != NULL);
1110  assert (new_entry != NULL && entry != NULL);
1111 
1112  /* extract key from new entry */
1113  key = OF_GET_PTR (new_entry, edesc->of_key);
1114 
1115  /* by default, not found */
1116  (*entry) = NULL;
1117 
1118 restart_search:
1119  curr_p = list_p;
1120  curr = *((void *volatile *) curr_p);
1121 
1122  /* search */
1123  while (curr_p != NULL)
1124  {
1125  /* is this the droid we are looking for? */
1126  if (curr != NULL)
1127  {
1128  if (edesc->f_key_cmp (key, OF_GET_PTR (curr, edesc->of_key)) == 0)
1129  {
1130  /* found! */
1131  if (edesc->using_mutex)
1132  {
1133  /* entry has a mutex protecting it's members; lock it */
1134  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (curr, edesc->of_mutex);
1135  rv = pthread_mutex_lock (entry_mutex);
1136  }
1137 
1138  (*entry) = curr;
1139  return NO_ERROR;
1140  }
1141 
1142  /* advance */
1143  curr_p = (void **) OF_GET_REF (curr, edesc->of_next);
1144  curr = *((void *volatile *) curr_p);
1145  }
1146  else
1147  {
1148  /* end of bucket, we must insert */
1149  (*entry) = new_entry;
1150  if (edesc->using_mutex)
1151  {
1152  /* entry has a mutex protecting it's members; lock it */
1153  entry_mutex = (pthread_mutex_t *) OF_GET_PTR ((*entry), edesc->of_mutex);
1154  rv = pthread_mutex_lock (entry_mutex);
1155  }
1156 
1157  /* attempt an add */
1158  if (!ATOMIC_CAS_ADDR (curr_p, (void *) NULL, (*entry)))
1159  {
1160  if (edesc->using_mutex)
1161  {
1162  /* link failed, unlock mutex */
1163  entry_mutex = (pthread_mutex_t *) OF_GET_PTR ((*entry), edesc->of_mutex);
1164  pthread_mutex_unlock (entry_mutex);
1165  }
1166 
1167  goto restart_search;
1168  }
1169 
1170  /* done! */
1171  return NO_ERROR;
1172  }
1173  }
1174 
1175  /* impossible case */
1176  assert (false);
1177  return ER_FAILED;
1178 }
1179 
1180 /*
1181  * lf_list_find () - find an entry in list
1182  * returns: error code or NO_ERROR
1183  * tran(in): lock free transaction system
1184  * list_p(in): address of list head
1185  * key(in): key to search for
1186  * behavior_flags(in/out): flags that control restart behavior
1187  * edesc(in): entry descriptor
1188  * entry(out): entry (if found) or NULL
1189  */
1190 int
1191 lf_list_find (LF_TRAN_ENTRY * tran, void **list_p, void *key, int *behavior_flags, LF_ENTRY_DESCRIPTOR * edesc,
1192  void **entry)
1193 {
1194  pthread_mutex_t *entry_mutex;
1195  void **curr_p;
1196  void *curr;
1197  int rv;
1198 
1199  assert (tran != NULL);
1200  assert (list_p != NULL && edesc != NULL);
1201  assert (key != NULL && entry != NULL);
1202 
1203  /* by default, not found */
1204  (*entry) = NULL;
1205 
1206  lf_tran_start_with_mb (tran, false);
1207 
1208 restart_search:
1209  curr_p = list_p;
1210  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1211 
1212  /* search */
1213  while (curr != NULL)
1214  {
1215  if (edesc->f_key_cmp (key, OF_GET_PTR (curr, edesc->of_key)) == 0)
1216  {
1217  /* found! */
1218  if (edesc->using_mutex)
1219  {
1220  /* entry has a mutex protecting it's members; lock it */
1221  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (curr, edesc->of_mutex);
1222  rv = pthread_mutex_lock (entry_mutex);
1223 
1224  /* mutex has been locked, no need to keep transaction */
1225  lf_tran_end_with_mb (tran);
1226 
1227  if (ADDR_HAS_MARK (OF_GET_PTR_DEREF (curr, edesc->of_next)))
1228  {
1229  /* while waiting for lock, somebody else deleted the entry; restart the search */
1230  pthread_mutex_unlock (entry_mutex);
1231 
1232  if (behavior_flags && (*behavior_flags & LF_LIST_BF_RETURN_ON_RESTART))
1233  {
1234  *behavior_flags = (*behavior_flags) | LF_LIST_BR_RESTARTED;
1235  return NO_ERROR;
1236  }
1237  else
1238  {
1239  goto restart_search;
1240  }
1241  }
1242  }
1243 
1244  (*entry) = curr;
1245  return NO_ERROR;
1246  }
1247 
1248  /* advance */
1249  curr_p = (void **) OF_GET_REF (curr, edesc->of_next);
1250  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1251  }
1252 
1253  /* all ok but not found */
1254  lf_tran_end_with_mb (tran);
1255  return NO_ERROR;
1256 }
1257 
1258 /*
1259  * lf_list_insert_internal () - insert an entry into latch-free list.
1260  * returns: error code or NO_ERROR
1261  * tran(in): lock free transaction system
1262  * list_p(in): address of list head
1263  * key(in): key to search for or insert
1264  * behavior_flags(in/out): flags that control restart behavior
1265  * edesc(in): entry descriptor
1266  * freelist(in): freelist to fetch new entries from
1267  * entry(in/out): found entry or inserted entry
1268  * inserted(out): returns 1 if inserted, 0 if found or not inserted.
1269  *
1270  * Behavior flags:
1271  *
1272  * LF_LIST_BF_RETURN_ON_RESTART - When insert fails because last entry in bucket was deleted, if this flag is set,
1273  * then the operation is restarted from here, instead of looping inside
1274  * lf_list_insert_internal (as a consequence, hash key is recalculated).
1275  * NOTE: Currently, this flag is always used (I must find out why).
1276  *
1277  * LF_LIST_BF_INSERT_GIVEN - If this flag is set, the caller means to force its own entry into hash table.
1278  * When the flag is not set, a new entry is claimed from freelist.
1279  * NOTE: If an entry with the same key already exists, the entry given as argument is
1280  * automatically retired.
1281  *
1282  * LF_LIST_BF_FIND_OR_INSERT - If this flag is set and an entry for the same key already exists, the existing
1283  * key will be output. If the flag is not set and key exists, insert just gives up
1284  * and a NULL entry is output.
1285  * NOTE: insert will not give up when key exists, if edesc->f_update is provided.
1286  * a new key is generated and insert is restarted.
1287  */
1288 static int
1289 lf_list_insert_internal (LF_TRAN_ENTRY * tran, void **list_p, void *key, int *behavior_flags,
1290  LF_ENTRY_DESCRIPTOR * edesc, LF_FREELIST * freelist, void **entry, int *inserted)
1291 {
1292  /* Macro's to avoid repeating the code (and making mistakes) */
1293 
1294  /* Assert used to make sure the current entry is protected by either transaction or mutex. */
1295 #define LF_ASSERT_USE_MUTEX_OR_TRAN_STARTED() \
1296  assert (is_tran_started == !edesc->using_mutex); /* The transaction is started if and only if we don't use mutex */ \
1297  assert (!edesc->using_mutex || entry_mutex) /* If we use mutex, we have a mutex locked. */
1298 
1299  /* Start a transaction */
1300 #define LF_START_TRAN() \
1301  if (!is_tran_started) lf_tran_start_with_mb (tran, false); is_tran_started = true
1302 #define LF_START_TRAN_FORCE() \
1303  assert (!is_tran_started); lf_tran_start_with_mb (tran, false); is_tran_started = true
1304 
1305  /* End a transaction if started */
1306 #define LF_END_TRAN() \
1307  if (is_tran_started) lf_tran_end_with_mb (tran)
1308  /* Force end transaction; a transaction is expected */
1309 #define LF_END_TRAN_FORCE() \
1310  assert (is_tran_started); lf_tran_end_with_mb (tran); is_tran_started = false
1311 
1312 #if defined (UNITTEST_LF)
1313  /* Lock current entry (using mutex is expected) */
1314 #define LF_LOCK_ENTRY(tolock) \
1315  assert (tran->locked_mutex == NULL); \
1316  assert (edesc->using_mutex); \
1317  assert ((tolock) != NULL); \
1318  assert (entry_mutex == NULL); \
1319  /* entry has a mutex protecting it's members; lock it */ \
1320  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (tolock, edesc->of_mutex); \
1321  tran->locked_mutex_line = __LINE__; \
1322  tran->locked_mutex = entry_mutex; \
1323  rv = pthread_mutex_lock (entry_mutex)
1324 
1325  /* Unlock current entry (if it was locked). */
1326 #define LF_UNLOCK_ENTRY() \
1327  if (edesc->using_mutex && entry_mutex) \
1328  { \
1329  assert (tran->locked_mutex == entry_mutex); \
1330  tran->locked_mutex = NULL; \
1331  pthread_mutex_unlock (entry_mutex); \
1332  entry_mutex = NULL; \
1333  }
1334  /* Force unlocking current entry (it is expected to be locked). */
1335 #define LF_UNLOCK_ENTRY_FORCE() \
1336  assert (edesc->using_mutex && entry_mutex != NULL); \
1337  assert (tran->locked_mutex == entry_mutex); \
1338  tran->locked_mutex = NULL; \
1339  pthread_mutex_unlock (entry_mutex); \
1340  entry_mutex = NULL
1341 #else /* !UNITTEST_LF */
1342  /* Lock current entry (using mutex is expected) */
1343 #define LF_LOCK_ENTRY(tolock) \
1344  assert (edesc->using_mutex); \
1345  assert ((tolock) != NULL); \
1346  assert (entry_mutex == NULL); \
1347  /* entry has a mutex protecting it's members; lock it */ \
1348  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (tolock, edesc->of_mutex); \
1349  rv = pthread_mutex_lock (entry_mutex)
1350 
1351  /* Unlock current entry (if it was locked). */
1352 #define LF_UNLOCK_ENTRY() \
1353  if (edesc->using_mutex && entry_mutex) \
1354  { \
1355  pthread_mutex_unlock (entry_mutex); \
1356  entry_mutex = NULL; \
1357  }
1358  /* Force unlocking current entry (it is expected to be locked). */
1359 #define LF_UNLOCK_ENTRY_FORCE() \
1360  assert (edesc->using_mutex && entry_mutex != NULL); \
1361  pthread_mutex_unlock (entry_mutex); \
1362  entry_mutex = NULL
1363 #endif /* !UNITTEST_LF */
1364 
1365  pthread_mutex_t *entry_mutex = NULL; /* Locked entry mutex when not NULL */
1366  void **curr_p;
1367  void *curr;
1368  int rv;
1369  bool is_tran_started = false;
1370 
1371  assert (tran != NULL);
1372  assert (list_p != NULL && edesc != NULL);
1373  assert (key != NULL && entry != NULL);
1374  assert (freelist != NULL);
1375  assert (behavior_flags != NULL);
1376 
1377  assert ((*entry != NULL) == LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_INSERT_GIVEN));
1378 
1379  if (inserted != NULL)
1380  {
1381  *inserted = 0;
1382  }
1383 
1384 restart_search:
1385 
1387 
1389 
1390  curr_p = list_p;
1391  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1392 
1393  /* search */
1394  while (curr_p != NULL)
1395  {
1396  assert (is_tran_started);
1397  assert (entry_mutex == NULL);
1398 
1399  if (curr != NULL)
1400  {
1401  if (edesc->f_key_cmp (key, OF_GET_PTR (curr, edesc->of_key)) == 0)
1402  {
1403  /* found an entry with the same key. */
1404 
1406 
1407  if (!LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_INSERT_GIVEN) && *entry != NULL)
1408  {
1409  /* save this for further (local) use. */
1410  assert (tran->temp_entry == NULL);
1411  tran->temp_entry = *entry;
1412 
1414  LF_UNITTEST_INC (&lf_temps, 1);
1415 
1416  /* don't keep the entry around. */
1417  *entry = NULL;
1418  }
1419 
1420  if (edesc->using_mutex)
1421  {
1422  /* entry has a mutex protecting it's members; lock it */
1423  LF_LOCK_ENTRY (curr);
1424 
1425  /* mutex has been locked, no need to keep transaction alive */
1426  LF_END_TRAN_FORCE ();
1427 
1428  if (ADDR_HAS_MARK (OF_GET_PTR_DEREF (curr, edesc->of_next)))
1429  {
1430  /* while waiting for lock, somebody else deleted the entry; restart the search */
1432 
1433  if (behavior_flags && (*behavior_flags & LF_LIST_BF_RETURN_ON_RESTART))
1434  {
1435  *behavior_flags = (*behavior_flags) | LF_LIST_BR_RESTARTED;
1436  return NO_ERROR;
1437  }
1438  else
1439  {
1440  goto restart_search;
1441  }
1442  }
1443  }
1444 
1446  if (edesc->f_duplicate != NULL)
1447  {
1448  /* we have a duplicate key callback. */
1449  if (edesc->f_duplicate (key, curr) != NO_ERROR)
1450  {
1451  ASSERT_ERROR ();
1452  LF_END_TRAN ();
1453  LF_UNLOCK_ENTRY ();
1454  return NO_ERROR;
1455  }
1456 #if 1
1457  LF_LIST_BR_SET_FLAG (behavior_flags, LF_LIST_BR_RESTARTED);
1458  LF_END_TRAN ();
1459  LF_UNLOCK_ENTRY ();
1460  return NO_ERROR;
1461 #else /* !1 = 0 */
1462  /* Could we have such cases that we just update existing entry without modifying anything else?
1463  * And would it be usable with just a flag?
1464  * Then this code may be used.
1465  * So far we have only one usage for f_duplicate, which increment SESSION_ID and requires
1466  * restarting hash search. This will be the usual approach if f_duplicate.
1467  * If we just increment a counter in existing entry, we don't need to do anything else. This however
1468  * most likely depends on f_duplicate implementation. Maybe it is more useful to give behavior_flags
1469  * argument to f_duplicate to tell us if restart is or is not needed.
1470  */
1472  {
1473  LF_LIST_BR_SET_FLAG (behavior_flags, LF_LIST_BR_RESTARTED);
1474  LF_END_TRAN ();
1475  LF_UNLOCK_ENTRY ();
1476  return NO_ERROR;
1477  }
1478  else
1479  {
1480  /* duplicate does not require restarting search. */
1481  if (LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_INSERT_GIVEN))
1482  {
1483  /* Could not be inserted. Retire the entry. */
1484  lf_freelist_retire (tran, freelist, *entry);
1485  *entry = NULL;
1486  }
1487 
1488  /* fall through to output current entry. */
1489  }
1490 #endif /* 0 */
1491  }
1492  else
1493  {
1494  if (LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_INSERT_GIVEN))
1495  {
1496  /* the given entry could not be inserted. retire it. */
1497  lf_freelist_retire (tran, freelist, *entry);
1498  *entry = NULL;
1499  }
1500 
1501  if (!LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_FIND_OR_INSERT))
1502  {
1503  /* found entry is not accepted */
1504  LF_END_TRAN ();
1505  LF_UNLOCK_ENTRY ();
1506  return NO_ERROR;
1507  }
1508 
1509  /* fall through to output current entry. */
1510  }
1511 
1512  assert (*entry == NULL);
1514  /* We don't end transaction or unlock mutex here. */
1515  *entry = curr;
1516  return NO_ERROR;
1517  }
1518 
1519  /* advance */
1520  curr_p = (void **) OF_GET_REF (curr, edesc->of_next);
1521  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1522  }
1523  else
1524  {
1525  /* end of bucket, we must insert */
1526  if (*entry == NULL)
1527  {
1529 
1530  *entry = lf_freelist_claim (tran, freelist);
1531  if (*entry == NULL)
1532  {
1533  assert (false);
1534  LF_END_TRAN_FORCE ();
1535  return ER_FAILED;
1536  }
1537 
1539 
1540  /* set it's key */
1541  if (edesc->f_key_copy (key, OF_GET_PTR (*entry, edesc->of_key)) != NO_ERROR)
1542  {
1543  assert (false);
1544  LF_END_TRAN_FORCE ();
1545  return ER_FAILED;
1546  }
1547  }
1548 
1549  if (edesc->using_mutex)
1550  {
1551  /* entry has a mutex protecting it's members; lock it */
1552  LF_LOCK_ENTRY (*entry);
1553  }
1554 
1555  /* attempt an add */
1556  if (!ATOMIC_CAS_ADDR (curr_p, (void *) NULL, (*entry)))
1557  {
1558  if (edesc->using_mutex)
1559  {
1560  /* link failed, unlock mutex */
1562  }
1563 
1565 
1566  /* someone added before us, restart process */
1568  {
1569  if (!LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_INSERT_GIVEN))
1570  {
1571  assert (tran->temp_entry == NULL);
1572  tran->temp_entry = *entry;
1573  *entry = NULL;
1574 
1576  LF_UNITTEST_INC (&lf_temps, 1);
1577  }
1578  LF_LIST_BR_SET_FLAG (behavior_flags, LF_LIST_BR_RESTARTED);
1579  LF_END_TRAN_FORCE ();
1580  return NO_ERROR;
1581  }
1582  else
1583  {
1584  LF_END_TRAN_FORCE ();
1585  goto restart_search;
1586  }
1587  }
1588 
1590 
1591  /* end transaction if mutex is acquired */
1592  if (edesc->using_mutex)
1593  {
1594  LF_END_TRAN_FORCE ();
1595  }
1596  if (inserted)
1597  {
1598  *inserted = 1;
1599  }
1601 
1602  /* done! */
1603  return NO_ERROR;
1604  }
1605  }
1606 
1607  /* impossible case */
1608  assert (false);
1609  return ER_FAILED;
1610 
1611 #undef LF_ASSERT_USE_MUTEX_OR_TRAN_STARTED
1612 #undef LF_START_TRAN
1613 #undef LF_START_TRAN_FORCE
1614 #undef LF_END_TRAN
1615 #undef LF_END_TRAN_FORCE
1616 #undef LF_LOCK_ENTRY
1617 #undef LF_UNLOCK_ENTRY
1618 #undef LF_UNLOCK_ENTRY_FORCE
1619 }
1620 
1621 /*
1622  * lf_list_delete () - delete an entry from a list
1623  * returns: error code or NO_ERROR
1624  * tran(in): lock free transaction system
1625  * list_p(in): address of list head
1626  * key(in): key to search for
1627  * locked_entry(in): entry already locked.
1628  * behavior_flags(in/out): flags that control restart behavior
1629  * edesc(in): entry descriptor
1630  * freelist(in): freelist to place deleted entries to
1631  * success(out): 1 if entry was deleted, 0 otherwise
1632  */
1633 int
1634 lf_list_delete (LF_TRAN_ENTRY * tran, void **list_p, void *key, void *locked_entry, int *behavior_flags,
1635  LF_ENTRY_DESCRIPTOR * edesc, LF_FREELIST * freelist, int *success)
1636 {
1637  /* Start a transaction */
1638 #define LF_START_TRAN_FORCE() \
1639  assert (!is_tran_started); lf_tran_start_with_mb (tran, false); is_tran_started = true
1640 
1641  /* Promote from transaction without incremented transaction ID to transaction with incremented transaction ID. */
1642 #define LF_PROMOTE_TRAN_FORCE() \
1643  assert (is_tran_started); MEMORY_BARRIER (); lf_tran_start_with_mb (tran, true)
1644 
1645  /* End a transaction */
1646  /* Force end transaction; a transaction is expected */
1647 #define LF_END_TRAN_FORCE() \
1648  assert (is_tran_started); lf_tran_end_with_mb (tran); is_tran_started = false
1649 
1650 #if defined (UNITTEST_LF)
1651  /* Lock current entry (using mutex is expected) */
1652 #define LF_LOCK_ENTRY(tolock) \
1653  assert (edesc->using_mutex); \
1654  assert ((tolock) != NULL); \
1655  assert (entry_mutex == NULL); \
1656  /* entry has a mutex protecting it's members; lock it */ \
1657  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (tolock, edesc->of_mutex); \
1658  assert (tran->locked_mutex == NULL); \
1659  tran->locked_mutex = entry_mutex; \
1660  tran->locked_mutex_line = __LINE__; \
1661  rv = pthread_mutex_lock (entry_mutex)
1662 
1663  /* Force unlocking current entry (it is expected to be locked). */
1664 #define LF_UNLOCK_ENTRY_FORCE() \
1665  assert (edesc->using_mutex && entry_mutex != NULL); \
1666  assert (tran->locked_mutex == entry_mutex); \
1667  tran->locked_mutex = NULL; \
1668  pthread_mutex_unlock (entry_mutex); \
1669  entry_mutex = NULL
1670 #else /* !UNITTEST_LF */
1671  /* Lock current entry (using mutex is expected) */
1672 #define LF_LOCK_ENTRY(tolock) \
1673  assert (edesc->using_mutex); \
1674  assert ((tolock) != NULL); \
1675  assert (entry_mutex == NULL); \
1676  /* entry has a mutex protecting it's members; lock it */ \
1677  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (tolock, edesc->of_mutex); \
1678  rv = pthread_mutex_lock (entry_mutex)
1679 
1680  /* Force unlocking current entry (it is expected to be locked). */
1681 #define LF_UNLOCK_ENTRY_FORCE() \
1682  assert (edesc->using_mutex && entry_mutex != NULL); \
1683  pthread_mutex_unlock (entry_mutex); \
1684  entry_mutex = NULL
1685 #endif /* !UNITTEST_LF */
1686 
1687  pthread_mutex_t *entry_mutex = NULL;
1688  void **curr_p, **next_p;
1689  void *curr, *next;
1690  int rv;
1691  bool is_tran_started = false;
1692 
1693  /* reset success flag */
1694  if (success != NULL)
1695  {
1696  *success = 0;
1697  }
1698 
1699  assert (list_p != NULL && edesc != NULL && key != NULL);
1700  assert (freelist != NULL);
1701  assert (tran != NULL && tran->tran_system != NULL);
1702 
1703 restart_search:
1704 
1706 
1707  /* read transaction; we start a write transaction only after remove */
1709 
1710  curr_p = list_p;
1711  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1712 
1713  /* search */
1714  while (curr != NULL)
1715  {
1716  /* is this the droid we are looking for? */
1717  if (edesc->f_key_cmp (key, OF_GET_PTR (curr, edesc->of_key)) == 0)
1718  {
1719  if (locked_entry != NULL && locked_entry != curr)
1720  {
1721  assert (edesc->using_mutex && !LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_LOCK_ON_DELETE));
1722 
1723  /* We are here because lf_hash_delete_already_locked was called. The entry found by matching key is
1724  * different from the entry we were trying to delete.
1725  * This is possible (please find the description of lf_hash_delete_already_locked). */
1727  LF_END_TRAN_FORCE ();
1728  return NO_ERROR;
1729  }
1730 
1731  /* fetch next entry */
1732  next_p = (void **) OF_GET_REF (curr, edesc->of_next);
1733  next = ADDR_STRIP_MARK (*((void *volatile *) next_p));
1734 
1736 
1737  /* set mark on next pointer; this way, if anyone else is trying to delete the next entry, it will fail */
1738  if (!ATOMIC_CAS_ADDR (next_p, next, ADDR_WITH_MARK (next)))
1739  {
1740  /* joke's on us, this time; somebody else marked it before */
1741 
1743 
1744  LF_END_TRAN_FORCE ();
1745  if (behavior_flags && (*behavior_flags & LF_LIST_BF_RETURN_ON_RESTART))
1746  {
1747  *behavior_flags = (*behavior_flags) | LF_LIST_BR_RESTARTED;
1748  assert ((*behavior_flags) & LF_LIST_BR_RESTARTED);
1749  return NO_ERROR;
1750  }
1751  else
1752  {
1753  goto restart_search;
1754  }
1755  }
1756 
1757  /* lock mutex if necessary */
1758  if (edesc->using_mutex)
1759  {
1760  if (LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_LOCK_ON_DELETE))
1761  {
1762  LF_LOCK_ENTRY (curr);
1763  }
1764  else
1765  {
1766  /* Must be already locked! */
1767 #if defined (UNITTEST_LF)
1768  assert (locked_entry != NULL && locked_entry == curr);
1769 #endif /* UNITTEST_LF */
1770  entry_mutex = (pthread_mutex_t *) OF_GET_PTR (curr, edesc->of_mutex);
1771 
1772 #if defined (UNITTEST_LF)
1773  assert (tran->locked_mutex != NULL && tran->locked_mutex == entry_mutex);
1774 #endif /* UNITTEST_LF */
1775  }
1776 
1777  /* since we set the mark, nobody else can delete it, so we have nothing else to check */
1778  }
1779 
1780  /* unlink */
1781  if (!ATOMIC_CAS_ADDR (curr_p, curr, next))
1782  {
1783  /* unlink failed; first step is to remove lock (if applicable) */
1784  if (edesc->using_mutex && LF_LIST_BF_IS_FLAG_SET (behavior_flags, LF_LIST_BF_LOCK_ON_DELETE))
1785  {
1787  }
1788 
1790 
1791  /* remove mark and restart search */
1792  if (!ATOMIC_CAS_ADDR (next_p, ADDR_WITH_MARK (next), next))
1793  {
1794  /* impossible case */
1795  assert (false);
1796  LF_END_TRAN_FORCE ();
1797  return ER_FAILED;
1798  }
1799 
1800  LF_END_TRAN_FORCE ();
1801  if (behavior_flags && (*behavior_flags & LF_LIST_BF_RETURN_ON_RESTART))
1802  {
1803  *behavior_flags = (*behavior_flags) | LF_LIST_BR_RESTARTED;
1804  assert ((*behavior_flags) & LF_LIST_BR_RESTARTED);
1805  return NO_ERROR;
1806  }
1807  else
1808  {
1809  goto restart_search;
1810  }
1811  }
1812  /* unlink successful */
1813 
1815 
1816  /* unlock mutex */
1817  if (edesc->using_mutex)
1818  {
1820  }
1821 
1823 
1824  /* now we can feed the entry to the freelist and forget about it */
1825  if (lf_freelist_retire (tran, freelist, curr) != NO_ERROR)
1826  {
1827  assert (false);
1828  LF_END_TRAN_FORCE ();
1829  return ER_FAILED;
1830  }
1831 
1832  /* end the transaction */
1833  LF_END_TRAN_FORCE ();
1834 
1835  /* set success flag */
1836  if (success != NULL)
1837  {
1838  *success = 1;
1839  }
1841 
1842  /* success! */
1843  return NO_ERROR;
1844  }
1845 
1846  /* advance */
1847  curr_p = (void **) OF_GET_REF (curr, edesc->of_next);
1848  curr = ADDR_STRIP_MARK (*((void *volatile *) curr_p));
1849  }
1850 
1852 
1853  /* search yielded no result so no delete was performed */
1854  LF_END_TRAN_FORCE ();
1855  return NO_ERROR;
1856 
1857 #undef LF_START_TRAN_FORCE
1858 #undef LF_PROMOTE_TRAN_FORCE
1859 #undef LF_END_TRAN_FORCE
1860 #undef LF_LOCK_ENTRY
1861 #undef LF_UNLOCK_ENTRY_FORCE
1862 }
1863 
1864 /*
1865  * lf_hash_init () - initialize a lock free hash table
1866  * returns: error code or NO_ERROR
1867  * table(in): hash table structure to initialize
1868  * freelist(in): freelist to use for entries
1869  * hash_size(in): size of hash table
1870  * edesc(in): entry descriptor
1871  */
1872 int
1873 lf_hash_init (LF_HASH_TABLE * table, LF_FREELIST * freelist, unsigned int hash_size, LF_ENTRY_DESCRIPTOR * edesc)
1874 {
1875  assert (table != NULL && freelist != NULL && edesc != NULL);
1876  assert (hash_size > 0);
1877 
1878  if (table->buckets != NULL)
1879  {
1880  /* already initialized */
1881  return NO_ERROR;
1882  }
1883 
1884  /* register values */
1885  table->freelist = freelist;
1886  table->hash_size = hash_size;
1887  table->entry_desc = edesc;
1888 
1889  /* allocate bucket space */
1890  table->buckets = (void **) malloc (sizeof (void *) * hash_size);
1891  if (table->buckets == NULL)
1892  {
1893  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (void *) * hash_size);
1894  return ER_OUT_OF_VIRTUAL_MEMORY;
1895  }
1896  else
1897  {
1898  /* zero all */
1899  memset (table->buckets, 0, sizeof (void *) * hash_size);
1900  }
1901 
1902  /* allocate backbuffer */
1903  table->backbuffer = (void **) malloc (sizeof (void *) * hash_size);
1904  if (table->backbuffer == NULL)
1905  {
1906  free (table->buckets);
1907  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (void *) * hash_size);
1908  return ER_OUT_OF_VIRTUAL_MEMORY;
1909  }
1910  else
1911  {
1912  int i;
1913 
1914  /* put backbuffer in a "locked" state */
1915  for (i = 0; i < (int) hash_size; i++)
1916  {
1917  table->backbuffer[i] = ADDR_WITH_MARK (NULL);
1918  }
1919 
1920  /* initialize mutex */
1922  }
1923 
1924  /* all ok */
1925  return NO_ERROR;
1926 }
1927 
1928 /*
1929  * lf_hash_destroy () - destroy a hash table
1930  * table(in): hash table to destroy
1931  */
1932 void
1934 {
1935  unsigned int i;
1936  void *entry, *next;
1937 
1938  if (table == NULL)
1939  {
1940  return;
1941  }
1942 
1943  if (table->buckets)
1944  {
1945  /* free entries */
1946  for (i = 0; i < table->hash_size; i++)
1947  {
1948  entry = table->buckets[i];
1949 
1950  while (entry != NULL)
1951  {
1952  next = OF_GET_PTR_DEREF (entry, table->entry_desc->of_next);
1953 
1954  if (table->entry_desc->f_uninit != NULL)
1955  {
1956  table->entry_desc->f_uninit (entry);
1957  }
1958  table->entry_desc->f_free (entry);
1959  entry = next;
1960  }
1961  }
1962 
1963  /* free memory */
1964  free (table->buckets);
1965  table->buckets = NULL;
1966  }
1967 
1969  if (table->backbuffer)
1970  {
1971  free (table->backbuffer);
1972  table->backbuffer = NULL;
1973  }
1974 
1975  table->hash_size = 0;
1976 }
1977 
1978 /*
1979  * lf_hash_find () - find an entry in the hash table given a key
1980  * returns: error code or NO_ERROR
1981  * tran(in): LF transaction entry
1982  * table(in): hash table
1983  * key(in): key of entry that we seek
1984  * entry(out): existing or NULL otherwise
1985  */
1986 int
1987 lf_hash_find (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void **entry)
1988 {
1989  LF_ENTRY_DESCRIPTOR *edesc;
1990  unsigned int hash_value;
1991  int rc, bflags;
1992 
1993  assert (table != NULL && key != NULL && entry != NULL);
1994  edesc = table->entry_desc;
1995  assert (edesc != NULL);
1996 
1997 restart:
1998  *entry = NULL;
1999  hash_value = edesc->f_hash (key, table->hash_size);
2000  if (hash_value >= table->hash_size)
2001  {
2002  assert (false);
2003  return ER_FAILED;
2004  }
2005 
2007  rc = lf_list_find (tran, &table->buckets[hash_value], key, &bflags, edesc, entry);
2008  if ((rc == NO_ERROR) && (bflags & LF_LIST_BR_RESTARTED))
2009  {
2010  goto restart;
2011  }
2012  else
2013  {
2014  return rc;
2015  }
2016 }
2017 
2018 /*
2019  * lf_hash_insert_internal () - hash insert function.
2020  * returns: error code or NO_ERROR
2021  * tran(in): LF transaction entry
2022  * table(in): hash table
2023  * key(in): key of entry that we seek
2024  * bflags(in): behavior flags
2025  * entry(out): existing or new entry
2026  * inserted(out): returns 1 if inserted, 0 if found or not inserted.
2027  *
2028  * Behavior flags:
2029  *
2030  * LF_LIST_BF_RETURN_ON_RESTART - When insert fails because last entry in bucket was deleted, if this flag is set,
2031  * then the operation is restarted from here, instead of looping inside
2032  * lf_list_insert_internal (as a consequence, hash key is recalculated).
2033  * NOTE: Currently, this flag is always used (I must find out why).
2034  *
2035  * LF_LIST_BF_INSERT_GIVEN - If this flag is set, the caller means to force its own entry into hash table.
2036  * When the flag is not set, a new entry is claimed from freelist.
2037  * NOTE: If an entry with the same key already exists, the entry given as argument is
2038  * automatically retired.
2039  *
2040  * LF_LIST_BF_FIND_OR_INSERT - If this flag is set and an entry for the same key already exists, the existing
2041  * key will be output. If the flag is not set and key exists, insert just gives up
2042  * and a NULL entry is output.
2043  * NOTE: insert will not give up when key exists, if edesc->f_update is provided.
2044  * a new key is generated and insert is restarted.
2045  */
2046 static int
2047 lf_hash_insert_internal (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, int bflags, void **entry,
2048  int *inserted)
2049 {
2050  LF_ENTRY_DESCRIPTOR *edesc;
2051  unsigned int hash_value;
2052  int rc;
2053 
2054  assert (table != NULL && key != NULL && entry != NULL);
2055  edesc = table->entry_desc;
2056  assert (edesc != NULL);
2057 
2059 
2060 restart:
2062  {
2063  assert (*entry != NULL);
2064  }
2065  else
2066  {
2067  *entry = NULL;
2068  }
2069  hash_value = edesc->f_hash (key, table->hash_size);
2070  if (hash_value >= table->hash_size)
2071  {
2072  assert (false);
2073  return ER_FAILED;
2074  }
2075 
2076  rc =
2077  lf_list_insert_internal (tran, &table->buckets[hash_value], key, &bflags, edesc, table->freelist, entry, inserted);
2078  if ((rc == NO_ERROR) && (bflags & LF_LIST_BR_RESTARTED))
2079  {
2080  bflags &= ~LF_LIST_BR_RESTARTED;
2082  goto restart;
2083  }
2084  else
2085  {
2086  return rc;
2087  }
2088 }
2089 
2090 /*
2091  * lf_hash_find_or_insert () - find or insert an entry in the hash table
2092  * returns: error code or NO_ERROR
2093  * tran(in): LF transaction entry
2094  * table(in): hash table
2095  * key(in): key of entry that we seek
2096  * entry(out): existing or new entry
2097  * inserted(out): returns 1 if inserted, 0 if found or not inserted.
2098  *
2099  */
2100 int
2101 lf_hash_find_or_insert (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void **entry, int *inserted)
2102 {
2104  inserted);
2105 }
2106 
2107 /*
2108  * lf_hash_insert () - insert a new entry with a specified key.
2109  * returns: error code or NO_ERROR
2110  * tran(in): LF transaction entry
2111  * table(in): hash table
2112  * key(in): key of entry to insert
2113  * entry(out): new entry
2114  * inserted(out): returns 1 if inserted, 0 if found or not inserted.
2115  *
2116  */
2117 int
2118 lf_hash_insert (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void **entry, int *inserted)
2119 {
2120  return lf_hash_insert_internal (tran, table, key, LF_LIST_BF_RETURN_ON_RESTART, entry, inserted);
2121 }
2122 
2123 /*
2124  * lf_hash_insert_given () - insert entry given as argument. if same key exists however, replace it with existing key.
2125  * returns: error code or NO_ERROR
2126  * tran(in): LF transaction entry
2127  * table(in): hash table
2128  * key(in): key of entry to insert
2129  * entry(in/out): new entry
2130  * inserted(out): returns 1 if inserted, 0 if found or not inserted.
2131  *
2132  */
2133 int
2134 lf_hash_insert_given (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void **entry, int *inserted)
2135 {
2136  assert (entry != NULL && *entry != NULL);
2137  return lf_hash_insert_internal (tran, table, key,
2139  entry, inserted);
2140 }
2141 
2142 /*
2143  * lf_hash_delete_already_locked () - Delete hash entry without locking mutex.
2144  *
2145  * return : error code or NO_ERROR
2146  * tran (in) : LF transaction entry
2147  * table (in) : hash table
2148  * key (in) : key to seek
2149  * locked_entry (in) : locked entry
2150  * success (out) : 1 if entry is deleted, 0 otherwise
2151  *
2152  * NOTE: Careful when calling this function. The typical scenario to call this function is to first find entry using
2153  * lf_hash_find and then call lf_hash_delete on the found entry.
2154  * NOTE: lf_hash_delete_already_locks can be called only if entry has mutexes.
2155  * NOTE: The delete will be successful only if the entry found by key matches the given entry.
2156  * Usually, the entry will match. However, we do have a limited scenario when a different entry with the same
2157  * key may be found:
2158  * 1. Entry was found or inserted by this transaction.
2159  * 2. Another transaction cleared the hash. All current entries are moved to back buffer and will be soon retired.
2160  * 3. A third transaction inserts a new entry with the same key.
2161  * 4. This transaction tries to delete the entry but the entry inserted by the third transaction si found.
2162  */
2163 int
2164 lf_hash_delete_already_locked (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void *locked_entry, int *success)
2165 {
2166  assert (locked_entry != NULL);
2167  assert (table->entry_desc->using_mutex);
2168  return lf_hash_delete_internal (tran, table, key, locked_entry, LF_LIST_BF_RETURN_ON_RESTART, success);
2169 }
2170 
2171 /*
2172  * lf_hash_delete () - Delete hash entry. If the entries have mutex, it will lock the mutex before deleting.
2173  *
2174  * return : error code or NO_ERROR
2175  * tran (in) : LF transaction entry
2176  * table (in) : hash table
2177  * key (in) : key to seek
2178  * success (out) : 1 if entry is deleted, 0 otherwise
2179  */
2180 int
2181 lf_hash_delete (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, int *success)
2182 {
2184  success);
2185 }
2186 
2187 
2188 /*
2189  * lf_hash_delete () - delete an entry from the hash table
2190  * returns: error code or NO_ERROR
2191  * tran(in): LF transaction entry
2192  * table(in): hash table
2193  * locked_entry(in): locked entry
2194  * key(in): key to seek
2195  * success(out): 1 if entry is deleted, 0 otherwise.
2196  */
2197 static int
2198 lf_hash_delete_internal (LF_TRAN_ENTRY * tran, LF_HASH_TABLE * table, void *key, void *locked_entry, int bflags,
2199  int *success)
2200 {
2201  LF_ENTRY_DESCRIPTOR *edesc;
2202  unsigned int hash_value;
2203  int rc;
2204 
2205  assert (table != NULL && key != NULL);
2206  edesc = table->entry_desc;
2207  assert (edesc != NULL);
2208 
2210 
2211 restart:
2212  if (success != NULL)
2213  {
2214  *success = 0;
2215  }
2216  hash_value = edesc->f_hash (key, table->hash_size);
2217  if (hash_value >= table->hash_size)
2218  {
2219  assert (false);
2220  return ER_FAILED;
2221  }
2222 
2223  rc = lf_list_delete (tran, &table->buckets[hash_value], key, locked_entry, &bflags, edesc, table->freelist, success);
2224  if ((rc == NO_ERROR) && (bflags & LF_LIST_BR_RESTARTED))
2225  {
2226  /* Remove LF_LIST_BR_RESTARTED from behavior flags. */
2227  bflags &= ~LF_LIST_BR_RESTARTED;
2229  goto restart;
2230  }
2231  else
2232  {
2233  return rc;
2234  }
2235 }
2236 
2237 /*
2238  * lf_hash_clear () - clear the hash table
2239  * returns: Void
2240  * tran(in): LF transaction entry
2241  * table(in): hash table to clear
2242  *
2243  * NOTE: This function is NOT lock free.
2244  */
2245 void
2247 {
2248  LF_ENTRY_DESCRIPTOR *edesc;
2249  void **old_buckets, *curr, **next_p, *next;
2250  void *ret_head = NULL, *ret_tail = NULL;
2251  pthread_mutex_t *mutex_p;
2252  int rv, i, ret_count = 0;
2253 
2254  assert (tran != NULL && table != NULL && table->freelist != NULL);
2255  edesc = table->entry_desc;
2256  assert (edesc != NULL);
2257 
2258 #if defined (UNITTEST_LF)
2259  assert (tran->locked_mutex == NULL);
2260 #endif /* UNITTEST_LF */
2261 
2262  /* lock mutex */
2263  rv = pthread_mutex_lock (&table->backbuffer_mutex);
2264 
2265  /* swap bucket pointer with current backbuffer */
2266  do
2267  {
2268  old_buckets = VOLATILE_ACCESS (table->buckets, void **);
2269  }
2270  while (!ATOMIC_CAS_ADDR (&table->buckets, old_buckets, table->backbuffer));
2271 
2272  /* clear bucket buffer, containing remains of old entries marked for delete */
2273  for (i = 0; i < (int) table->hash_size; i++)
2274  {
2275  assert (table->backbuffer[i] == ADDR_WITH_MARK (NULL));
2276  table->buckets[i] = NULL;
2277  }
2278 
2279  /* register new backbuffer */
2280  table->backbuffer = old_buckets;
2281 
2282  /* retire all entries from old buckets; note that threads currently operating on the entries will not be disturbed
2283  * since the actual deletion is performed when the entries are no longer handled by active transactions */
2284  for (i = 0; i < (int) table->hash_size; i++)
2285  {
2286  do
2287  {
2288  curr = ADDR_STRIP_MARK (VOLATILE_ACCESS (old_buckets[i], void *));
2289  }
2290  while (!ATOMIC_CAS_ADDR (&old_buckets[i], curr, ADDR_WITH_MARK (NULL)));
2291 
2292  while (curr)
2293  {
2294  next_p = (void **) OF_GET_REF (curr, edesc->of_next);
2295 
2296  /* unlink from hash chain */
2297  do
2298  {
2299  next = ADDR_STRIP_MARK (VOLATILE_ACCESS (*next_p, void *));
2300  }
2301  while (!ATOMIC_CAS_ADDR (next_p, next, ADDR_WITH_MARK (next)));
2302 
2303  /* wait for mutex */
2304  if (edesc->using_mutex)
2305  {
2306  mutex_p = (pthread_mutex_t *) OF_GET_PTR (curr, edesc->of_mutex);
2307 
2308  rv = pthread_mutex_lock (mutex_p);
2309  pthread_mutex_unlock (mutex_p);
2310 
2311  /* there should be only one mutex lock-unlock per entry per access via bucket array, so locking/unlocking
2312  * once while the entry is inaccessible should be enough to guarantee nobody will be using it afterwards */
2313  }
2314 
2315  /* save and advance */
2316  if (ret_head == NULL)
2317  {
2318  ret_head = curr;
2319  ret_tail = curr;
2320  ret_count = 1;
2321  }
2322  else
2323  {
2324  OF_GET_PTR_DEREF (ret_tail, edesc->of_local_next) = curr;
2325  ret_tail = curr;
2326  ret_count++;
2327  }
2328 
2329  /* advance */
2330  curr = next;
2331  }
2332  }
2333 
2334  if (ret_head != NULL)
2335  {
2336  /* reuse entries */
2337  lf_tran_start_with_mb (tran, true);
2338 
2339  for (curr = ret_head; curr != NULL; curr = OF_GET_PTR_DEREF (curr, edesc->of_local_next))
2340  {
2341  UINT64 *del_id = (UINT64 *) OF_GET_PTR (curr, edesc->of_del_tran_id);
2342  *del_id = tran->transaction_id;
2343  }
2344 
2345  OF_GET_PTR_DEREF (ret_tail, edesc->of_local_next) = tran->retired_list;
2346  tran->retired_list = ret_head;
2347 
2348  ATOMIC_INC_32 (&table->freelist->retired_cnt, ret_count);
2349 
2350  LF_UNITTEST_INC (&lf_clears, ret_count);
2351  LF_UNITTEST_INC (&lf_hash_size, -ret_count);
2352 
2353  lf_tran_end_with_mb (tran);
2354  }
2355 
2356  /* unlock mutex and return to caller */
2358 }
2359 
2360 /*
2361  * lf_hash_create_iterator () - create an iterator for a hash table
2362  * iterator(out): iterator to be initialized
2363  * tran_entry(in):
2364  * table(in): hash table to iterate on
2365  * returns: void
2366  */
2367 void
2369 {
2370  assert (iterator != NULL && table != NULL);
2371 
2372  iterator->hash_table = table;
2373  iterator->curr = NULL;
2374  iterator->bucket_index = -1;
2375  iterator->tran_entry = tran_entry;
2376 }
2377 
2378 /*
2379  * lf_hash_iterate () - iterate using a pre-created iterator
2380  * it(in): iterator
2381  * returns: next entry or NULL on end
2382  *
2383  * NOTE: Absolutely no order guaranteed.
2384  * NOTE: Caller must not change HP_LEADER until end of iteration.
2385  * NOTE: This function will change HP_TRAILER.
2386  */
2387 void *
2389 {
2390  LF_ENTRY_DESCRIPTOR *edesc;
2391  LF_TRAN_ENTRY *tran_entry;
2392  void **next_p;
2393 
2394  if (it == NULL || it->hash_table == NULL)
2395  {
2396  assert (false);
2397  return NULL;
2398  }
2399 
2400  edesc = it->hash_table->entry_desc;
2401  tran_entry = it->tran_entry;
2402  assert (edesc != NULL && tran_entry != NULL);
2403 
2404  do
2405  {
2406  /* save current leader as trailer */
2407  if (it->curr != NULL)
2408  {
2409  if (edesc->using_mutex)
2410  {
2411  /* follow house rules: lock mutex */
2412  pthread_mutex_t *mx;
2413  mx = (pthread_mutex_t *) OF_GET_PTR (it->curr, edesc->of_mutex);
2414  pthread_mutex_unlock (mx);
2415  }
2416 
2417  /* load next entry */
2418  next_p = (void **) OF_GET_REF (it->curr, edesc->of_next);
2419  it->curr = *(void *volatile *) next_p;
2420  it->curr = ADDR_STRIP_MARK (it->curr);
2421  }
2422  else
2423  {
2424  /* reset transaction for each bucket */
2425  if (it->bucket_index >= 0)
2426  {
2427  lf_tran_end_with_mb (tran_entry);
2428  }
2429  lf_tran_start_with_mb (tran_entry, false);
2430 
2431  /* load next bucket */
2432  it->bucket_index++;
2433  if (it->bucket_index < (int) it->hash_table->hash_size)
2434  {
2435  it->curr = VOLATILE_ACCESS (it->hash_table->buckets[it->bucket_index], void *);
2436  it->curr = ADDR_STRIP_MARK (it->curr);
2437  }
2438  else
2439  {
2440  /* end */
2441  lf_tran_end_with_mb (tran_entry);
2442  return NULL;
2443  }
2444  }
2445 
2446  if (it->curr != NULL)
2447  {
2448  if (edesc->using_mutex)
2449  {
2450  pthread_mutex_t *mx;
2451  int rv;
2452 
2453  mx = (pthread_mutex_t *) OF_GET_PTR (it->curr, edesc->of_mutex);
2454  rv = pthread_mutex_lock (mx);
2455 
2456  if (ADDR_HAS_MARK (OF_GET_PTR_DEREF (it->curr, edesc->of_next)))
2457  {
2458  /* deleted in the meantime, skip it */
2459  continue;
2460  }
2461  }
2462  }
2463  }
2464  while (it->curr == NULL);
2465 
2466  /* we have a valid entry */
2467  return it->curr;
2468 }
2469 
2470 #if defined (UNITTEST_LF)
2471 /*
2472  * lf_reset_counters () - Reset all counters.
2473  *
2474  * return :
2475  * void (in) :
2476  */
2477 void
2478 lf_reset_counters (void)
2479 {
2480  lf_hash_size = 0;
2481 
2482  lf_inserts = 0;
2483  lf_inserts_restart = 0;
2484  lf_list_inserts = 0;
2491 
2492  lf_deletes = 0;
2493  lf_deletes_restart = 0;
2494  lf_list_deletes = 0;
2501 
2502  lf_clears = 0;
2503 
2504  lf_retires = 0;
2505  lf_claims = 0;
2506  lf_claims_temp = 0;
2507  lf_transports = 0;
2508  lf_temps = 0;
2509 }
2510 #endif /* UNITTEST_LF */
int lf_freelist_transport(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist)
Definition: lock_free.c:930
#define NO_ERROR
Definition: error_code.h:46
#define LF_LIST_BF_INSERT_GIVEN
Definition: lock_free.h:274
int mati_refresh_interval
Definition: lock_free.h:170
#define LF_END_TRAN_FORCE()
#define LF_NULL_TRANSACTION_ID
Definition: lock_free.h:115
int lf_list_delete(LF_TRAN_ENTRY *tran, void **list_p, void *key, void *locked_entry, int *behavior_flags, LF_ENTRY_DESCRIPTOR *edesc, LF_FREELIST *freelist, int *success)
Definition: lock_free.c:1634
#define ADDR_STRIP_MARK(p)
Definition: lock_free.c:72
static INT64 lf_list_inserts
Definition: lock_free.c:86
#define ASSERT_ERROR()
static INT64 lf_list_inserts_claim
Definition: lock_free.c:90
void * temp_entry
Definition: lock_free.h:132
unsigned int of_local_next
Definition: lock_free.h:66
void lf_hash_destroy(LF_HASH_TABLE *table)
Definition: lock_free.c:1933
LF_HASH_TABLE * hash_table
Definition: lock_free.h:340
LF_ENTRY_INITIALIZE_FUNC f_init
Definition: lock_free.h:90
LF_TRAN_ENTRY * lf_tran_request_entry(LF_TRAN_SYSTEM *sys)
Definition: lock_free.c:271
static const LF_BITMAP_STYLE LF_BITMAP_ONE_CHUNK
int retired_cnt
Definition: lock_free.h:239
int available_cnt
Definition: lock_free.h:238
int alloc_cnt
Definition: lock_free.h:237
#define ER_FAILED
Definition: error_code.h:47
void * lf_hash_iterate(LF_HASH_TABLE_ITERATOR *it)
Definition: lock_free.c:2388
UINT64 global_transaction_id
Definition: lock_free.h:164
static INT64 lf_clears
Definition: lock_free.c:104
pthread_mutex_t backbuffer_mutex
Definition: lock_free.h:305
LF_TRAN_SYSTEM sessions_Ts
Definition: lock_free.c:50
LF_ENTRY_UNINITIALIZE_FUNC f_uninit
Definition: lock_free.h:93
void ** backbuffer
Definition: lock_free.h:302
unsigned int hash_size
Definition: lock_free.h:308
static int rv
Definition: lock_free.c:40
int lf_hash_delete_already_locked(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void *locked_entry, int *success)
Definition: lock_free.c:2164
int lf_hash_find(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void **entry)
Definition: lock_free.c:1987
void free_entry(int entry_idx)
static INT64 lf_list_inserts_fail_link
Definition: lock_free.c:91
void lf_hash_create_iterator(LF_HASH_TABLE_ITERATOR *iterator, LF_TRAN_ENTRY *tran_entry, LF_HASH_TABLE *table)
Definition: lock_free.c:2368
static INT64 lf_list_deletes
Definition: lock_free.c:96
Definition: lock_free.h:63
LF_ENTRY_FREE_FUNC f_free
Definition: lock_free.h:87
Definition: lock_free.h:120
static INT64 lf_list_deletes_fail_mark_next
Definition: lock_free.c:98
void * retired_list
Definition: lock_free.h:129
int lf_initialize_transaction_systems(int max_threads)
Definition: lock_free.c:448
static INT64 lf_list_inserts_found
Definition: lock_free.c:87
void lf_tran_system_destroy(LF_TRAN_SYSTEM *sys)
Definition: lock_free.c:240
void * lf_stack_pop(void **top, LF_ENTRY_DESCRIPTOR *edesc)
Definition: lock_free.c:575
UINT64 last_cleanup_id
Definition: lock_free.h:123
int32_t pageid
Definition: dbtype_def.h:879
#define lf_tran_end_with_mb(entry)
Definition: lock_free.h:198
LF_TRAN_SYSTEM spage_saving_Ts
Definition: lock_free.c:46
void * lf_freelist_claim(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist)
Definition: lock_free.c:751
void lf_tran_destroy_entry(LF_TRAN_ENTRY *entry)
Definition: lock_free.c:336
static INT64 lf_inserts
Definition: lock_free.c:84
LF_ENTRY_DESCRIPTOR * entry_desc
Definition: lock_free.h:314
#define LF_BITMAP_COUNT_ALIGN(count)
static INT64 lf_deletes
Definition: lock_free.c:94
LF_ENTRY_DESCRIPTOR * entry_desc
Definition: lock_free.h:242
void lf_destroy_transaction_systems(void)
Definition: lock_free.c:520
#define ADDR_WITH_MARK(p)
Definition: lock_free.c:71
void lf_tran_end(LF_TRAN_ENTRY *entry)
Definition: lock_free.c:436
#define lf_tran_start_with_mb(entry, incr)
Definition: lock_free.h:197
unsigned int of_del_tran_id
Definition: lock_free.h:72
LF_TRAN_SYSTEM xcache_Ts
Definition: lock_free.c:54
static bool tran_systems_initialized
Definition: lock_free.c:58
static INT64 lf_retires
Definition: lock_free.c:106
int lf_tran_system_init(LF_TRAN_SYSTEM *sys, int max_threads)
Definition: lock_free.c:184
int lf_hash_init(LF_HASH_TABLE *table, LF_FREELIST *freelist, unsigned int hash_size, LF_ENTRY_DESCRIPTOR *edesc)
Definition: lock_free.c:1873
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
LF_TRAN_SYSTEM obj_lock_ent_Ts
Definition: lock_free.c:48
#define LF_PROMOTE_TRAN_FORCE()
int lf_callback_vpid_compare(void *vpid_1, void *vpid_2)
Definition: lock_free.c:154
#define assert(x)
UINT64 min_active_transaction_id
Definition: lock_free.h:167
static INT64 lf_list_deletes_found
Definition: lock_free.c:97
LF_ENTRY_KEY_COPY_FUNC f_key_copy
Definition: lock_free.h:96
LF_BITMAP lf_bitmap
Definition: lock_free.h:161
void lf_tran_return_entry(LF_TRAN_ENTRY *entry)
Definition: lock_free.c:310
LF_TRAN_SYSTEM * tran_system
Definition: lock_free.h:245
int used_entry_count
Definition: lock_free.h:173
LF_ENTRY_KEY_COMPARE_FUNC f_key_cmp
Definition: lock_free.h:99
static INT64 lf_deletes_restart
Definition: lock_free.c:95
unsigned int of_next
Definition: lock_free.h:69
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
#define pthread_mutex_lock(a)
Definition: lock_free.c:37
#define LF_LIST_BF_IS_FLAG_SET(bf, flag)
Definition: lock_free.h:277
static INT64 lf_list_deletes_not_found
Definition: lock_free.c:101
static INT64 lf_list_deletes_success_unlink
Definition: lock_free.c:100
#define LF_ASSERT_USE_MUTEX_OR_TRAN_STARTED()
int lf_stack_push(void **top, void *entry, LF_ENTRY_DESCRIPTOR *edesc)
Definition: lock_free.c:545
LF_TRAN_SYSTEM dwb_slots_Ts
Definition: lock_free.c:56
int lf_freelist_retire(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist, void *entry)
Definition: lock_free.c:864
void lf_tran_compute_minimum_transaction_id(LF_TRAN_SYSTEM *sys)
Definition: lock_free.c:369
#define pthread_mutex_unlock(a)
Definition: lock_free.c:39
void ** buckets
Definition: lock_free.h:299
unsigned int lf_callback_vpid_hash(void *vpid, int htsize)
Definition: lock_free.c:140
#define LF_UNITTEST_INC(lf_stat, incval)
Definition: lock_free.c:115
#define OF_GET_PTR(p, o)
Definition: lock_free.c:64
short volid
Definition: dbtype_def.h:880
#define LF_START_TRAN_FORCE()
#define LF_LIST_BF_RESTART_ON_DUPLICATE
Definition: lock_free.h:273
static INT64 lf_list_inserts_save_temp_1
Definition: lock_free.c:88
static INT64 lf_transports
Definition: lock_free.c:109
int lf_io_list_find(void **list_p, void *key, LF_ENTRY_DESCRIPTOR *edesc, void **entry)
Definition: lock_free.c:1047
LF_TRAN_SYSTEM global_unique_stats_Ts
Definition: lock_free.c:52
#define NULL
Definition: freelistheap.h:34
int lf_hash_find_or_insert(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void **entry, int *inserted)
Definition: lock_free.c:2101
static INT64 lf_list_deletes_fail_unlink
Definition: lock_free.c:99
#define LF_LOCK_ENTRY(tolock)
static int success()
LF_TRAN_SYSTEM hfid_table_Ts
Definition: lock_free.c:53
static int lf_list_insert_internal(LF_TRAN_ENTRY *tran, void **list_p, void *key, int *behavior_flags, LF_ENTRY_DESCRIPTOR *edesc, LF_FREELIST *freelist, void **entry, int *inserted)
Definition: lock_free.c:1289
unsigned int of_mutex
Definition: lock_free.h:78
static INT64 lf_list_deletes_not_match
Definition: lock_free.c:102
LF_ENTRY_DUPLICATE_KEY_HANDLER f_duplicate
Definition: lock_free.h:106
int lf_freelist_init(LF_FREELIST *freelist, int initial_blocks, int block_size, LF_ENTRY_DESCRIPTOR *edesc, LF_TRAN_SYSTEM *tran_system)
Definition: lock_free.c:666
LF_TRAN_SYSTEM catalog_Ts
Definition: lock_free.c:49
#define LF_BITFIELD_WORD_SIZE
#define LF_LIST_BF_FIND_OR_INSERT
Definition: lock_free.h:275
int using_mutex
Definition: lock_free.h:81
#define LF_LIST_BF_RETURN_ON_RESTART
Definition: lock_free.h:272
#define LF_LIST_BR_SET_FLAG(br, flag)
Definition: lock_free.h:284
static void error(const char *msg)
Definition: gencat.c:331
LF_ENTRY_HASH_FUNC f_hash
Definition: lock_free.h:102
static int rc
Definition: serial.c:50
#define LF_LIST_BF_LOCK_ON_DELETE
Definition: lock_free.h:276
std::atomic< unsigned int > * bitfield
static INT64 lf_hash_size
Definition: lock_free.c:82
#define ARG_FILE_LINE
Definition: error_manager.h:44
static INT64 lf_inserts_restart
Definition: lock_free.c:85
LF_ENTRY_ALLOC_FUNC f_alloc
Definition: lock_free.h:84
void lf_hash_clear(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table)
Definition: lock_free.c:2246
int lf_io_list_find_or_insert(void **list_p, void *new_entry, LF_ENTRY_DESCRIPTOR *edesc, void **entry)
Definition: lock_free.c:1101
int lf_hash_insert(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void **entry, int *inserted)
Definition: lock_free.c:2118
static INT64 lf_temps
Definition: lock_free.c:110
#define pthread_mutex_init(a, b)
Definition: lock_free.c:35
static INT64 lf_claims_temp
Definition: lock_free.c:108
int lf_list_find(LF_TRAN_ENTRY *tran, void **list_p, void *key, int *behavior_flags, LF_ENTRY_DESCRIPTOR *edesc, void **entry)
Definition: lock_free.c:1191
LF_ENTRY_DESCRIPTOR * entry_desc
Definition: lock_free.h:176
#define LF_TRAN_SYSTEM_INITIALIZER
Definition: lock_free.h:179
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define LF_UNLOCK_ENTRY_FORCE()
static INT64 lf_list_inserts_save_temp_2
Definition: lock_free.c:89
LF_FREELIST * freelist
Definition: lock_free.h:311
void lf_tran_start(LF_TRAN_ENTRY *entry, bool incr)
Definition: lock_free.c:403
void lf_freelist_destroy(LF_FREELIST *freelist)
Definition: lock_free.c:711
#define OF_GET_REF(p, o)
Definition: lock_free.c:63
int lf_hash_insert_given(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void **entry, int *inserted)
Definition: lock_free.c:2134
LF_TRAN_ENTRY * tran_entry
Definition: lock_free.h:349
#define pthread_mutex_destroy(a)
Definition: lock_free.c:36
static int lf_hash_delete_internal(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, void *locked_entry, int bflags, int *success)
Definition: lock_free.c:2198
int entry_idx
Definition: lock_free.h:138
int i
Definition: dynamic_load.c:954
int block_size
Definition: lock_free.h:234
int lf_hash_delete(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, int *success)
Definition: lock_free.c:2181
#define LF_UNLOCK_ENTRY()
LF_TRAN_SYSTEM * tran_system
Definition: lock_free.h:135
LF_TRAN_ENTRY * entries
Definition: lock_free.h:155
#define VOLATILE_ACCESS(v, t)
Definition: area_alloc.c:85
UINT64 transaction_id
Definition: lock_free.h:126
#define LF_LIST_BR_RESTARTED
Definition: lock_free.h:281
#define LF_END_TRAN()
#define ADDR_HAS_MARK(p)
Definition: lock_free.c:70
static INT64 lf_list_inserts_success_link
Definition: lock_free.c:92
static INT64 lf_claims
Definition: lock_free.c:107
#define OF_GET_PTR_DEREF(p, o)
Definition: lock_free.c:65
bool did_incr
Definition: lock_free.h:141
void * available
Definition: lock_free.h:231
#define LF_TRAN_CLEANUP_NECESSARY(e)
Definition: lock_free.h:182
void init(chunking_style style, int entries_count, float usage_ratio)
LF_TRAN_SYSTEM free_sort_list_Ts
Definition: lock_free.c:51
int lf_callback_vpid_copy(void *src, void *dest)
Definition: lock_free.c:169
LF_TRAN_SYSTEM fpcache_Ts
Definition: lock_free.c:55
unsigned int of_key
Definition: lock_free.h:75
#define LF_BITMAP_FULL_USAGE_RATIO
static int lf_freelist_alloc_block(LF_FREELIST *freelist)
Definition: lock_free.c:611
static int lf_hash_insert_internal(LF_TRAN_ENTRY *tran, LF_HASH_TABLE *table, void *key, int bflags, void **entry, int *inserted)
Definition: lock_free.c:2047
LF_TRAN_SYSTEM obj_lock_res_Ts
Definition: lock_free.c:47