OmniSciDB  04ee39c94c
RWLocks.h
Go to the documentation of this file.
1 /*
2  * Copyright 2019 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef RW_LOCKS_H
18 #define RW_LOCKS_H
19 
20 #include "../Shared/mapd_shared_mutex.h"
21 
22 namespace Catalog_Namespace {
23 
24 /*
25  * The locking sequence for the locks below is as follows:
26  *
27  * inter catalog / syscatalog it is always
28  *
29  * read or write lock, then the sqlite_lock (if required)
30  *
31  * intra catalog and syscatalog
32  *
33  * always syscatalog locks (if required), then catalog locks
34  */
35 
36 template <typename T>
37 class read_lock {
38  const T* catalog;
39  mapd_shared_lock<mapd_shared_mutex> lock;
40  bool holds_lock;
41 
42  template <typename inner_type>
43  void lock_catalog(const inner_type* cat) {
44  std::thread::id tid = std::this_thread::get_id();
45 
46  if (cat->thread_holding_write_lock != tid && !inner_type::thread_holds_read_lock) {
47  lock = mapd_shared_lock<mapd_shared_mutex>(cat->sharedMutex_);
48  inner_type::thread_holds_read_lock = true;
49  holds_lock = true;
50  }
51  }
52 
53  public:
54  read_lock(const T* cat) : catalog(cat), holds_lock(false) { lock_catalog(cat); }
55 
57  if (holds_lock) {
58  T::thread_holds_read_lock = false;
59  }
60  }
61 };
62 
63 template <typename T>
64 class sqlite_lock {
65  // always obtain a read lock on catalog first
66  // to ensure correct locking order
68  const T* catalog;
69  std::unique_lock<std::mutex> lock;
70  bool holds_lock;
71 
72  template <typename inner_type>
73  void lock_catalog(const inner_type* cat) {
74  std::thread::id tid = std::this_thread::get_id();
75 
76  if (cat->thread_holding_sqlite_lock != tid) {
77  lock = std::unique_lock<std::mutex>(cat->sqliteMutex_);
78  cat->thread_holding_sqlite_lock = tid;
79  holds_lock = true;
80  }
81  }
82 
83  public:
84  sqlite_lock(const T* cat) : cat_read_lock(cat), catalog(cat), holds_lock(false) {
85  lock_catalog(cat);
86  }
87 
89  if (holds_lock) {
90  std::thread::id no_thread;
91  catalog->thread_holding_sqlite_lock = no_thread;
92  }
93  }
94 };
95 
96 template <typename T>
97 class write_lock {
98  const T* catalog;
99  mapd_unique_lock<mapd_shared_mutex> lock;
101 
102  template <typename inner_type>
103  void lock_catalog(const inner_type* cat) {
104  std::thread::id tid = std::this_thread::get_id();
105 
106  if (cat->thread_holding_write_lock != tid) {
107  lock = mapd_unique_lock<mapd_shared_mutex>(cat->sharedMutex_);
108  cat->thread_holding_write_lock = tid;
109  holds_lock = true;
110  }
111  }
112 
113  public:
114  write_lock(const T* cat) : catalog(cat), holds_lock(false) { lock_catalog(cat); }
115 
117  if (holds_lock) {
118  std::thread::id no_thread;
119  catalog->thread_holding_write_lock = no_thread;
120  }
121  }
122 };
123 
124 } // namespace Catalog_Namespace
125 
126 #endif // RW_LOCKS_H
void lock_catalog(const inner_type *cat)
Definition: RWLocks.h:103
mapd_unique_lock< mapd_shared_mutex > lock
Definition: RWLocks.h:99
write_lock(const T *cat)
Definition: RWLocks.h:114
sqlite_lock(const T *cat)
Definition: RWLocks.h:84
mapd_shared_lock< mapd_shared_mutex > lock
Definition: RWLocks.h:39
read_lock(const T *cat)
Definition: RWLocks.h:54
std::unique_lock< std::mutex > lock
Definition: RWLocks.h:69
read_lock< T > cat_read_lock
Definition: RWLocks.h:67
void lock_catalog(const inner_type *cat)
Definition: RWLocks.h:43
void lock_catalog(const inner_type *cat)
Definition: RWLocks.h:73