CUBRID Engine  latest
unittests_snapshot.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  * unittests_snapshot.c : unit tests for snapshot
21  */
22 
23 #include "porting.h"
24 
25 #include "thread_manager.hpp"
26 
27 #include <stdio.h>
28 #include <pthread.h>
29 #include <log_impl.h>
30 #include <sys/time.h>
31 
32 #define strlen(s1) ((int) strlen(s1))
33 
34 #define NOPS_SNAPSHOT 1000000
35 #define NOPS_COMPLPETE 1000000
36 #define NOPS_OLDEST 2000000
37 
38 /* bit area sizes expressed in bits */
39 #define MVCC_BITAREA_ELEMENT_BITS 64
40 #define MVCC_BITAREA_ELEMENT_ALL_COMMITTED 0xffffffffffffffffULL
41 #define MVCC_BITAREA_BIT_COMMITTED 1
42 #define MVCC_BITAREA_BIT_ACTIVE 0
43 
44 /* bit area size after cleanup */
45 #define MVCC_BITAREA_ELEMENTS_AFTER_FULL_CLEANUP 16
46 
47 /* maximum size - 500 UINT64 */
48 #define MVCC_BITAREA_MAXIMUM_ELEMENTS 500
49 
50 /* maximum size - 32000 bits */
51 #define MVCC_BITAREA_MAXIMUM_BITS 32000
52 
53 #define MVCC_BITAREA_BITS_TO_ELEMENTS(count_bits) (((count_bits) + 63) >> 6)
54 #define MVCC_BITAREA_BITS_TO_BYTES(count_bits) ((((count_bits) + 63) >> 6) << 3)
55 #define MVCC_BITAREA_ELEMENTS_TO_BYTES(count_elements) ((count_elements) << 3)
56 #define MVCC_BITAREA_ELEMENTS_TO_BITS(count_elements) ((count_elements) << 6)
57 
58 /* print function */
59 static struct timeval start_time;
60 
61 static void
62 begin (char *test_name)
63 {
64 #define MSG_LEN 40
65  int i;
66 
67  printf ("Testing %s", test_name);
68  for (i = 0; i < MSG_LEN - strlen (test_name); i++)
69  {
70  putchar (' ');
71  }
72  printf ("...\n");
73 
74  gettimeofday (&start_time, NULL);
75 
76 #undef MSG_LEN
77 }
78 
79 static int
81 {
82  struct timeval end_time;
83  long long int elapsed_msec = 0;
84 
85  gettimeofday (&end_time, NULL);
86 
87  elapsed_msec = (end_time.tv_usec - start_time.tv_usec) / 1000;
88  elapsed_msec += (end_time.tv_sec - start_time.tv_sec) * 1000;
89 
90  printf (" %s [%9.3f sec]\n", "OK", (float) elapsed_msec / 1000.0f);
91  return NO_ERROR;
92 }
93 
94 static void
96 {
98 }
99 
100 
101 static void
103 {
105 }
106 
107 static unsigned int
108 logtb_tran_btid_hash_func (const void *key, const unsigned int ht_size)
109 {
110  return 0;
111 }
112 
113 static int
114 logtb_tran_btid_hash_cmp_func (const void *key1, const void *key2)
115 {
116  return 0;
117 }
118 
119 
120 static void
122 {
123  memset (tdes, 0, sizeof (LOG_TDES));
124  tdes->tran_index = tran_index;
125  tdes->trid = NULL_TRANID;
126 
127  tdes->mvccinfo.init ();
128 
131 }
132 
133 
134 static int
135 logtb_initialize_mvcc_testing (int num_threads, THREAD_ENTRY ** thread_array)
136 {
137  LOG_ADDR_TDESAREA *area = NULL; /* Contiguous area for new transaction indices */
138  size_t size, area_size;
139  int i;
140  THREAD_ENTRY *thread_p;
141  int error_code = NO_ERROR;
142  LOG_TDES *tdes;
143 
144  if (num_threads == 0 || thread_array == NULL)
145  {
146  return ER_FAILED;
147  }
148 
151 
152  size = num_threads * sizeof (THREAD_ENTRY);
153  *thread_array = (THREAD_ENTRY *) malloc (size);
154  if (*thread_array == NULL)
155  {
156  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
157  goto error;
158  }
159  memset (*thread_array, 0, size);
160  for (i = 0; i < num_threads; i++)
161  {
162  thread_p = *thread_array + i;
163  thread_p->type = TT_WORKER; /* init */
164  thread_p->index = i;
165  thread_p->tran_index = i + 1; /* quick fix to avoid issue in logtb_get_mvcc_snapshot - LOG_SYSTEM_TRAN_INDEX */
166  }
167 
168  size = num_threads * sizeof (*log_Gl.trantable.all_tdes);
169  log_Gl.trantable.all_tdes = (LOG_TDES **) malloc (size);
170  if (log_Gl.trantable.all_tdes == NULL)
171  {
172  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
173  goto error;
174  }
175 
176  area_size = num_threads * sizeof (LOG_TDES) + sizeof (LOG_ADDR_TDESAREA);
177  area = (LOG_ADDR_TDESAREA *) malloc (area_size);
178  if (area == NULL)
179  {
180  error_code = ER_OUT_OF_VIRTUAL_MEMORY;
181  goto error;
182  }
183 
184  area->tdesarea = ((LOG_TDES *) ((char *) area + sizeof (LOG_ADDR_TDESAREA)));
185  area->next = NULL;
186 
187  /*
188  * Initialize every newly created transaction descriptor index
189  */
190  for (i = 0; i < num_threads; i++)
191  {
192  tdes = log_Gl.trantable.all_tdes[i] = &area->tdesarea[i];
194  }
195 
196  log_Gl.trantable.area = area;
197  log_Gl.trantable.num_total_indices = num_threads;
198 
201 
202  return NO_ERROR;
203 
204 error:
205  if (*thread_array)
206  {
207  free_and_init (*thread_array);
208  }
209 
211  {
213  }
214 
215  if (log_Gl.trantable.area)
216  {
218  }
219 
220  return error_code;
221 }
222 
223 static void
225 {
226  LOG_TDES *tdes;
227  MVCC_INFO *curr_mvcc_info;
228  int i;
229 
231 
232  for (i = 0; i < log_Gl.trantable.num_total_indices; i++)
233  {
234  tdes = log_Gl.trantable.all_tdes[i];
235  curr_mvcc_info = &tdes->mvccinfo;
236 
237  curr_mvcc_info->snapshot.m_active_mvccs.finalize ();
238 
239  if (tdes->log_upd_stats.unique_stats_hash != NULL)
240  {
243  }
244  }
245 
246  if (thread_array && *thread_array)
247  {
248  free_and_init (*thread_array);
249  }
250 
252  {
254  }
255 
256  if (log_Gl.trantable.area)
257  {
259  }
260 }
261 
262 static UINT64 count_snapshots = 0;
263 static UINT64 count_complete = 0;
264 static UINT64 count_oldest = 0;
265 
268 {
269  int i;
270  THREAD_ENTRY *thread_p = (THREAD_ENTRY *) param;
271  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
272  LOG_TDES *tdes = LOG_FIND_TDES (tran_index);
273  unsigned int local_count_snapshots = 0;
274  MVCC_INFO *curr_mvcc_info = &tdes->mvccinfo;
275 
276  // *INDENT-OFF*
278  // *INDENT-ON*
279 
280  for (i = 0; i < NOPS_SNAPSHOT; i++)
281  {
282  if (logtb_get_mvcc_snapshot (thread_p) != NULL)
283  {
284  local_count_snapshots++;
285  }
286 
287  /* Invalidate snapshot */
289  curr_mvcc_info->reset ();
290  }
291 
292  ATOMIC_INC_64 (&count_snapshots, local_count_snapshots);
293  fprintf (stdout, "snapshot worker thread (%p) is leaving\n", thread_p);
294  fflush (stdout);
295 
296  // *INDENT-OFF*
298  // *INDENT-ON*
299 
300  return (THREAD_RET_T) 0;
301 }
302 
305 {
306  int i;
307  THREAD_ENTRY *thread_p = (THREAD_ENTRY *) param;
308  int tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
309  LOG_TDES *tdes = LOG_FIND_TDES (tran_index);
310  unsigned int local_count_complete = 0;
311  bool committed = true;
312  MVCCID mvccid;
313 
314  // *INDENT-OFF*
316  // *INDENT-ON*
317 
318  for (i = 0; i < NOPS_COMPLPETE; i++)
319  {
320  mvccid = logtb_get_current_mvccid (thread_p);
321  if (mvccid == MVCCID_NULL)
322  {
323  abort ();
324  }
325 
326  logtb_complete_mvcc (thread_p, tdes, committed);
327  committed = !committed;
328 
329  /* here we may test whether bit was set */
330  local_count_complete++;
331 
333  }
334 
335  ATOMIC_INC_64 (&count_complete, local_count_complete);
336  fprintf (stdout, "complete worker thread (%p) is leaving\n", thread_p);
337  fflush (stdout);
338 
339  // *INDENT-OFF*
341  // *INDENT-ON*
342 
343  return (THREAD_RET_T) 0;
344 }
345 
347 test_mvcc_get_oldest (void *param)
348 {
349  int i;
350  THREAD_ENTRY *thread_p = (THREAD_ENTRY *) param;
351  unsigned int local_count_oldest = 0;
352  MVCCID prev_oldest, curr_oldest = MVCCID_NULL;
353 
354  // *INDENT-OFF*
356  // *INDENT-ON*
357 
358  for (i = 0; i < NOPS_OLDEST; i++)
359  {
360  prev_oldest = curr_oldest;
362  if (MVCC_ID_PRECEDES (curr_oldest, prev_oldest))
363  {
364  abort ();
365  continue;
366  }
367 
368  local_count_oldest++;
369  }
370 
371  ATOMIC_INC_64 (&count_oldest, local_count_oldest);
372 
373  fprintf (stdout, "get_oldest thread (%p) is leaving\n", thread_p);
374  fflush (stdout);
375 
376  // *INDENT-OFF*
378  // *INDENT-ON*
379 
380  return (THREAD_RET_T) 0;
381 }
382 
383 static int
384 test_mvcc_operations (int num_snapshot_threads, int num_complete_threads, int num_oldest_mvccid_threads,
385  THREAD_ENTRY * thread_array)
386 {
387  int i;
388  int numthreads;
389 #define MAX_THREADS 100
390  pthread_t threads[MAX_THREADS];
391  int idx_thread_entry;
392  char msg[256];
393 
394  numthreads = num_snapshot_threads + num_complete_threads + num_oldest_mvccid_threads;
395  sprintf (msg, "test_mvcc_operations (%d snapshot threads, %d complete threads, %d oldest threads)",
396  num_snapshot_threads, num_complete_threads, num_oldest_mvccid_threads);
397  begin (msg);
398 
399  if (num_snapshot_threads < 0 || num_complete_threads < 0 || num_oldest_mvccid_threads < 0)
400  {
401  printf (" %s: %s\n", "FAILED", "negative number of threads not allowed");
402  return ER_FAILED;
403  }
404 
405  if (numthreads > MAX_THREADS)
406  {
407  printf (" %s: %s\n", "FAILED", "too many threads");
408  return ER_FAILED;
409  }
410 
412  idx_thread_entry = 0;
413  for (i = 0; i < num_snapshot_threads; i++, idx_thread_entry++)
414  {
415  if (pthread_create (&threads[idx_thread_entry], NULL, test_mvcc_get_snapshot,
416  (void *) (thread_array + idx_thread_entry)) != NO_ERROR)
417  {
418  printf (" %s: %s\n", "FAILED", "thread create error");
419  return ER_FAILED;
420  }
421  }
422 
423  for (i = 0; i < num_complete_threads; i++, idx_thread_entry++)
424  {
425  if (pthread_create (&threads[idx_thread_entry], NULL, test_new_mvcc_complete,
426  (void *) (thread_array + idx_thread_entry)) != NO_ERROR)
427  {
428  printf (" %s: %s\n", "FAILED", "thread create error");
429  return ER_FAILED;
430  }
431  }
432 
433  for (i = 0; i < num_oldest_mvccid_threads; i++, idx_thread_entry++)
434  {
435  if (pthread_create (&threads[idx_thread_entry], NULL, test_mvcc_get_oldest,
436  (void *) (thread_array + idx_thread_entry)) != NO_ERROR)
437  {
438  printf (" %s: %s\n", "FAILED", "thread create error");
439  return ER_FAILED;
440  }
441  }
442 
443  for (i = 0; i < numthreads; i++)
444  {
445  void *retval;
446 
447  pthread_join (threads[i], &retval);
448  if (retval != NO_ERROR)
449  {
450  printf (" %s: %s\n", "FAILED", "thread proc error");
451  return ER_FAILED;
452  }
453  }
454 
455  if (count_snapshots != (UINT64) num_snapshot_threads * NOPS_SNAPSHOT)
456  {
457  printf ("snapshot count fail (%llu != %llu)",
458  (unsigned long long) count_snapshots, (unsigned long long) num_snapshot_threads * NOPS_SNAPSHOT);
459  return ER_FAILED;
460  }
461 
462  if (count_complete != (UINT64) num_complete_threads * NOPS_COMPLPETE)
463  {
464  printf ("complete count fail (%llu != %llu)",
465  (unsigned long long) count_complete, (unsigned long long) num_complete_threads * NOPS_COMPLPETE);
466  return ER_FAILED;
467  }
468 
469  if (count_oldest != (UINT64) num_oldest_mvccid_threads * NOPS_OLDEST)
470  {
471  printf ("oldest count fail (%llu != %llu)",
472  (unsigned long long) count_oldest, (unsigned long long) num_oldest_mvccid_threads * NOPS_OLDEST);
473  return ER_FAILED;
474  }
475 
476  success ();
477 
478  return NO_ERROR;
479 }
480 
481 /* program entry */
482 int
483 main (int argc, char **argv)
484 {
485 #define MAX_SNAPSHOT_THREADS 10
486 #define MAX_COMPLETE_THREADS 10
487 #define MAX_OLDEST_THREADS 1
488 
489  int num_snapshot_threads, num_complete_threads, num_oldest_threads;
490  THREAD_ENTRY *thread_array = NULL;
491 
492  logtb_initialize_mvcc_testing (100, &thread_array);
493 
494  for (num_oldest_threads = 1; num_oldest_threads <= MAX_OLDEST_THREADS; num_oldest_threads++)
495  {
496  for (num_complete_threads = 1; num_complete_threads <= MAX_COMPLETE_THREADS; num_complete_threads++)
497  {
498  for (num_snapshot_threads = 1; num_snapshot_threads <= MAX_SNAPSHOT_THREADS; num_snapshot_threads++)
499  {
500  if (test_mvcc_operations (num_snapshot_threads, num_complete_threads, num_oldest_threads,
501  thread_array) != NO_ERROR)
502  {
503  goto fail;
504  }
505  }
506  }
507  }
508 
509  logtb_finalize_mvcc_testing (&thread_array);
510  return 0;
511 
512 fail:
513  logtb_finalize_mvcc_testing (&thread_array);
514  printf ("Unit tests failed!\n");
515  return ER_FAILED;
516 
517 #undef MAX_SNAPSHOT_THREADS
518 #undef MAX_COMPLETE_THREADS
519 #undef MAX_OLDEST_THREADS
520 }
static unsigned int logtb_tran_btid_hash_func(const void *key, const unsigned int ht_size)
#define MAX_COMPLETE_THREADS
THREAD_RET_T THREAD_CALLING_CONVENTION test_mvcc_get_snapshot(void *param)
#define NOPS_SNAPSHOT
int tran_index
Definition: log_impl.h:465
#define NO_ERROR
Definition: error_code.h:46
#define MAX_OLDEST_THREADS
LOG_TDES * tdesarea
Definition: log_impl.h:573
MVCC_SNAPSHOT * logtb_get_mvcc_snapshot(THREAD_ENTRY *thread_p)
void logtb_complete_mvcc(THREAD_ENTRY *thread_p, LOG_TDES *tdes, bool committed)
MHT_TABLE * unique_stats_hash
Definition: log_impl.h:439
void finalize()
Definition: mvcc_table.cpp:211
TRANTABLE trantable
Definition: log_impl.h:650
int num_total_indices
Definition: log_impl.h:581
static void logtb_initialize_mvcctable(void)
THREAD_RET_T THREAD_CALLING_CONVENTION test_mvcc_get_oldest(void *param)
#define MVCCID_FIRST
LOG_TRAN_UPDATE_STATS log_upd_stats
Definition: log_impl.h:534
int argc
Definition: dynamic_load.c:951
#define MAX_THREADS
struct log_addr_tdesarea LOG_ADDR_TDESAREA
Definition: log_impl.h:570
#define ER_FAILED
Definition: error_code.h:47
static void logtb_finalize_mvcctable()
LOG_GLOBAL log_Gl
LOG_HEADER hdr
Definition: log_impl.h:653
#define NULL_TRANID
#define NOPS_COMPLPETE
void clear_thread_local_entry(void)
#define MVCCID_NULL
void set_thread_local_entry(entry &tl_entry)
static int success()
LOG_ADDR_TDESAREA * next
Definition: log_impl.h:574
static int fail(const char *message)
LOG_TDES * LOG_FIND_TDES(int tran_index)
Definition: log_impl.h:1095
static int test_mvcc_operations(int num_snapshot_threads, int num_complete_threads, int num_oldest_mvccid_threads, THREAD_ENTRY *thread_array)
static UINT64 count_complete
void THREAD_ENTRY
mvcctable mvcc_table
Definition: log_impl.h:684
LOG_TDES ** all_tdes
Definition: log_impl.h:595
void mht_destroy(MHT_TABLE *ht)
Definition: memory_hash.c:1140
#define THREAD_RET_T
Definition: porting.h:713
static int logtb_initialize_mvcc_testing(int num_threads, THREAD_ENTRY **thread_array)
#define MSG_LEN
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static void logtb_initialize_tdes_for_mvcc_testing(LOG_TDES *tdes, int tran_index)
void reset()
Definition: mvcc.c:691
MVCC_INFO mvccinfo
Definition: log_impl.h:463
mvcc_active_tran m_active_mvccs
Definition: mvcc.h:174
#define NULL
Definition: freelistheap.h:34
UINT64 MVCCID
void initialize()
Definition: mvcc_table.cpp:183
MHT_TABLE * mht_create(const char *name, int est_size, unsigned int(*hash_func)(const void *key, unsigned int ht_size), int(*cmp_func)(const void *key1, const void *key2))
Definition: memory_hash.c:894
#define MVCC_ID_PRECEDES(id1, id2)
Definition: mvcc.h:137
void init()
Definition: mvcc.c:685
#define MAX_SNAPSHOT_THREADS
MVCCID logtb_get_current_mvccid(THREAD_ENTRY *thread_p)
static void error(const char *msg)
Definition: gencat.c:331
static struct timeval start_time
MVCCID get_global_oldest_visible() const
Definition: mvcc_table.cpp:612
static void logtb_finalize_mvcc_testing(THREAD_ENTRY **thread_array)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd)
Definition: perf_monitor.h:158
#define NOPS_OLDEST
LOG_ADDR_TDESAREA * area
Definition: log_impl.h:594
static void begin(char *test_name)
const char ** argv
Definition: dynamic_load.c:952
struct log_tdes LOG_TDES
Definition: log_impl.h:459
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
TRANID trid
Definition: log_impl.h:466
MVCC_SNAPSHOT snapshot
Definition: mvcc.h:194
THREAD_RET_T THREAD_CALLING_CONVENTION test_new_mvcc_complete(void *param)
static UINT64 count_oldest
static int logtb_tran_btid_hash_cmp_func(const void *key1, const void *key2)
void reset_transaction_lowest_active(int tran_index)
Definition: mvcc_table.cpp:594
int i
Definition: dynamic_load.c:954
MVCCID mvcc_next_id
static UINT64 count_snapshots
#define THREAD_CALLING_CONVENTION
Definition: porting.h:714
int main(int argc, char **argv)