CUBRID Engine  latest
mvcc_table.cpp
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 // MVCC table - transaction information required for multi-version concurrency control system
21 //
22 
23 #include "mvcc_table.hpp"
24 
25 #include "extensible_array.hpp"
26 #include "log_impl.h"
27 #include "mvcc.h"
28 #include "perf_monitor.h"
29 #include "thread_manager.hpp"
30 
31 #include <cassert>
32 
33 // help debugging oldest active by following all changes
35 {
36  enum op_type
37  {
38  SET,
39  GET,
41  };
42 
43  enum source
44  {
50  };
51 
53  int m_tran_index_or_global; // 0 for global, non-zero for active transactions
54  op_type m_set_or_get; // self-explanatory
56  // todo - add thread index?
57 
59  {
60  m_value = other.m_value;
61  m_tran_index_or_global = other.m_tran_index_or_global;
62  m_set_or_get = other.m_set_or_get;
63  m_source = other.m_source;
64 
65  return *this;
66  }
67 };
68 #if !defined (NDEBUG)
69 const size_t OLDEST_ACTIVE_HISTORY_SIZE = 1024 * 8; // 8k
71 {
72  std::atomic<size_t> m_event_count;
74 };
76 
77 static inline void
78 oldest_active_add_event (MVCCID mvccid, int tran_index, oldest_active_event::op_type set_or_get,
80 {
81  size_t index = Oldest_active_tracker.m_event_count++ % OLDEST_ACTIVE_HISTORY_SIZE;
82  Oldest_active_tracker.m_history[index] = { mvccid, tran_index, set_or_get, src };
83 }
84 
85 // NOTE - while investigating history, please consider that not all Oldest_active_event_count events may be mature.
86 // investigate concurrent threads that may still be working on populating their event
87 #endif // debug
88 
89 static inline void
92 {
93 #if !defined (NDEBUG)
94  oldest_active_add_event (mvccid, tran_index, oldest_active_event::SET, src);
95 #endif
96  lowest.store (mvccid);
97 }
98 
99 static inline MVCCID
102 {
103  MVCCID mvccid = lowest.load ();
104 #if !defined (NDEBUG)
105  if (mvccid != MVCCID_NULL)
106  {
107  // don't spam will null reads
108  oldest_active_add_event (mvccid, tran_index, oldest_active_event::GET, src);
109  }
110 #endif
111  return mvccid;
112 }
113 
115  : m_active_mvccs ()
116  , m_last_completed_mvccid (MVCCID_NULL)
117  , m_event_type (COMMIT)
118  , m_version (0)
119 {
120 }
121 
123 {
124 }
125 
126 void
128 {
130  m_version = 0;
131 }
132 
133 void
135 {
137 }
138 
139 void
141 {
142  MVCCID crt_oldest_active;
143  do
144  {
145  crt_oldest_active = m_current_status_lowest_active_mvccid.load ();
146  if (crt_oldest_active >= next_oldest_active)
147  {
148  // already advanced to equal or better
149  return;
150  }
151  }
152  while (!m_current_status_lowest_active_mvccid.compare_exchange_strong (crt_oldest_active, next_oldest_active));
153 #if !defined (NDEBUG)
155 #endif // debug
156 }
157 
158 //
159 // MVCC table
160 //
161 
163  : m_transaction_lowest_visible_mvccids (NULL)
164  , m_transaction_lowest_visible_mvccids_size (0)
165  , m_current_status_lowest_active_mvccid (MVCCID_FIRST)
166  , m_current_trans_status ()
167  , m_trans_status_history_position (0)
168  , m_trans_status_history (NULL)
169  , m_new_mvccid_lock ()
170  , m_active_trans_mutex ()
171  , m_oldest_visible (MVCCID_NULL)
172  , m_ov_lock_count (0)
173 {
174 }
175 
177 {
179  delete [] m_trans_status_history;
180 }
181 
182 void
184 {
187  for (size_t idx = 0; idx < HISTORY_MAX_SIZE; idx++)
188  {
190  }
193 
195 }
196 
197 void
199 {
201  {
202  // either first time or transaction table size has changed
206  // all are 0 = MVCCID_NULL
207  }
208 }
209 
210 void
212 {
214 
215  delete [] m_trans_status_history;
217 
221 }
222 
223 void
225 {
226  MVCCID tx_lowest_active;
227  MVCCID crt_status_lowest_active;
228  size_t index;
229  mvcc_trans_status::version_type trans_status_version;
230 
231  MVCCID highest_completed_mvccid;
232 
233  bool is_perf_tracking = perfmon_is_perf_tracking ();
234  TSC_TICKS start_tick, end_tick;
235  TSCTIMEVAL tv_diff;
236  UINT64 snapshot_wait_time;
237  UINT64 snapshot_retry_count = 0;
238 
240 
241  if (is_perf_tracking)
242  {
243  tsc_getticks (&start_tick);
244  }
245 
246  // make sure snapshot has allocated data
248 
251 
252  // repeat steps until a trans_status can be read successfully without a version change
253  while (true)
254  {
255  snapshot_retry_count++;
256 
257  if (!MVCCID_IS_VALID (tx_lowest_active))
258  {
259  /*
260  * First, by setting MVCCID_ALL_VISIBLE we will tell to VACUUM that transaction lowest MVCCID will be set
261  * soon.
262  * This is needed since setting p_transaction_lowest_active_mvccid is not an atomic operation (global
263  * lowest_active_mvccid must be obtained first). We want to avoid a possible scenario (even if the chances
264  * are minimal) like the following one:
265  * - the snapshot thread reads the initial value of global lowest active MVCCID but the thread is
266  * suspended (due to thread switching) just before setting p_transaction_lowest_active_mvccid
267  * - the transaction having global lowest active MVCCID commits, so the global value is updated (advanced)
268  * - the VACCUM thread computes the MVCCID threshold as the updated global lowest active MVCCID
269  * - the snapshot thread resumes and p_transaction_lowest_active_mvccid is set to initial value of global
270  * lowest active MVCCID
271  * - the VACUUM thread computes the threshold again and found a value (initial global lowest active MVCCID)
272  * less than the previously threshold
273  */
276 
277  /*
278  * Is important that between next two code lines to not have delays (to not execute any other code).
279  * Otherwise, VACUUM may delay, waiting more in logtb_get_oldest_active_mvccid.
280  */
281  crt_status_lowest_active = oldest_active_get (m_current_status_lowest_active_mvccid, 0,
284  crt_status_lowest_active, oldest_active_event::BUILD_MVCC_INFO);
285  }
286  else
287  {
288  crt_status_lowest_active = oldest_active_get (m_current_status_lowest_active_mvccid, 0,
290  }
291 
292  index = m_trans_status_history_position.load ();
293  assert (index < HISTORY_MAX_SIZE);
294 
295  const mvcc_trans_status &trans_status = m_trans_status_history[index];
296 
297  trans_status_version = trans_status.m_version.load ();
300  /* load statistics temporary disabled need to be enabled when activate count optimization */
301 #if 0
302  /* load global statistics. This must take place here and nowhere else. */
304  {
306  error_code = ER_MVCC_CANT_GET_SNAPSHOT;
307  }
308 #endif
309 
310  if (trans_status_version == trans_status.m_version.load ())
311  {
312  // no version change; copying status was successful
313  break;
314  }
315  else
316  {
317  // a failed copy may break data validity; to make sure next copy is not affected, it is better to reset
318  // bit area.
320  }
321  }
322 
323  // tdes.mvccinfo.snapshot.m_active_mvccs was not checked because it was not safe; now it is
325 
326  highest_completed_mvccid = tdes.mvccinfo.snapshot.m_active_mvccs.compute_highest_completed_mvccid ();
327  MVCCID_FORWARD (highest_completed_mvccid);
328 
329  /* update lowest active mvccid computed for the most recent snapshot */
330  tdes.mvccinfo.recent_snapshot_lowest_active_mvccid = crt_status_lowest_active;
331 
332  /* update remaining snapshot data */
334  tdes.mvccinfo.snapshot.lowest_active_mvccid = crt_status_lowest_active;
335  tdes.mvccinfo.snapshot.highest_completed_mvccid = highest_completed_mvccid;
336  tdes.mvccinfo.snapshot.valid = true;
337 
338  if (is_perf_tracking)
339  {
340  tsc_getticks (&end_tick);
341  tsc_elapsed_time_usec (&tv_diff, end_tick, start_tick);
342  snapshot_wait_time = tv_diff.tv_sec * 1000000LL + tv_diff.tv_usec;
343  if (snapshot_wait_time > 0)
344  {
346  }
347  if (snapshot_retry_count > 1)
348  {
350  snapshot_retry_count - 1);
351  }
352  }
353 }
354 
355 MVCCID
357 {
358  perf_utime_tracker perf;
360  PERF_UTIME_TRACKER_START (&threadr, &perf);
361 
362  const size_t MVCC_OLDEST_ACTIVE_BUFFER_LENGTH = 32;
364  MVCCID loaded_tran_mvccid;
367 
368  for (size_t idx = 0; idx < m_transaction_lowest_visible_mvccids_size; idx++)
369  {
370  loaded_tran_mvccid = oldest_active_get (m_transaction_lowest_visible_mvccids[idx], idx,
372  if (loaded_tran_mvccid == MVCCID_ALL_VISIBLE)
373  {
374  waiting_mvccids_pos.append (idx);
375  }
376  else if (loaded_tran_mvccid != MVCCID_NULL && MVCC_ID_PRECEDES (loaded_tran_mvccid, lowest_active_mvccid))
377  {
378  lowest_active_mvccid = loaded_tran_mvccid;
379  }
380  }
381 
382  size_t retry_count = 0;
383  while (waiting_mvccids_pos.get_size () > 0)
384  {
385  ++retry_count;
386  if (retry_count % 20 == 0)
387  {
388  thread_sleep (10);
389  }
390 
391  for (size_t i = waiting_mvccids_pos.get_size () - 1; i < waiting_mvccids_pos.get_size (); --i)
392  {
393  size_t pos = waiting_mvccids_pos.get_array ()[i];
394  loaded_tran_mvccid = oldest_active_get (m_transaction_lowest_visible_mvccids[pos], pos,
396  if (loaded_tran_mvccid == MVCCID_ALL_VISIBLE)
397  {
398  /* Not set yet, need to wait more. */
399  continue;
400  }
401  if (loaded_tran_mvccid != MVCCID_NULL && MVCC_ID_PRECEDES (loaded_tran_mvccid, lowest_active_mvccid))
402  {
403  lowest_active_mvccid = loaded_tran_mvccid;
404  }
405  // remove from waiting array
406  waiting_mvccids_pos.erase (i);
407  }
408  }
409 
410  if (perf.is_perf_tracking)
411  {
412  PERF_UTIME_TRACKER_TIME (&threadr, &perf, PSTAT_LOG_OLDEST_MVCC_TIME_COUNTERS);
413  if (retry_count > 0)
414  {
416  }
417  }
418 
419  assert (MVCCID_IS_NORMAL (lowest_active_mvccid));
420  return lowest_active_mvccid;
421 }
422 
423 bool
425 {
426  size_t index = 0;
428  bool ret_active = false;
429  // trans status must be same before and after computing is_active. if it is not, we need to repeat the computation.
430  do
431  {
432  index = m_trans_status_history_position.load ();
433  version = m_trans_status_history[index].m_version.load ();
434  ret_active = m_trans_status_history[index].m_active_mvccs.is_active (mvccid);
435  }
436  while (version != m_trans_status_history[index].m_version.load ());
437 
438  return ret_active;
439 }
440 
443 {
444  // new version, new status entry
445  next_index = (m_trans_status_history_position.load () + 1) & HISTORY_INDEX_MASK;
446  next_version = ++m_current_trans_status.m_version;
447 
448  // invalidate next status entry
449  mvcc_trans_status &next_trans_status = m_trans_status_history[next_index];
450  next_trans_status.m_version.store (next_version);
451 
452  return next_trans_status;
453 }
454 
455 void
456 mvcctable::next_tran_status_finish (mvcc_trans_status &next_trans_status, size_t next_index)
457 {
462  m_trans_status_history_position.store (next_index);
463 }
464 
465 void
466 mvcctable::complete_mvcc (int tran_index, MVCCID mvccid, bool committed)
467 {
468  assert (MVCCID_IS_VALID (mvccid));
469 
470  // only one can change status at a time
471  std::unique_lock<std::mutex> ulock (m_active_trans_mutex);
472 
473  mvcc_trans_status::version_type next_version;
474  size_t next_index;
475  mvcc_trans_status &next_status = next_trans_status_start (next_version, next_index);
476 
477  // todo - until we activate count optimization (if ever), should we move this outside mutex?
479  {
480  assert (false);
481  }
482 
483  // update current trans status
487 
488  // finish next trans status
489  next_tran_status_finish (next_status, next_index);
490 
491  if (committed)
492  {
493  /* be sure that transaction modifications can't be vacuumed up to LOG_COMMIT. Otherwise, the following
494  * scenario will corrupt the database:
495  * - transaction set its lowest_active_mvccid to MVCCID_NULL
496  * - VACUUM clean up transaction modifications
497  * - the system crash before LOG_COMMIT of current transaction
498  *
499  * It will be set to NULL after LOG_COMMIT
500  */
501  MVCCID tran_lowest_active = oldest_active_get (m_transaction_lowest_visible_mvccids[tran_index], tran_index,
503  if (tran_lowest_active == MVCCID_NULL || MVCC_ID_PRECEDES (tran_lowest_active, mvccid))
504  {
505  oldest_active_set (m_transaction_lowest_visible_mvccids[tran_index], tran_index, mvccid,
507  }
508  }
509  else
510  {
513  }
514 
515  ulock.unlock ();
516 
517  // update lowest active in current transactions status. can be done outside lock
518  // this doesn't have to be 100% accurate; it is used as indicative by vacuum to clean up the database. however, it
519  // shouldn't be left too much behind, or vacuum can't advance
520  // so we try to limit recalculation when mvccid matches current global_lowest_active; since we are not locked, it is
521  // not guaranteed to be always updated; therefore we add the second condition to go below trans status
522  // bit area starting MVCCID; the recalculation will happen on each iteration if there are long transactions.
523  MVCCID global_lowest_active = m_current_status_lowest_active_mvccid;
524  if (global_lowest_active == mvccid
525  || MVCC_ID_PRECEDES (mvccid, next_status.m_active_mvccs.get_bit_area_start_mvccid ()))
526  {
527  MVCCID new_lowest_active = next_status.m_active_mvccs.compute_lowest_active_mvccid ();
528 #if !defined (NDEBUG)
529  oldest_active_add_event (new_lowest_active, (int) next_index, oldest_active_event::GET_LOWEST_ACTIVE,
531 #endif // !NDEBUG
532  // we need to recheck version to validate result
533  if (next_status.m_version.load () == next_version)
534  {
535  // advance
536  advance_oldest_active (new_lowest_active);
537  }
538  }
539 }
540 
541 void
543 {
544  assert (MVCCID_IS_VALID (mvccid));
545 
546  // only one can change status at a time
547  std::unique_lock<std::mutex> ulock (m_active_trans_mutex);
548 
549  mvcc_trans_status::version_type next_version;
550  size_t next_index;
551  mvcc_trans_status &next_status = next_trans_status_start (next_version, next_index);
552 
553  // update current trans status
557 
558  // finish next trans status
559  next_tran_status_finish (next_status, next_index);
560 
561  ulock.unlock ();
562 
563  // mvccid can't be lowest, so no need to update it here
564 }
565 
566 MVCCID
568 {
569  MVCCID id;
570 
571  m_new_mvccid_lock.lock ();
572  id = log_Gl.hdr.mvcc_next_id;
574  m_new_mvccid_lock.unlock ();
575 
576  return id;
577 }
578 
579 void
581 {
582  m_new_mvccid_lock.lock ();
583 
584  first = log_Gl.hdr.mvcc_next_id;
586 
587  second = log_Gl.hdr.mvcc_next_id;
589 
590  m_new_mvccid_lock.unlock ();
591 }
592 
593 void
595 {
598 }
599 
600 void
602 {
604 
607 
609 }
610 
611 MVCCID
613 {
614  return m_oldest_visible.load ();
615 }
616 
617 MVCCID
619 {
620  if (m_ov_lock_count == 0)
621  {
622  MVCCID oldest_visible = compute_oldest_visible_mvccid ();
623  if (m_ov_lock_count == 0)
624  {
625  assert (m_oldest_visible.load () <= oldest_visible);
626  m_oldest_visible.store (oldest_visible);
627  }
628  }
629  return m_oldest_visible.load ();
630 }
631 
632 void
634 {
635  ++m_ov_lock_count;
636 }
637 
638 void
640 {
641  assert (m_ov_lock_count > 0);
642  --m_ov_lock_count;
643 }
644 
645 bool
647 {
648  return m_ov_lock_count != 0;
649 }
MVCCID recent_snapshot_lowest_active_mvccid
Definition: mvcc.h:202
MVCCID m_last_completed_mvccid
Definition: mvcc_table.hpp:53
int tran_index
Definition: log_impl.h:465
MVCCID highest_completed_mvccid
Definition: mvcc.h:172
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
void reset_start_mvccid()
Definition: mvcc_table.cpp:601
MVCCID update_global_oldest_visible()
Definition: mvcc_table.cpp:618
void finalize()
Definition: mvcc_table.cpp:211
static void oldest_active_set(mvcctable::lowest_active_mvccid_type &lowest, int tran_index, MVCCID mvccid, oldest_active_event::source src)
Definition: mvcc_table.cpp:90
void unlock_global_oldest_visible()
Definition: mvcc_table.cpp:639
void get_two_new_mvccid(MVCCID &first, MVCCID &second)
Definition: mvcc_table.cpp:580
MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_satisfies_snapshot(THREAD_ENTRY *thread_p, MVCC_REC_HEADER *rec_header, MVCC_SNAPSHOT *snapshot)
Definition: mvcc.c:144
#define MVCCID_FIRST
std::atomic< size_t > m_trans_status_history_position
Definition: mvcc_table.hpp:110
bool is_global_oldest_visible_locked() const
Definition: mvcc_table.cpp:646
int logtb_get_number_of_total_tran_indices(void)
LOG_GLOBAL log_Gl
LOG_HEADER hdr
Definition: log_impl.h:653
int logtb_tran_update_all_global_unique_stats(THREAD_ENTRY *thread_p)
void advance_oldest_active(MVCCID next_oldest_active)
Definition: mvcc_table.cpp:140
void thread_sleep(double millisec)
void reset_start_mvccid(MVCCID mvccid)
#define MVCCID_NULL
void build_mvcc_info(log_tdes &tdes)
Definition: mvcc_table.cpp:224
std::atomic< version_type > m_version
Definition: mvcc_table.hpp:55
struct timeval TSCTIMEVAL
Definition: tsc_timer.h:40
MVCCID compute_oldest_visible_mvccid() const
Definition: mvcc_table.cpp:356
void tsc_elapsed_time_usec(TSCTIMEVAL *tv, TSC_TICKS end_tick, TSC_TICKS start_tick)
Definition: tsc_timer.c:101
bool valid
Definition: mvcc.h:178
static void oldest_active_add_event(MVCCID mvccid, int tran_index, oldest_active_event::op_type set_or_get, oldest_active_event::source src)
Definition: mvcc_table.cpp:78
MVCCID lowest_active_mvccid
Definition: mvcc.h:171
void complete_mvcc(int tran_index, MVCCID mvccid, bool committed)
Definition: mvcc_table.cpp:466
const size_t OLDEST_ACTIVE_HISTORY_SIZE
Definition: mvcc_table.cpp:69
static MVCCID oldest_active_get(const mvcctable::lowest_active_mvccid_type &lowest, int tran_index, oldest_active_event::source src)
Definition: mvcc_table.cpp:100
#define MVCCID_ALL_VISIBLE
size_t get_size(void) const
#define MVCCID_IS_NORMAL(id)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define assert(x)
oldest_active_event m_history[OLDEST_ACTIVE_HISTORY_SIZE]
Definition: mvcc_table.cpp:73
std::atomic< MVCCID > m_oldest_visible
Definition: mvcc_table.hpp:118
void set_inactive_mvccid(MVCCID mvccid)
MVCCID compute_highest_completed_mvccid() const
bool is_active(MVCCID mvccid) const
Definition: mvcc_table.cpp:424
#define ER_MVCC_CANT_GET_SNAPSHOT
Definition: error_code.h:1482
static const size_t HISTORY_MAX_SIZE
Definition: mvcc_table.hpp:97
MVCC_INFO mvccinfo
Definition: log_impl.h:463
oldest_active_history_tracker Oldest_active_tracker
Definition: mvcc_table.cpp:75
mvcc_active_tran m_active_mvccs
Definition: mvcc.h:174
size_t m_transaction_lowest_visible_mvccids_size
Definition: mvcc_table.hpp:102
std::mutex m_new_mvccid_lock
Definition: mvcc_table.hpp:114
#define NULL
Definition: freelistheap.h:34
UINT64 MVCCID
void check_valid() const
void tsc_getticks(TSC_TICKS *tck)
Definition: tsc_timer.c:81
STATIC_INLINE bool perfmon_is_perf_tracking(void) __attribute__((ALWAYS_INLINE))
std::atomic< MVCCID > lowest_active_mvccid_type
Definition: mvcc_table.hpp:67
void initialize()
Definition: mvcc_table.cpp:183
#define MVCC_ID_PRECEDES(id1, id2)
Definition: mvcc.h:137
mvcc_trans_status * m_trans_status_history
Definition: mvcc_table.hpp:111
static int logtb_load_global_statistics_to_tran(THREAD_ENTRY *thread_p)
lowest_active_mvccid_type m_current_status_lowest_active_mvccid
Definition: mvcc_table.hpp:104
MVCCID get_global_oldest_visible() const
Definition: mvcc_table.cpp:612
#define ARG_FILE_LINE
Definition: error_manager.h:44
mvcc_trans_status & next_trans_status_start(mvcc_trans_status::version_type &next_version, size_t &next_index)
Definition: mvcc_table.cpp:442
void lock_global_oldest_visible()
Definition: mvcc_table.cpp:633
event_type m_event_type
Definition: mvcc_table.hpp:54
unsigned int version_type
Definition: mvcc_table.hpp:42
MVCCID get_bit_area_start_mvccid()
MVCC_SNAPSHOT snapshot
Definition: mvcc.h:194
mvcc_trans_status m_current_trans_status
Definition: mvcc_table.hpp:107
static const size_t HISTORY_INDEX_MASK
Definition: mvcc_table.hpp:98
void append(const T &source)
MVCCID compute_lowest_active_mvccid() const
void reset_transaction_lowest_active(int tran_index)
Definition: mvcc_table.cpp:594
int i
Definition: dynamic_load.c:954
bool is_active(MVCCID mvccid) const
void alloc_transaction_lowest_active()
Definition: mvcc_table.cpp:198
void copy_to(mvcc_active_tran &dest, copy_safety safety) const
STATIC_INLINE void perfmon_add_stat(THREAD_ENTRY *thread_p, PERF_STAT_ID psid, UINT64 amount) __attribute__((ALWAYS_INLINE))
MVCC_SNAPSHOT_FUNC snapshot_fnc
Definition: mvcc.h:176
lowest_active_mvccid_type * m_transaction_lowest_visible_mvccids
Definition: mvcc_table.hpp:101
std::mutex m_active_trans_mutex
Definition: mvcc_table.hpp:116
entry & get_entry(void)
void next_tran_status_finish(mvcc_trans_status &next_trans_status, size_t next_index)
Definition: mvcc_table.cpp:456
oldest_active_event & operator=(const oldest_active_event &other)
Definition: mvcc_table.cpp:58
#define MVCCID_FORWARD(id)
std::atomic< size_t > m_event_count
Definition: mvcc_table.cpp:72
MVCCID mvcc_next_id
mvcc_active_tran m_active_mvccs
Definition: mvcc_table.hpp:51
#define MVCCID_IS_VALID(id)
const T * get_array(void) const
void complete_sub_mvcc(MVCCID mvccid)
Definition: mvcc_table.cpp:542
std::atomic< size_t > m_ov_lock_count
Definition: mvcc_table.hpp:119
MVCCID get_new_mvccid()
Definition: mvcc_table.cpp:567