CUBRID Engine  latest
thread_lockfree_hash_map.hpp
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 // specialize lock-free hash map to thread manager and its entries
21 //
22 
23 #ifndef _THREAD_LOCKFREE_HASH_MAP_HPP_
24 #define _THREAD_LOCKFREE_HASH_MAP_HPP_
25 
26 #include "lock_free.h" // old implementation
27 #include "lockfree_hashmap.hpp"
29 #include "system_parameter.h"
30 #include "thread_entry.hpp"
31 
32 namespace cubthread
33 {
34  template <class Key, class T>
36  {
37  public:
39 
40  class iterator;
41 
42  void init (lf_tran_system &transys, int entry_idx, int hash_size, int freelist_block_size,
43  int freelist_block_count, lf_entry_descriptor &edesc);
44 
45  void init_as_old (lf_tran_system &transys, int hash_size, int freelist_block_count, int freelist_block_size,
46  lf_entry_descriptor &edesc, int entry_idx);
47  void init_as_new (lockfree::tran::system &transys, size_t hash_size, size_t freelist_block_size,
48  size_t freelist_block_count, lf_entry_descriptor &edesc);
49  void destroy ();
50 
51  T *find (cubthread::entry *thread_p, Key &key);
52  bool find_or_insert (cubthread::entry *thread_p, Key &key, T *&t);
53  bool insert (cubthread::entry *thread_p, Key &key, T *&t);
54  bool insert_given (cubthread::entry *thread_p, Key &key, T *&t);
55  bool erase (cubthread::entry *thread_p, Key &key);
56  bool erase_locked (cubthread::entry *thread_p, Key &key, T *&t);
57 
58  void unlock (cubthread::entry *thread_p, T *&t);
59 
60  void clear (cubthread::entry *thread_p); // NOT LOCK-FREE
61 
62  T *freelist_claim (cubthread::entry *thread_p);
63  void freelist_retire (cubthread::entry *thread_p, T *&t);
64 
65  void start_tran (cubthread::entry *thread_p);
66  void end_tran (cubthread::entry *thread_p);
67 
68  size_t get_size () const;
69  size_t get_element_count () const;
70 
71  private:
72  bool is_old_type () const;
74 
75  enum type
76  {
77  OLD,
78  NEW,
80  };
81 
86  };
87 
88  template <class Key, class T>
89  class lockfree_hashmap<Key, T>::iterator
90  {
91  public:
92  iterator (cubthread::entry *thread_p, lockfree_hashmap &map);
93  ~iterator () = default;
94 
95  T *iterate ();
96 
97  void restart ();
98 
99  private:
100  // old stuff
104  };
105 
107 } // namespace cubthread
108 
109 //
110 // implementation
111 //
112 
113 namespace cubthread
114 {
115  //
116  // lockfree_hashmap
117  //
118  template <class Key, class T>
120  : m_old_hash {}
121  , m_new_hash {}
122  , m_type (UNKNOWN)
123  {
124  }
125 
126  template <class Key, class T>
127  void
128  lockfree_hashmap<Key, T>::init (lf_tran_system &transys, int entry_idx, int hash_size, int freelist_block_size,
129  int freelist_block_count, lf_entry_descriptor &edesc)
130  {
132  {
133  init_as_new (get_thread_entry_lftransys (), (size_t) hash_size, (size_t) freelist_block_size,
134  (size_t) freelist_block_count, edesc);
135  }
136  else
137  {
138  init_as_old (transys, hash_size, freelist_block_count, freelist_block_size, edesc, entry_idx);
139  }
140  }
141 
142  template <class Key, class T>
143  void
144  lockfree_hashmap<Key, T>::init_as_old (lf_tran_system &transys, int hash_size, int freelist_block_count,
145  int freelist_block_size, lf_entry_descriptor &edesc, int entry_idx)
146  {
147  m_type = OLD;
148  m_old_hash.init (transys, hash_size, freelist_block_count, freelist_block_size, edesc);
149  m_entry_idx = entry_idx;
150  }
151 
152  template <class Key, class T>
153  void
154  lockfree_hashmap<Key, T>::init_as_new (lockfree::tran::system &transys, size_t hash_size, size_t freelist_block_size,
155  size_t freelist_block_count, lf_entry_descriptor &edesc)
156  {
157  m_type = NEW;
158  m_new_hash.init (transys, hash_size, freelist_block_size, freelist_block_count, edesc);
159  }
160 
161 #define lockfree_hashmap_forward_func(f_, tp_, ...) \
162  is_old_type () ? \
163  m_old_hash.f_ (get_tran_entry (tp_), __VA_ARGS__) : \
164  m_new_hash.f_ ((tp_)->get_lf_tran_index (), __VA_ARGS__)
165 #define lockfree_hashmap_forward_func_noarg(f_, tp_) \
166  is_old_type () ? \
167  m_old_hash.f_ (get_tran_entry (tp_)) : \
168  m_new_hash.f_ ((tp_)->get_lf_tran_index ())
169 
170  template <class Key, class T>
171  void
173  {
174  if (m_type == UNKNOWN)
175  {
176  // was not initialized
177  return;
178  }
179  if (is_old_type ())
180  {
181  m_old_hash.destroy ();
182  }
183  else
184  {
185  m_new_hash.destroy ();
186  }
187  }
188 
189  template <class Key, class T>
190  T *
192  {
193  return lockfree_hashmap_forward_func (find, thread_p, key);
194  }
195 
196  template <class Key, class T>
197  bool
199  {
200  return lockfree_hashmap_forward_func (find_or_insert, thread_p, key, t);
201  }
202 
203  template <class Key, class T>
204  bool
206  {
207  return lockfree_hashmap_forward_func (insert, thread_p, key, t);
208  }
209 
210  template <class Key, class T>
211  bool
213  {
214  return lockfree_hashmap_forward_func (insert_given, thread_p, key, t);
215  }
216 
217  template <class Key, class T>
218  bool
220  {
221  return lockfree_hashmap_forward_func (erase, thread_p, key);
222  }
223 
224  template <class Key, class T>
225  bool
227  {
228  return lockfree_hashmap_forward_func (erase_locked, thread_p, key, t);
229  }
230 
231  template <class Key, class T>
232  void
234  {
235  lockfree_hashmap_forward_func (unlock, thread_p, t);
236  }
237 
238  template <class Key, class T>
239  void
241  {
243  }
244 
245  template <class Key, class T>
246  T *
248  {
250  }
251 
252  template <class Key, class T>
253  void
255  {
257  }
258 
259  template <class Key, class T>
260  void
262  {
264  }
265 
266  template <class Key, class T>
267  void
269  {
271  }
272 
273  template <class Key, class T>
274  size_t
276  {
277  return is_old_type () ? m_old_hash.get_size () : m_new_hash.get_size ();
278  }
279 
280  template <class Key, class T>
281  size_t
283  {
284  return is_old_type () ? m_old_hash.get_element_count () : m_new_hash.get_element_count ();
285  }
286 
287 #undef lockfree_hashmap_forward_func
288 #undef lockfree_hashmap_forward_func_noarg
289 
290  template <class Key, class T>
291  bool
293  {
294  assert (m_type == OLD || m_type == NEW);
295  return m_type == OLD;
296  }
297 
298  template <class Key, class T>
299  lf_tran_entry *
301  {
302  return thread_p->tran_entries[m_entry_idx];
303  }
304 
305  //
306  // lockfree_hashmap::iterator
307  //
308  template <class Key, class T>
310  : m_map (map)
311  , m_old_iter ()
312  , m_new_iter ()
313  {
314  if (m_map.is_old_type ())
315  {
316  m_old_iter = { m_map.get_tran_entry (thread_p), m_map.m_old_hash };
317  }
318  else
319  {
320  m_new_iter = { thread_p->get_lf_tran_index (), m_map.m_new_hash };
321  }
322  }
323 
324  template <class Key, class T>
325  T *
327  {
328  if (m_map.is_old_type ())
329  {
330  return m_old_iter.iterate ();
331  }
332  else
333  {
334  return m_new_iter.iterate ();
335  }
336  }
337 
338  template <class Key, class T>
339  void
341  {
342  if (m_map.is_old_type ())
343  {
344  m_old_iter.restart ();
345  }
346  else
347  {
348  m_new_iter.restart ();
349  }
350  }
351 }
352 
353 #endif // !_THREAD_LOCKFREE_HASH_MAP_HPP_
lockfree::tran::system & get_thread_entry_lftransys()
lf_tran_entry * tran_entries[THREAD_TS_COUNT]
void unlock(cubthread::entry *thread_p, T *&t)
lf_tran_entry * get_tran_entry(cubthread::entry *thread_p)
Definition: lock_free.h:63
Definition: lock_free.h:120
void init_as_new(lockfree::tran::system &transys, size_t hash_size, size_t freelist_block_size, size_t freelist_block_count, lf_entry_descriptor &edesc)
lf_hash_table_cpp< Key, T >::iterator m_old_iter
T * freelist_claim(cubthread::entry *thread_p)
bool erase(cubthread::entry *thread_p, Key &key)
#define lockfree_hashmap_forward_func(f_, tp_,...)
bool find_or_insert(cubthread::entry *thread_p, Key &key, T *&t)
#define assert(x)
void end_tran(cubthread::entry *thread_p)
T * find(cubthread::entry *thread_p, Key &key)
void freelist_retire(cubthread::entry *thread_p, T *&t)
bool erase_locked(cubthread::entry *thread_p, Key &key, T *&t)
bool insert(cubthread::entry *thread_p, Key &key, T *&t)
lockfree::tran::index get_lf_tran_index()
bool insert_given(cubthread::entry *thread_p, Key &key, T *&t)
void init(lf_tran_system &transys, int entry_idx, int hash_size, int freelist_block_size, int freelist_block_count, lf_entry_descriptor &edesc)
lf_hash_table_cpp< Key, T > m_old_hash
lockfree::hashmap< Key, T > m_new_hash
#define lockfree_hashmap_forward_func_noarg(f_, tp_)
iterator(cubthread::entry *thread_p, lockfree_hashmap &map)
lockfree::hashmap< Key, T >::iterator m_new_iter
bool prm_get_bool_value(PARAM_ID prm_id)
void clear(cubthread::entry *thread_p)
void init_as_old(lf_tran_system &transys, int hash_size, int freelist_block_count, int freelist_block_size, lf_entry_descriptor &edesc, int entry_idx)
void start_tran(cubthread::entry *thread_p)