CUBRID Engine  latest
unittests_lf.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  * unittest_lf.c : unit tests for latch free primitives
21  */
22 
23 #include "porting.h"
24 #include "lock_free.h"
25 #include <stdio.h>
26 #include <pthread.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <assert.h>
30 
31 #define strlen(s1) ((int) strlen(s1))
32 
33 /* wait-free random number array */
34 #define RAND_BLOCKS 64
35 #define RAND_BLOCK_SIZE 1000000
36 #define RAND_SIZE RAND_BLOCKS * RAND_BLOCK_SIZE
38 
39 #define PTHREAD_ABORT_AND_EXIT(code) \
40  do \
41  { \
42  int rc = (code); \
43  abort (); \
44  pthread_exit (&rc); \
45  } \
46  while (0)
47 
48 static void
50 {
51  int i = 0;
52 
53  srand (time (NULL));
54 
55  for (i = 0; i < RAND_SIZE; i++)
56  {
57  random_numbers[i] = rand ();
58  }
59 }
60 
61 /* hash entry type definition */
62 typedef struct xentry XENTRY;
63 struct xentry
64 {
65  XENTRY *next; /* used by hash and freelist */
66  XENTRY *stack; /* used by freelist */
67  UINT64 del_tran_id; /* used by freelist */
68 
69  pthread_mutex_t mutex; /* entry mutex (where applicable) */
70 
71  int key;
72  unsigned long long int data;
73 };
74 
75 // *INDENT-OFF*
78 // *INDENT-ON*
79 
80 /* entry manipulation functions */
81 static void *
83 {
84  XENTRY *ptr = (XENTRY *) malloc (sizeof (XENTRY));
85  if (ptr != NULL)
86  {
87  pthread_mutex_init (&ptr->mutex, NULL);
88  ptr->data = 0;
89  }
90  return ptr;
91 }
92 
93 static int
94 xentry_free (void *entry)
95 {
96  pthread_mutex_destroy (&((XENTRY *) entry)->mutex);
97  free (entry);
98  return NO_ERROR;
99 }
100 
101 static int
102 xentry_init (void *entry)
103 {
104  if (entry != NULL)
105  {
106  ((XENTRY *) entry)->data = 0;
107  return NO_ERROR;
108  }
109  else
110  {
111  return ER_FAILED;
112  }
113 }
114 
115 static int
116 xentry_uninit (void *entry)
117 {
118  if (entry != NULL)
119  {
120  ((XENTRY *) entry)->data = -1;
121  return NO_ERROR;
122  }
123  else
124  {
125  return ER_FAILED;
126  }
127 
128 }
129 
130 static unsigned int
131 xentry_hash (void *key, int htsize)
132 {
133  int *ikey = (int *) key;
134  return (*ikey) % htsize;
135 }
136 
137 static int
138 xentry_key_compare (void *k1, void *k2)
139 {
140  int *ik1 = (int *) k1, *ik2 = (int *) k2;
141  return !(*ik1 == *ik2);
142 }
143 
144 static int
145 xentry_key_copy (void *src, void *dest)
146 {
147  int *isrc = (int *) src, *idest = (int *) dest;
148 
149  *idest = *isrc;
150 
151  return NO_ERROR;
152 }
153 
154 /* hash entry descriptors */
156  /* signature */
157  offsetof (XENTRY, stack),
158  offsetof (XENTRY, next),
159  offsetof (XENTRY, del_tran_id),
160  offsetof (XENTRY, key),
161  offsetof (XENTRY, mutex),
162 
163  /* mutex flags */
165 
166  /* functions */
167  xentry_alloc,
168  xentry_free,
169  xentry_init,
173  xentry_hash,
174  NULL
175 };
176 
177 /* print function */
178 static struct timeval start_time;
179 
180 static void
181 begin (const char *test_name)
182 {
183 #define MSG_LEN 40
184  int i;
185 
186  printf ("Testing %s", test_name);
187  for (i = 0; i < MSG_LEN - strlen (test_name); i++)
188  {
189  putchar (' ');
190  }
191  printf ("...");
192 
193  gettimeofday (&start_time, NULL);
194 
195 #undef MSG_LEN
196 }
197 
198 static int
199 fail (const char *message)
200 {
201  printf (" %s: %s\n", "FAILED", message);
202  abort ();
203  return ER_FAILED;
204 }
205 
206 static int
208 {
209  struct timeval end_time;
210  long long int elapsed_msec = 0;
211 
212  gettimeofday (&end_time, NULL);
213 
214  elapsed_msec = (end_time.tv_usec - start_time.tv_usec) / 1000;
215  elapsed_msec += (end_time.tv_sec - start_time.tv_sec) * 1000;
216 
217  printf (" %s [%9.3f sec]\n", "OK", (float) elapsed_msec / 1000.0f);
218  return NO_ERROR;
219 }
220 
221 /* thread entry functions */
222 void *test_freelist_proc (void *param);
223 
224 void *
225 test_freelist_proc (void *param)
226 {
227 #define NOPS 1000000 /* 1M */
228 
229  LF_FREELIST *freelist = (LF_FREELIST *) param;
230  LF_TRAN_SYSTEM *ts = freelist->tran_system;
231  LF_TRAN_ENTRY *te;
232  XENTRY *entry = NULL;
233  int i;
234 
235  te = lf_tran_request_entry (ts);
236  if (te == NULL)
237  {
239  }
240 
241  for (i = 0; i < NOPS; i++)
242  {
243  lf_tran_start_with_mb (te, true);
244 
245  if (i % 2 == 0)
246  {
247  entry = (XENTRY *) lf_freelist_claim (te, freelist);
248  if (entry == NULL)
249  {
251  }
252  }
253  else
254  {
255  if (lf_freelist_retire (te, freelist, (void *) entry) != NO_ERROR)
256  {
258  }
259  }
260 
261  lf_tran_end_with_mb (te);
262  }
263 
265 
266  pthread_exit (NO_ERROR);
267 
268 #undef NOPS
269 }
270 
271 void *test_freelist_proc_local_tran (void *param);
272 
273 void *
275 {
276 #define NOPS 1000000 /* 1M */
277 
278  LF_FREELIST *freelist = (LF_FREELIST *) param;
279  LF_TRAN_SYSTEM *ts = freelist->tran_system;
280  LF_TRAN_ENTRY *te;
281  XENTRY *entry = NULL;
282  int i;
283 
284  te = lf_tran_request_entry (ts);
285  if (te == NULL)
286  {
288  }
289 
290  for (i = 0; i < NOPS; i++)
291  {
292  /* Test freelist without transaction */
293  if (i % 2 == 0)
294  {
295  entry = (XENTRY *) lf_freelist_claim (te, freelist);
296  if (entry == NULL)
297  {
299  }
300  }
301  else
302  {
303  if (lf_freelist_retire (te, freelist, (void *) entry) != NO_ERROR)
304  {
306  }
307  }
308  }
309 
311 
312  pthread_exit (NO_ERROR);
313 
314 #undef NOPS
315 }
316 
317 void *test_hash_proc_1 (void *param);
318 
319 void *
320 test_hash_proc_1 (void *param)
321 {
322 #define NOPS 1000000
323 
324  my_hashmap *hashmap = (my_hashmap *) param;
325  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
326  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
327  LF_TRAN_ENTRY *te;
328  XENTRY *entry;
329  int i, rand_base, key;
330 
331  te = lf_tran_request_entry (ts);
332  if (te == NULL)
333  {
335  }
336 
337  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
338  {
340  }
341  else
342  {
343  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
344  }
345 
346  for (i = 0; i < NOPS; i++)
347  {
348  key = random_numbers[rand_base + i] % 1000;
349 
350  if (i % 10 < 5)
351  {
352  entry = NULL;
353  (void) hashmap->find_or_insert (te, key, entry);
354  hashmap->unlock (te, entry);
355  }
356  else
357  {
358  (void) hashmap->erase (te, key);
359  }
360  }
361 
363 
364  pthread_exit (NO_ERROR);
365 
366 #undef NOPS
367 }
368 
369 void *test_hash_proc_2 (void *param);
370 
371 void *
372 test_hash_proc_2 (void *param)
373 {
374 #define NOPS 1000000
375 
376  my_hashmap *hashmap = (my_hashmap *) param;
377  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
378  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
379  LF_TRAN_ENTRY *te;
380  XENTRY *entry;
381  int i, rand_base, key;
382 
383  te = lf_tran_request_entry (ts);
384  if (te == NULL)
385  {
387  }
388 
389  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
390  {
392  }
393  else
394  {
395  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
396  }
397 
398  for (i = 0; i < NOPS; i++)
399  {
400  key = random_numbers[rand_base + i] % 1000;
401 
402  if (i % 10 < 5)
403  {
404  (void) hashmap->find_or_insert (te, key, entry);
405  if (entry == NULL)
406  {
408  }
409 
410  if (te->locked_mutex != &entry->mutex)
411  {
412  abort ();
413  }
414  te->locked_mutex = NULL;
415  hashmap->unlock (te, entry);
416  }
417  else
418  {
419  (void) hashmap->erase (te, key);
420  }
421 
422  assert (te->locked_mutex == NULL);
423  }
424 
426 
427  pthread_exit (NO_ERROR);
428 
429 #undef NOPS
430 }
431 
432 static int del_op_count = -1;
433 
434 void *test_hash_proc_3 (void *param);
435 
436 void *
437 test_hash_proc_3 (void *param)
438 {
439 #define NOPS 1000000
440 
441  my_hashmap *hashmap = (my_hashmap *) param;
442  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
443  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
444  LF_TRAN_ENTRY *te;
445  XENTRY *entry;
446  int i, rand_base, key, local_del_op_count = 0;
447 
448  te = lf_tran_request_entry (ts);
449  if (te == NULL)
450  {
452  }
453 
454  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
455  {
457  }
458  else
459  {
460  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
461  }
462 
463  for (i = 0; i < NOPS; i++)
464  {
465  key = random_numbers[rand_base + i] % 1000;
466 
467  (void) hashmap->find_or_insert (te, key, entry);
468  if (entry == NULL)
469  {
471  }
472  if (entry->key != key)
473  {
475  }
476 
477  entry->data++;
478 
479  if (entry->data >= 10)
480  {
481  local_del_op_count += entry->data;
482  bool success = hashmap->erase_locked (te, key, entry);
483  if (!success)
484  {
486  }
487  }
488  else
489  {
490  if (te->locked_mutex != &entry->mutex)
491  {
492  abort ();
493  }
494  te->locked_mutex = NULL;
495  hashmap->unlock (te, entry);
496  }
497 
498  assert (te->locked_mutex == NULL);
499  }
500 
502 
503  ATOMIC_INC_32 (&del_op_count, local_del_op_count);
504  pthread_exit (NO_ERROR);
505 
506 #undef NOPS
507 }
508 
509 void *test_clear_proc_1 (void *param);
510 
511 void *
512 test_clear_proc_1 (void *param)
513 {
514 #define NOPS 1000000
515 
516  my_hashmap *hashmap = (my_hashmap *) param;
517  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
518  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
519  LF_TRAN_ENTRY *te;
520  XENTRY *entry;
521  int i, rand_base, key;
522 
523  te = lf_tran_request_entry (ts);
524  if (te == NULL)
525  {
527  }
528 
529  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
530  {
532  }
533  else
534  {
535  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
536  }
537 
538  for (i = 0; i < NOPS; i++)
539  {
540  key = random_numbers[rand_base + i] % 1000;
541  key = i % 100;
542 
543  if (i % 1000 != 999)
544  {
545  if (i % 10 < 8)
546  {
547  entry = NULL;
548  (void) hashmap->find_or_insert (te, key, entry);
549  hashmap->unlock (te, entry);
550  }
551  else if (i % 1000 < 999)
552  {
553  (void) hashmap->erase (te, key);
554  }
555  }
556  else
557  {
558  hashmap->clear (te);
559  }
560  }
561 
563 
564  pthread_exit (NO_ERROR);
565 
566 #undef NOPS
567 }
568 
569 void *test_clear_proc_2 (void *param);
570 
571 void *
572 test_clear_proc_2 (void *param)
573 {
574 #define NOPS 1000000
575 
576  my_hashmap *hashmap = (my_hashmap *) param;
577  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
578  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
579  LF_TRAN_ENTRY *te;
580  XENTRY *entry;
581  int i, rand_base, key;
582 
583  te = lf_tran_request_entry (ts);
584  if (te == NULL)
585  {
587  }
588 
589  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
590  {
592  }
593  else
594  {
595  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
596  }
597 
598  for (i = 0; i < NOPS; i++)
599  {
600  key = random_numbers[rand_base + i] % 1000;
601 
602  if (i % 1000 < 999)
603  {
604  if (i % 10 < 5)
605  {
606  (void) hashmap->find_or_insert (te, key, entry);
607  if (entry == NULL)
608  {
610  }
611 
612  if (te->locked_mutex != &entry->mutex)
613  {
614  abort ();
615  }
616  te->locked_mutex = NULL;
617  hashmap->unlock (te, entry);
618  }
619  else
620  {
621  (void) hashmap->erase (te, key);
622  }
623  }
624  else
625  {
626  hashmap->clear (te);
627  }
628  assert (te->locked_mutex == NULL);
629  }
630 
632 
633  pthread_exit (NO_ERROR);
634 
635 #undef NOPS
636 }
637 
638 void *test_clear_proc_3 (void *param);
639 
640 void *
641 test_clear_proc_3 (void *param)
642 {
643 #define NOPS 1000000
644 
645  my_hashmap *hashmap = (my_hashmap *) param;
646  LF_HASH_TABLE *hash = &hashmap->get_hash_table ();
647  LF_TRAN_SYSTEM *ts = hash->freelist->tran_system;
648  LF_TRAN_ENTRY *te;
649  XENTRY *entry;
650  int i, rand_base, key;
651 
652  te = lf_tran_request_entry (ts);
653  if (te == NULL)
654  {
656  }
657 
658  if (te->entry_idx >= RAND_BLOCKS || te->entry_idx < 0)
659  {
661  }
662  else
663  {
664  rand_base = te->entry_idx * RAND_BLOCK_SIZE;
665  }
666 
667  for (i = 0; i < NOPS; i++)
668  {
669  key = random_numbers[rand_base + i] % 1000;
670 
671  if (i % 1000 == 999)
672  {
673  hashmap->clear (te);
674  continue;
675  }
676 
677  (void) hashmap->find_or_insert (te, key, entry);
678  if (entry == NULL)
679  {
681  }
682 
683  entry->data++;
684 
685  if (entry->data >= 10)
686  {
687  bool success = hashmap->erase_locked (te, key, entry);
688  if (!success)
689  {
690  /* cleared in the meantime */
691  if (te->locked_mutex != &entry->mutex)
692  {
693  abort ();
694  }
695  te->locked_mutex = NULL;
696  hashmap->unlock (te, entry);
697  }
698  }
699  else
700  {
701  if (te->locked_mutex != &entry->mutex)
702  {
703  abort ();
704  }
705  te->locked_mutex = NULL;
706  hashmap->unlock (te, entry);
707  }
708 
709  assert (te->locked_mutex == NULL);
710  }
711 
713 
714  pthread_exit (NO_ERROR);
715 
716 #undef NOPS
717 }
718 
719 /* test functions */
720 static int
721 test_freelist (LF_ENTRY_DESCRIPTOR * edesc, int nthreads, bool test_local_tran)
722 {
723 #define MAX_THREADS 64
724 
725  static LF_FREELIST freelist;
726  static LF_TRAN_SYSTEM ts;
727  pthread_t threads[MAX_THREADS];
728  char msg[256];
729  int i;
730 
731  sprintf (msg, "freelist (transaction=%s, %d threads)", test_local_tran ? "n" : "y", nthreads);
732  begin (msg);
733 
734  /* initialization */
735  if (nthreads > MAX_THREADS)
736  {
737  return fail ("too many threads");
738  }
739 
740  if (lf_tran_system_init (&ts, nthreads) != NO_ERROR)
741  {
742  return fail ("transaction system init");
743  }
744 
745  if (lf_freelist_init (&freelist, 100, 100, edesc, &ts) != NO_ERROR)
746  {
747  return fail ("freelist init");
748  }
749 
750  /* multithreaded test */
751  for (i = 0; i < nthreads; i++)
752  {
753  if (pthread_create (&threads[i], NULL, (test_local_tran ? test_freelist_proc_local_tran : test_freelist_proc),
754  (void *) &freelist) != NO_ERROR)
755  {
756  return fail ("thread create");
757  }
758  }
759 
760  for (i = 0; i < nthreads; i++)
761  {
762  void *retval;
763 
764  pthread_join (threads[i], &retval);
765  if (retval != NO_ERROR)
766  {
767  return fail ("thread proc error");
768  }
769  }
770 
771  /* results */
772  {
773  volatile XENTRY *e, *a;
774  volatile int active, retired, _a, _r, _t;
775 
776  a = (XENTRY *) VOLATILE_ACCESS (freelist.available, void *);
777 
778  _a = VOLATILE_ACCESS (freelist.available_cnt, int);
779  _r = VOLATILE_ACCESS (freelist.retired_cnt, int);
780  _t = VOLATILE_ACCESS (freelist.alloc_cnt, int);
781 
782  active = 0;
783  retired = 0;
784  for (e = (XENTRY *) a; e != NULL; e = e->stack)
785  {
786  active++;
787  }
788  for (i = 0; i < ts.entry_count; i++)
789  {
790  for (e = (XENTRY *) ts.entries[i].retired_list; e != NULL; e = e->stack)
791  {
792  retired++;
793  }
794  }
795 
796  if ((_t - active - retired) != 0)
797  {
798  sprintf (msg, "leak problem (lost %d entries)", _t - active + retired);
799  return fail (msg);
800  }
801 
802  if ((active != _a) || (retired != _r))
803  {
804  sprintf (msg, "counting problem (%d != %d) or (%d != %d)", active, _a, retired, _r);
805  return fail (msg);
806  }
807  }
808 
809  /* uninit */
810  lf_freelist_destroy (&freelist);
812 
813  return success ();
814 
815 #undef MAX_THREADS
816 }
817 
818 static int
819 test_hash_table (LF_ENTRY_DESCRIPTOR * edesc, int nthreads, void *(*proc) (void *))
820 {
821 #define MAX_THREADS 1024
822 #define HASH_SIZE 113
823 
824  static LF_TRAN_SYSTEM ts;
825  static my_hashmap hashmap;
826  // *INDENT-OFF*
827  lf_hash_table &hash = hashmap.get_hash_table ();
828  lf_freelist &freelist = hashmap.get_freelist ();
829  // *INDENT-ON*
830  pthread_t threads[MAX_THREADS];
831  char msg[256];
832  int i;
833  XENTRY *e = NULL;
834 
835  sprintf (msg, "hash (mutex=%s, %d threads)", edesc->using_mutex ? "y" : "n", nthreads);
836  begin (msg);
837 
838  lf_reset_counters ();
839 
840  /* initialization */
841  if (nthreads > MAX_THREADS)
842  {
843  return fail ("too many threads");
844  }
845 
846  if (lf_tran_system_init (&ts, nthreads) != NO_ERROR)
847  {
848  return fail ("transaction system init");
849  }
850 
851  hashmap.init (ts, HASH_SIZE, 100, 100, *edesc);
852 
853  /* multithreaded test */
854  for (i = 0; i < nthreads; i++)
855  {
856  if (pthread_create (&threads[i], NULL, proc, (void *) &hashmap) != NO_ERROR)
857  {
858  return fail ("thread create");
859  }
860  }
861 
862  for (i = 0; i < nthreads; i++)
863  {
864  void *retval;
865 
866  pthread_join (threads[i], &retval);
867  if (retval != NO_ERROR)
868  {
869  return fail ("thread proc error");
870  }
871  }
872 
873  for (i = 0; i < HASH_SIZE; i++)
874  {
875  for (e = (XENTRY *) hash.buckets[i]; e != NULL; e = e->next)
876  {
877  if (edesc->f_hash (&e->key, HASH_SIZE) != (unsigned int) i)
878  {
879  sprintf (msg, "hash (%d) = %d != %d", e->key, edesc->f_hash (&e->key, HASH_SIZE), i);
880  return fail (msg);
881  }
882  }
883  }
884 
885  /* count operations */
886  if (edesc->using_mutex)
887  {
888  int nondel_op_count = 0;
889 
890  for (i = 0; i < HASH_SIZE; i++)
891  {
892  for (e = (XENTRY *) hash.buckets[i]; e != NULL; e = e->next)
893  {
894  nondel_op_count += e->data;
895  }
896  }
897 
898  if (del_op_count != -1)
899  {
900  /* we're counting delete ops */
901  if (nondel_op_count + del_op_count != nthreads * 1000000)
902  {
903  sprintf (msg, "op count fail (%d + %d != %d)", nondel_op_count, del_op_count, nthreads * 1000000);
904  return fail (msg);
905  }
906  }
907  }
908 
909  /* count entries */
910  {
911  XENTRY *e;
912  int ecount = 0, acount = 0, rcount = 0;
913 
914  for (i = 0; i < HASH_SIZE; i++)
915  {
916  for (e = (XENTRY *) hash.buckets[i]; e != NULL; e = e->next)
917  {
918  ecount++;
919  }
920  }
921 
922  for (e = (XENTRY *) freelist.available; e != NULL; e = e->stack)
923  {
924  acount++;
925  }
926  for (i = 0; i < ts.entry_count; i++)
927  {
928  for (e = (XENTRY *) ts.entries[i].retired_list; e != NULL; e = e->stack)
929  {
930  rcount++;
931  }
932  if (ts.entries[i].temp_entry != NULL)
933  {
934  ecount++;
935  }
936  }
937 
938  if (freelist.available_cnt != acount)
939  {
940  sprintf (msg, "counting fail (available %d != %d)", freelist.available_cnt, acount);
941  return fail (msg);
942  }
943  if (freelist.retired_cnt != rcount)
944  {
945  sprintf (msg, "counting fail (retired %d != %d)", freelist.retired_cnt, rcount);
946  return fail (msg);
947  }
948 
949  if (ecount + freelist.available_cnt + freelist.retired_cnt != freelist.alloc_cnt)
950  {
951  sprintf (msg, "leak check fail (%d + %d + %d = %d != %d)", ecount, freelist.available_cnt, freelist.retired_cnt,
952  ecount + freelist.available_cnt + freelist.retired_cnt, freelist.alloc_cnt);
953  return fail (msg);
954  }
955  }
956 
957  /* uninit */
958  hashmap.destroy ();
960 
961  return success ();
962 #undef HASH_SIZE
963 #undef MAX_THREADS
964 }
965 
966 static int
968 {
969 #define HASH_SIZE 200
970 #define HASH_POPULATION HASH_SIZE * 5
971 #define NUM_THREADS 16
972 
973  static LF_TRAN_SYSTEM ts;
974  static my_hashmap hashmap;
975  LF_HASH_TABLE hash = hashmap.get_hash_table ();
976  LF_FREELIST freelist = hashmap.get_freelist ();
977  static LF_TRAN_ENTRY *te;
978  int i;
979 
980  begin ("hash table iterator");
981 
982  /* initialization */
984  {
985  return fail ("transaction system init");
986  }
987 
988  te = lf_tran_request_entry (&ts);
989  if (te == NULL)
990  {
991  return fail ("failed to fetch tran entry");
992  }
993 
994  hashmap.init (ts, HASH_SIZE, 100, 100, xentry_desc);
995 
996  /* static (single threaded) test */
997  for (i = 0; i < HASH_POPULATION; i++)
998  {
999  XENTRY *entry;
1000 
1001  (void) hashmap.find_or_insert (te, i, entry);
1002  if (entry == NULL)
1003  {
1004  return fail ("null insert error");
1005  }
1006  else
1007  {
1008  entry->data = i;
1009  /* end transaction */
1010  hashmap.unlock (te, entry);
1011  }
1012  }
1013 
1014  {
1015  // *INDENT-OFF*
1016  my_hashmap_iterator it { te, hashmap};
1017  // *INDENT-ON*
1018  XENTRY *curr = NULL;
1019  char msg[256];
1020  int sum = 0;
1021 
1022  for (curr = it.iterate (); curr != NULL; curr = it.iterate ())
1023  {
1024  sum += curr->data;
1025  }
1026 
1027  if (sum != ((HASH_POPULATION - 1) * HASH_POPULATION) / 2)
1028  {
1029  sprintf (msg, "counting error (%d != %d)", sum, (HASH_POPULATION - 1) * HASH_POPULATION / 2);
1030  return fail (msg);
1031  }
1032  }
1033 
1034  /* reset */
1035  hashmap.clear (te);
1036 
1037  /* multi-threaded test */
1038  /* TODO TODO TODO */
1039 
1040  /* uninit */
1041  lf_tran_return_entry (te);
1042  hashmap.destroy ();
1043  lf_tran_system_destroy (&ts);
1044  return success ();
1045 #undef HASH_SIZE
1046 #undef HASH_POPULATION
1047 #undef NUM_THREADS
1048 }
1049 
1050 /* program entry */
1051 int
1052 main (int argc, char **argv)
1053 {
1054  int i;
1055  bool test_local_tran;
1056 
1057  /* generate random number array for non-blocking access */
1058  generate_random ();
1059 
1060  /* circular queue */
1061  /* temporarily disabled */
1062  /* for (i = 1; i <= 64; i *= 2) { if (test_circular_queue (i) != NO_ERROR) { goto fail; } } */
1063 
1064  /* freelist */
1065  test_local_tran = false;
1066  for (i = 1; i <= 64; i *= 2)
1067  {
1068  if (test_freelist (&xentry_desc, i, test_local_tran) != NO_ERROR)
1069  {
1070  goto fail;
1071  }
1072  }
1073 
1074  test_local_tran = true;
1075  for (i = 1; i <= 64; i *= 2)
1076  {
1077  if (test_freelist (&xentry_desc, i, test_local_tran) != NO_ERROR)
1078  {
1079  goto fail;
1080  }
1081  }
1082 
1083  /* test hash table iterator */
1084  if (test_hash_iterator () != NO_ERROR)
1085  {
1086  goto fail;
1087  }
1088 
1089  /* hash table - no entry mutex */
1090  for (i = 1; i <= 64; i *= 2)
1091  {
1092  if (test_hash_table (&xentry_desc, i, test_hash_proc_1) != NO_ERROR)
1093  {
1094  goto fail;
1095  }
1096  if (test_hash_table (&xentry_desc, i, test_clear_proc_1) != NO_ERROR)
1097  {
1098  goto fail;
1099  }
1100  }
1101 
1102  /* hash table - entry mutex, no lock between find and delete */
1103  xentry_desc.using_mutex = LF_EM_USING_MUTEX;
1104  for (i = 1; i <= 64; i *= 2)
1105  {
1106  if (test_hash_table (&xentry_desc, i, test_hash_proc_2) != NO_ERROR)
1107  {
1108  goto fail;
1109  }
1110  if (test_hash_table (&xentry_desc, i, test_clear_proc_2) != NO_ERROR)
1111  {
1112  goto fail;
1113  }
1114 
1115  }
1116 
1117  /* hash table - entry mutex, hold lock between find and delete */
1118  xentry_desc.using_mutex = LF_EM_USING_MUTEX;
1119  for (i = 1; i <= 64; i *= 2)
1120  {
1121  /* test_hash_proc_3 uses global del_op_count */
1122  del_op_count = 0;
1123  if (test_hash_table (&xentry_desc, i, test_hash_proc_3) != NO_ERROR)
1124  {
1125  goto fail;
1126  }
1127  del_op_count = -1;
1128  if (test_hash_table (&xentry_desc, i, test_clear_proc_3) != NO_ERROR)
1129  {
1130  goto fail;
1131  }
1132 
1133  }
1134 
1135  /* all ok */
1136  return 0;
1137 
1138 fail:
1139  printf ("Unit tests failed!\n");
1140  return ER_FAILED;
1141 }
#define RAND_SIZE
Definition: unittests_lf.c:36
XENTRY * stack
Definition: unittests_lf.c:66
#define NO_ERROR
Definition: error_code.h:46
#define LF_EM_NOT_USING_MUTEX
Definition: lock_free.h:59
static void generate_random()
Definition: unittests_lf.c:49
void * test_hash_proc_1(void *param)
Definition: unittests_lf.c:320
static int xentry_free(void *entry)
Definition: unittests_lf.c:94
static unsigned int xentry_hash(void *key, int htsize)
Definition: unittests_lf.c:131
void * temp_entry
Definition: lock_free.h:132
static int fail(const char *message)
Definition: unittests_lf.c:199
#define pthread_mutex_init(a, b)
Definition: area_alloc.c:48
LF_TRAN_ENTRY * lf_tran_request_entry(LF_TRAN_SYSTEM *sys)
Definition: lock_free.c:271
int argc
Definition: dynamic_load.c:951
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 unlock(lf_tran_entry *t_entry, T *&t)
Definition: lock_free.h:546
UINT64 del_tran_id
Definition: unittests_lf.c:67
void * test_hash_proc_2(void *param)
Definition: unittests_lf.c:372
Definition: lock_free.h:63
bool erase_locked(lf_tran_entry *t_entry, Key &key, T *&t)
Definition: lock_free.h:529
Definition: lock_free.h:120
void * retired_list
Definition: lock_free.h:129
lf_hash_table & get_hash_table()
Definition: lock_free.h:622
void lf_tran_system_destroy(LF_TRAN_SYSTEM *sys)
Definition: lock_free.c:240
lf_freelist & get_freelist()
Definition: lock_free.h:629
#define lf_tran_end_with_mb(entry)
Definition: lock_free.h:198
#define HASH_POPULATION
void * lf_freelist_claim(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist)
Definition: lock_free.c:751
static int random_numbers[RAND_SIZE]
Definition: unittests_lf.c:37
int main(int argc, char **argv)
void * test_clear_proc_2(void *param)
Definition: unittests_lf.c:572
#define NOPS
#define HASH_SIZE
#define lf_tran_start_with_mb(entry, incr)
Definition: lock_free.h:197
void init(lf_tran_system &transys, int hash_size, int freelist_block_count, int freelist_block_size, lf_entry_descriptor &edes)
#define MSG_LEN
void * test_freelist_proc(void *param)
Definition: unittests_lf.c:225
#define MAX_THREADS
int lf_tran_system_init(LF_TRAN_SYSTEM *sys, int max_threads)
Definition: lock_free.c:184
void * test_clear_proc_3(void *param)
Definition: unittests_lf.c:641
static int xentry_key_compare(void *k1, void *k2)
Definition: unittests_lf.c:138
void * test_hash_proc_3(void *param)
Definition: unittests_lf.c:437
#define assert(x)
static int xentry_init(void *entry)
Definition: unittests_lf.c:102
void lf_tran_return_entry(LF_TRAN_ENTRY *entry)
Definition: lock_free.c:310
LF_TRAN_SYSTEM * tran_system
Definition: lock_free.h:245
#define RAND_BLOCKS
Definition: unittests_lf.c:34
int lf_freelist_retire(LF_TRAN_ENTRY *tran_entry, LF_FREELIST *freelist, void *entry)
Definition: lock_free.c:864
void ** buckets
Definition: lock_free.h:299
void * test_freelist_proc_local_tran(void *param)
Definition: unittests_lf.c:274
#define strlen(s1)
Definition: unittests_lf.c:31
static int del_op_count
Definition: unittests_lf.c:432
#define NULL
Definition: freelistheap.h:34
static struct timeval start_time
Definition: unittests_lf.c:178
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
static int success()
Definition: unittests_lf.c:207
int using_mutex
Definition: lock_free.h:81
pthread_mutex_t mutex
Definition: unittests_lf.c:69
LF_ENTRY_HASH_FUNC f_hash
Definition: lock_free.h:102
static int xentry_uninit(void *entry)
Definition: unittests_lf.c:116
void * test_clear_proc_1(void *param)
Definition: unittests_lf.c:512
void clear(lf_tran_entry *t_entry)
Definition: lock_free.h:562
static LF_ENTRY_DESCRIPTOR xentry_desc
Definition: unittests_lf.c:155
#define NUM_THREADS
#define PTHREAD_ABORT_AND_EXIT(code)
Definition: unittests_lf.c:39
bool find_or_insert(lf_tran_entry *t_entry, Key &key, T *&t)
Definition: lock_free.h:496
const char ** argv
Definition: dynamic_load.c:952
LF_FREELIST * freelist
Definition: lock_free.h:311
static int test_hash_table(LF_ENTRY_DESCRIPTOR *edesc, int nthreads, void *(*proc)(void *))
Definition: unittests_lf.c:819
#define RAND_BLOCK_SIZE
Definition: unittests_lf.c:35
void lf_freelist_destroy(LF_FREELIST *freelist)
Definition: lock_free.c:711
int entry_idx
Definition: lock_free.h:138
int i
Definition: dynamic_load.c:954
static int xentry_key_copy(void *src, void *dest)
Definition: unittests_lf.c:145
XENTRY * next
Definition: unittests_lf.c:65
bool erase(lf_tran_entry *t_entry, Key &key)
Definition: lock_free.h:517
LF_TRAN_ENTRY * entries
Definition: lock_free.h:155
#define VOLATILE_ACCESS(v, t)
Definition: area_alloc.c:85
int key
Definition: unittests_lf.c:71
static void begin(const char *test_name)
Definition: unittests_lf.c:181
static int test_freelist(LF_ENTRY_DESCRIPTOR *edesc, int nthreads, bool test_local_tran)
Definition: unittests_lf.c:721
#define LF_EM_USING_MUTEX
Definition: lock_free.h:60
void * available
Definition: lock_free.h:231
static void * xentry_alloc()
Definition: unittests_lf.c:82
unsigned long long int data
Definition: unittests_lf.c:72
#define pthread_mutex_destroy(a)
Definition: area_alloc.c:49
static int test_hash_iterator()
Definition: unittests_lf.c:967