Zero  0.1.0
smthread.h
Go to the documentation of this file.
1 /*
2  * (c) Copyright 2011-2013, Hewlett-Packard Development Company, LP
3  */
4 
5 /* -*- mode:C++; c-basic-offset:4 -*-
6  Shore-MT -- Multi-threaded port of the SHORE storage manager
7 
8  Copyright (c) 2007-2009
9  Data Intensive Applications and Systems Labaratory (DIAS)
10  Ecole Polytechnique Federale de Lausanne
11 
12  All Rights Reserved.
13 
14  Permission to use, copy, modify and distribute this software and
15  its documentation is hereby granted, provided that both the
16  copyright notice and this permission notice appear in all copies of
17  the software, derivative works or modified versions, and any
18  portions thereof, and that both notices appear in supporting
19  documentation.
20 
21  This code is distributed in the hope that it will be useful, but
22  WITHOUT ANY WARRANTY; without even the implied warranty of
23  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
24  DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
25  RESULTING FROM THE USE OF THIS SOFTWARE.
26 */
27 
28 /*<std-header orig-src='shore' incl-file-exclusion='SMTHREAD_H'>
29 
30  $Id: smthread.h,v 1.106 2010/12/08 17:37:43 nhall Exp $
31 
32 SHORE -- Scalable Heterogeneous Object REpository
33 
34 Copyright (c) 1994-99 Computer Sciences Department, University of
35  Wisconsin -- Madison
36 All Rights Reserved.
37 
38 Permission to use, copy, modify and distribute this software and its
39 documentation is hereby granted, provided that both the copyright
40 notice and this permission notice appear in all copies of the
41 software, derivative works or modified versions, and any portions
42 thereof, and that both notices appear in supporting documentation.
43 
44 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
45 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
46 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
47 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 
49 This software was developed with support by the Advanced Research
50 Project Agency, ARPA order number 018 (formerly 8230), monitored by
51 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
52 Further funding for this work was provided by DARPA through
53 Rome Research Laboratory Contract No. F30602-97-2-0247.
54 
55 */
56 
57 #ifndef __SMTHREAD_H
58 #define __SMTHREAD_H
59 
60 #include "w_defines.h"
61 
62 /* -- do not edit anything above this line -- </std-header>*/
63 
68 #include <cassert>
69 
70 #ifndef __W_H
71 #include "w.h"
72 #endif // __W_H
73 #ifndef __SM_BASE_H
74 #include "sm_base.h"
75 #endif // __SM_BASE_H
76 
77 #include "w_bitvector.h"
78 #include <mutex>
79 #include <memory>
80 #include <list>
81 
82 #include "timeout.h"
83 #include "latches.h"
84 #include "logrec.h"
85 #include "smstats.h"
86 
87 class xct_t;
88 class lockid_t;
89 class smthread_t;
90 
92 enum {
93  FINGER_BITS = SM_DREADLOCK_FINGERS
94 };
95 
96 typedef w_bitvector_t<SM_DREADLOCK_BITCOUNT> sm_thread_map_t;
119 typedef sm_thread_map_t atomic_thread_map_t;
120 /*
121  We do NOT need synchronization for Dreadlock bitmap.
122  We freshly re-compute bitmaps at each spin (no false-negatives in long run),
123  and we tolerate occasional false positives.
124  So, atomic_thread_map_t is no longer needed.
125 
126 class atomic_thread_map_t : public sm_thread_map_t {
127 private:
128  // mutable srwlock_t _map_lock;
129 public:
130 
131  bool has_reader() const {
132  return _map_lock.has_reader();
133  }
134  bool has_writer() const {
135  return _map_lock.has_writer();
136  }
137  void lock_for_read() const {
138  _map_lock.acquire_read();
139  }
140  void lock_for_write() {
141  _map_lock.acquire_write();
142  }
143  void unlock_reader() const{
144  w_assert2(_map_lock.has_reader());
145  _map_lock.release_read();
146  }
147  void unlock_writer() {
148  w_assert2(_map_lock.has_writer());
149  _map_lock.release_write();
150  }
151  atomic_thread_map_t () {
152  w_assert1(_map_lock.has_reader() == false);
153  w_assert1(_map_lock.has_writer() == false);
154  }
155  ~atomic_thread_map_t () {
156  w_assert1(_map_lock.has_reader() == false);
157  w_assert1(_map_lock.has_writer() == false);
158  }
159 
160  atomic_thread_map_t &operator=(const atomic_thread_map_t &other) {
161  // Copy only the bitmap portion; do not touch the
162  // _map_lock
163 #if W_DEBUG_LEVEL > 0
164  bool X=_map_lock.has_reader();
165  bool Y=_map_lock.has_writer();
166 #endif
167  copy(other);
168 #if W_DEBUG_LEVEL > 0
169  w_assert1(_map_lock.has_reader() == X);
170  w_assert1(_map_lock.has_writer() == Y);
171 #endif
172  return *this;
173  }
174 };
175 */
176 
201 class smthread_t {
202  friend class smthread_init_t;
203 
204  struct tcb_t {
205  // CS: moved out of xct_t
207 
208  logrec_t _logbuf2; // for "piggy-backed" SSX
209 
211 
212  int pin_count; // number of rsrc_m pins
213  int prev_pin_count; // previous # of rsrc_m pins
214  int lock_timeout; // timeout to use for lock acquisitions
215  bool _in_sm; // thread is in sm ss_m:: function
216  bool _is_update_thread;// thread is in update function
217 
218  int16_t _depth; // how many "outer" this has
219  tcb_t* _outer; // this forms a singly linked list
220 
221  sm_stats_t _TL_stats; // thread-local stats
222 
223  // for lock_head_t::my_lock::get_me
225 
227 
229 
235 
236  // force this to be 8-byte aligned:
237 
238  void create_TL_stats();
239 
240  void clear_TL_stats();
241 
242  void destroy_TL_stats();
243 
244  inline sm_stats_t& TL_stats() {
245  return _TL_stats;
246  }
247 
248  inline const sm_stats_t& TL_stats_const() const {
249  return _TL_stats;
250  }
251 
252  static long get_TL_stat(sm_stat_id stat) {
253  return smthread_t::TL_stats()[enum_to_base(stat)];
254  }
255 
256  tcb_t(tcb_t* outer) :
257  xct(0),
258  pin_count(0),
259  prev_pin_count(0),
260  lock_timeout(timeout_t::WAIT_FOREVER), // default for a thread
261  _in_sm(false),
262  _is_update_thread(false),
263  _depth(outer == nullptr ? 1 : outer->_depth + 1),
264  _outer(outer) {
268  QUEUE_EXT_QNODE_INITIALIZE(_xlist_mutex_node);
269 
270  create_TL_stats();
271  }
272 
273  ~tcb_t() {
275  }
276  };
277 
278 public:
279 
280  // bool _try_initialize_fingerprint(); // true: failure false: ok
281  // void _initialize_fingerprint();
282  // void _uninitialize_fingerprint();
283  // short _fingerprint[FINGER_BITS]; // dreadlocks
284  // atomic_thread_map_t _fingerprint_map; // map containing only fingerprint
285 
286 public:
287  // const atomic_thread_map_t& get_fingerprint_map() const
288  // { return _fingerprint_map; }
289  static void timeout_to_timespec(int timeout_ms, struct timespec& when);
290 
291 public:
292 
294  /* public for debugging */
295  static void init_fingerprint_map();
311  static void attach_xct(xct_t* x);
312 
324  static void detach_xct(xct_t* x);
325 
327  static inline
328  int lock_timeout() {
329  return tcb().lock_timeout;
330  }
331 
350  static inline
351  void set_lock_timeout(int i) {
352  tcb().lock_timeout = i;
353  }
354 
355  static logrec_t* get_logbuf() {
356  return &tcb()._logbuf;
357  }
358 
359  static logrec_t* get_logbuf2() {
360  return &tcb()._logbuf2;
361  }
362 
364  static inline xct_t* xct() {
365  return tcb().xct;
366  }
367 
369  static inline sm_stats_t& TL_stats() {
370  return tcb().TL_stats();
371  }
372 
373  static long get_TL_stat(sm_stat_id s) {
374  return tcb().get_TL_stat(s);
375  }
376 
378  static void add_from_TL_stats(sm_stats_t& w);
379 
380  // NOTE: These macros don't have to be atomic since these thread stats
381  // are stored in the smthread and collected when the smthread's tcb is
382  // destroyed.
383 
384 #define GET_TSTAT(x) smthread_t::TL_stats()[enum_to_base(sm_stat_id::x)]
385 
392 #define INC_TSTAT(x) smthread_t::TL_stats()[enum_to_base(sm_stat_id::x)]++
393 
397 #define ADD_TSTAT(x, y) smthread_t::TL_stats()[enum_to_base(sm_stat_id::x)] += (y)
398 
402 #define SET_TSTAT(x, y) smthread_t::TL_stats()[enum_to_base(sm_stat_id::x)] = (y)
403 
404 
406  /*
407  * These functions are used to verify than nothing is
408  * left pinned accidentally. Call mark_pin_count before an
409  * operation and check_pin_count after it with the expected
410  * number of pins that should not have been realeased.
411  */
412  static void mark_pin_count();
413 
414  static void check_pin_count(int change);
415 
416  static void check_actual_pin_count(int actual);
417 
418  static void incr_pin_count(int amount);
419 
420  static int pin_count();
421 
422  /*
423  * These functions are used to verify that a thread
424  * is only in one ss_m::, scan::, or pin:: function at a time.
425  */
426  static inline
427  void in_sm(bool in) {
428  tcb()._in_sm = in;
429  }
430 
431  static inline
432  bool is_in_sm() {
433  return tcb()._in_sm;
434  }
435 
436  static inline
437  bool is_update_thread() {
438  return tcb()._is_update_thread;
439  }
440 
441  static inline
442  void set_is_update_thread(bool in) {
443  tcb()._is_update_thread = in;
444  }
445 
446  static void no_xct(xct_t*);
447 
448  virtual void _dump(ostream&) const; // to be over-ridden
451  /* thread-level block() and unblock aren't public or protected
452  accessible.
453  These methods are used by the lock manager.
454  Otherwise, ordinarly pthreads sychronization variables
455  are used.
456  */
457  // w_error_codes smthread_block(int WAIT_FOREVER,
458  // const char * const caller = 0,
459  // const void * id = 0);
460  // w_rc_t smthread_unblock(w_error_codes e);
461 
462  // int sampling;
463 // private:
464  // w_error_codes _smthread_block( int WAIT_FOREVER,
465  // const char * const why =0);
466  // w_rc_t _smthread_unblock(w_error_codes e);
467 
468 public:
472  return tcb()._me3;
473  }
474 
476  return tcb()._me2;
477  }
478 
480  return tcb()._me1;
481  }
482 
484  return tcb()._xlist_mutex_node;
485  }
486 
487 private:
488  /* sm-specific block / unblock implementation */
489  bool _waiting;
490 
500  static tcb_t*& tcb_ptr() {
501  // static local var -- initialized only on first call
502  static thread_local tcb_t* tcb = new tcb_t(nullptr);
503  return tcb;
504  }
505 
506  static tcb_t& tcb() {
507  auto ret = tcb_ptr();
508  w_assert3(ret);
509  return *ret;
510  }
511 
512 public:
514  static inline size_t get_tcb_depth() {
515  return tcb()._depth;
516  }
517 
518 private:
519 
521  public:
522  void add_me() {
523  std::unique_lock<std::mutex> lck{_mutex};
524  _tcb_list.push_back(tcb_ptr());
525  }
526 
527  void remove_me() {
528  std::unique_lock<std::mutex> lck{_mutex};
529  auto iter = _tcb_list.begin();
530  while (iter != _tcb_list.end()) {
531  if (*iter == tcb_ptr()) {
532  delete *iter;
533  iter = _tcb_list.erase(iter);
534  } else {
535  iter++;
536  }
537  }
538  }
539 
540  template<typename F>
541  void for_each_stats(F& f) {
542  std::unique_lock<std::mutex> lck{_mutex};
543  for (auto p : _tcb_list) {
544  f(p->TL_stats());
545  }
546  }
547 
548  private:
549  std::list<tcb_t*> _tcb_list;
550 
551  std::mutex _mutex;
552  };
553 
554  static std::shared_ptr<GlobalThreadList> thread_list() {
555  static auto ptr = std::make_shared<GlobalThreadList>();
556  return ptr;
557  }
558 
559 public:
560 
561  static void add_me_to_thread_list() {
562  thread_list()->add_me();
563  }
564 
566  thread_list()->remove_me();
567  }
568 
569  template<typename F>
570  static void for_each_thread_stats(F& f) {
571  thread_list()->for_each_stats(f);
572  }
573 };
574 
575 inline xct_t* xct() {
576  return smthread_t::xct();
577 }
578 
580 class smthread_init_t {
581 public:
582  smthread_init_t();
583 
584  ~smthread_init_t();
585 
586 private:
587  static int count;
588 };
593 inline void
594 smthread_t::mark_pin_count() {
596 }
597 
598 inline void
599 smthread_t::check_pin_count(int W_IFDEBUG4(change)) {
600 #if W_DEBUG_LEVEL > 3
601  int diff = tcb().pin_count - tcb().prev_pin_count;
602  if (change >= 0) {
603  w_assert4(diff <= change);
604  } else {
605  w_assert4(diff >= change);
606  }
607 #endif
608 }
609 
610 inline void
611 smthread_t::check_actual_pin_count(int actual) {
612  w_assert3(tcb().pin_count == actual);
613 }
614 
615 inline void
616 smthread_t::incr_pin_count(int amount) {
617  tcb().pin_count += amount;
618 }
619 
620 inline int
621 smthread_t::pin_count() {
622  return tcb().pin_count;
623 }
624 
625 void
626 DumpBlockedThreads(ostream& o);
627 
628 /*
629  * redefine DBGTHRD to use our threads
630  */
631 #ifdef DBGTHRD
632 #undef DBGTHRD
633 #endif
634 #define DBGTHRD(arg) DBG(<< " th." << std::this_thread::get_id() << " " arg)
635 
639 /*<std-footer incl-file-exclusion='SMTHREAD_H'> -- do not edit anything below this line -- */
640 
641 #endif // __SMTHREAD_H /*</std-footer>*/
void create_TL_stats()
Called on tcb_t constructor.
Definition: smthread.cpp:34
static tcb_t *& tcb_ptr()
Definition: smthread.h:500
static queue_based_lock_t::ext_qnode & get_xlist_mutex_node()
Definition: smthread.h:483
void clear_TL_stats()
Definition: smthread.cpp:69
tcb_t(tcb_t *outer)
Definition: smthread.h:256
int prev_pin_count
Definition: smthread.h:213
logrec_t _logbuf2
Definition: smthread.h:208
static xct_t * xct()
return xct this thread is running
Definition: smthread.h:364
static logrec_t * get_logbuf()
Definition: smthread.h:355
logrec_t _logbuf
Definition: smthread.h:206
Storage Manager thread.
Definition: smthread.h:201
int lock_timeout
Definition: smthread.h:214
static int lock_timeout()
get lock_timeout value
Definition: smthread.h:328
void remove_me()
Definition: smthread.h:527
A transaction. Internal to the storage manager.This class may be used in a limited way for the handli...
Definition: xct.h:185
sm_thread_map_t atomic_thread_map_t
Fingerprint for this smthread.
Definition: smthread.h:89
bool _is_update_thread
Definition: smthread.h:216
#define w_assert3(x)
Level 3 definitely adds significant time.
Definition: w_base.h:214
sm_stats_t & TL_stats()
Definition: smthread.h:244
#define F
Definition: w_okvl_inl.h:46
queue_based_lock_t::ext_qnode _me3
Definition: smthread.h:228
Definition: smthread.h:520
static std::shared_ptr< GlobalThreadList > thread_list()
Definition: smthread.h:554
void add_me()
Definition: smthread.h:522
int pin_count
Definition: smthread.h:212
Represents a transactional log record.
Definition: logrec.h:143
bool _waiting
Definition: smthread.h:489
static queue_based_lock_t::ext_qnode & get_me3()
TLS variables Exported to sm.
Definition: smthread.h:471
sm_stat_id
Definition: smstats.h:131
static void add_from_TL_stats(sm_stats_t &w)
Add thread-local stats into the given structure.
Definition: smthread.cpp:82
static long get_TL_stat(sm_stat_id stat)
Definition: smthread.h:252
static void add_me_to_thread_list()
Definition: smthread.h:561
friend class smthread_init_t
Definition: smthread.h:202
bool _in_sm
Definition: smthread.h:215
Templated bitmap for arbitrary size in bits.
Definition: w_bitvector.h:62
static void detach_xct(xct_t *x)
Definition: smthread.cpp:396
std::array< long, enum_to_base(sm_stat_id::stat_max)> sm_stats_t
Definition: smstats.h:205
static void set_lock_timeout(int i)
Set lock_timeout value.
Definition: smthread.h:351
#define QUEUE_EXT_QNODE_INITIALIZE(x)
Definition: latches.h:219
static queue_based_lock_t::ext_qnode & get_me2()
Definition: smthread.h:475
void destroy_TL_stats()
Called on tcb_t destructor.
Definition: smthread.cpp:41
queue_based_lock_t::ext_qnode _xlist_mutex_node
Queue node for holding mutex to serialize access transaction list. Used in xct.cpp.
Definition: smthread.h:234
#define w_assert4(x)
Level 4 can be a hog.
Definition: w_base.h:222
static sm_stats_t & TL_stats()
Return thread-local statistics collected for this thread.
Definition: smthread.h:369
xct_t * xct
Definition: smthread.h:210
static long get_TL_stat(sm_stat_id s)
Definition: smthread.h:373
The means of identifying a desired or held lock.
Definition: lock_s.h:41
~tcb_t()
Definition: smthread.h:273
queue_based_lock_t::ext_qnode _me2
Definition: smthread.h:226
static void timeout_to_timespec(int timeout_ms, struct timespec &when)
Definition: smthread.cpp:335
Special values for timeouts (int-values).
Definition: timeout.h:26
tcb_t * _outer
Definition: smthread.h:219
constexpr auto enum_to_base(E e) -> typename std::underlying_type< E >::type
Definition: smstats.h:127
static queue_based_lock_t::ext_qnode & get_me1()
Definition: smthread.h:479
queue_based_lock_t::ext_qnode _me1
Definition: smthread.h:224
sm_stats_t _TL_stats
Definition: smthread.h:221
static tcb_t & tcb()
Definition: smthread.h:506
int16_t _depth
Definition: smthread.h:218
static size_t get_tcb_depth()
Definition: smthread.h:514
std::list< tcb_t * > _tcb_list
Definition: smthread.h:549
static void for_each_thread_stats(F &f)
Definition: smthread.h:570
std::mutex _mutex
Definition: smthread.h:551
#define W_IFDEBUG4(x)
Definition: w_base.h:119
const sm_stats_t & TL_stats_const() const
Definition: smthread.h:248
Definition: mcs_lock.h:76
Definition: smthread.h:204
void for_each_stats(F &f)
Definition: smthread.h:541
static logrec_t * get_logbuf2()
Definition: smthread.h:359
static void remove_me_from_thread_list()
Definition: smthread.h:565