Zero  0.1.0
w_okvl_inl.h
Go to the documentation of this file.
1 /*
2  * (c) Copyright 2013-, Hewlett-Packard Development Company, LP
3  */
4 #ifndef __W_OKVL_INL_H
5 #define __W_OKVL_INL_H
6 
12 #include "w_okvl.h"
13 #include <ostream>
14 
16 const char* const element_mode_names[] = {
17  "N", "IS", "IX", "S", "SIX", "X"
18 };
19 
28 
30 
32 
34 
36 
38 
40 
42 
44 
45 #define T true // to make following easier to read
46 #define F false
47 
53 /*req*/ //N IS IX S SIX X (granted)
54 /*N */ {T, T, T, T, T, T,},
55 /*IS*/
56  {T, T, T, T, T, F,},
57 /*IX*/
58  {T, T, T, F, F, F,},
59 /*S */
60  {T, T, F, T, F, F,},
61 /*SIX*/
62  {T, T, F, F, F, F,},
63 /*X */
64  {T, F, F, F, F, F,},
65 };
66 
72 /*left*/ //N IS IX S SIX X (right)
73 /*N */ {T, T, T, T, T, T,},
74 /*IS*/
75  {F, T, T, T, T, T,},
76 /*IX*/
77  {F, F, T, F, T, T,},
78 /*S */
79  {F, F, F, T, T, T,},
80 /*SIX*/
81  {F, F, F, F, T, T,},
82 /*X */
83  {F, F, F, F, F, T,},
84 };
85 
86 #undef T
87 #undef F
88 
94  okvl_mode::N, // N
95  okvl_mode::IS, // IS
96  okvl_mode::IX, // IX
97  okvl_mode::IS, // S
98  okvl_mode::IX, // SIX
99  okvl_mode::IX // X
100 };
101 
108 /*req*/ //N IS IX S SIX X (granted)
110 /*IS*/
112 /*IX*/
114 /*S */
116 /*SIX*/
118 /*X */
120 };
121 
123  element_lock_mode requested,
124  element_lock_mode granted) {
125  return compatibility_table[requested][granted];
126 }
127 
129  element_lock_mode left,
130  element_lock_mode right) {
131  return implication_table[left][right];
132 }
133 
135  clear();
136 }
137 
138 inline okvl_mode::okvl_mode(const okvl_mode& r) {
139  ::memcpy(modes, r.modes, OKVL_MODE_COUNT);
140 }
141 
143  ::memcpy(modes, r.modes, OKVL_MODE_COUNT);
144  return *this;
145 }
146 
148  clear();
149  if (key_mode != N) {
150  set_key_mode(key_mode);
151  }
152  if (gap_mode != N) {
153  set_gap_mode(gap_mode);
154  }
155 }
156 
157 inline okvl_mode::okvl_mode(part_id part, element_lock_mode partition_mode) {
158  clear();
159  set_partition_mode(part, partition_mode);
160 }
161 
163  return (element_lock_mode)modes[partition];
164 }
165 
168 }
169 
172 }
173 
174 inline bool okvl_mode::is_empty() const {
175  // because individual partition mode should leave an intent mode on key,
176  // we can just check the key and gap.
177  return (get_key_mode() == N && get_gap_mode() == N);
178 }
179 
180 inline bool okvl_mode::is_keylock_empty() const {
181  // same as above
182  return (get_key_mode() == N);
183 }
184 
186  // If the key mode doesn't contain IS/IX, all individual partitions must be empty.
187  return (get_key_mode() == N || get_key_mode() == S || get_key_mode() == X);
188 }
189 
190 inline bool okvl_mode::_can_batch64(part_id part) {
191  return (OKVL_PARTITIONS - part >= WORD_SIZE && part % WORD_SIZE == 0);
192 }
193 
194 inline uint64_t okvl_mode::_get_batch64(part_id part) const {
195  return reinterpret_cast<const uint64_t*>(modes)[part / WORD_SIZE];
196 }
197 
198 inline uint64_t& okvl_mode::_get_batch64_ref(part_id part) {
199  return reinterpret_cast<uint64_t*>(modes)[part / WORD_SIZE];
200 }
201 
202 inline bool okvl_mode::contains_dirty_lock() const {
203  bool ret = contains_dirty_key_lock();
204 
205  // If no X lock on key, check gap
206  if (false == ret) {
207  return (X == get_gap_mode());
208  }
209 
210  return ret;
211 }
212 
214  if (get_key_mode() == X) {
215  return true;
216  } else if (get_key_mode() == IX || get_key_mode() == SIX) {
217  // same above. They should have left IX in key.
218  // so, we check individual partitions only in that case.
219  for (part_id part = 0; part < OKVL_PARTITIONS; ++part) {
220  if (_can_batch64(part) && _get_batch64(part) == 0) {
221  part += sizeof(uint64_t) - 1; // skip bunch of zeros
222  continue;
223  } else if (get_partition_mode(part) == X) {
224  return true;
225  }
226  }
227  }
228  return false;
229 }
230 
232  modes[partition] = (unsigned char)mode;
233 
234  // also set the intent mode to key
235  element_lock_mode parent_mode = parent_lock_mode[mode];
237 }
238 
240  modes[OKVL_PARTITIONS] = mode;
241 }
242 
244  modes[OKVL_PARTITIONS + 1] = mode;
245 }
246 
247 inline void okvl_mode::clear() {
248  ::memset(modes, 0, sizeof(okvl_mode));
249 }
250 
252  const okvl_mode& requested) const {
253  return okvl_mode::is_compatible(requested, *this);
254 }
255 
257  const okvl_mode& granted) const {
258  return okvl_mode::is_compatible(*this, granted);
259 }
260 
262  const okvl_mode& requested,
263  const okvl_mode& granted) {
264  // So far we use a straightforward for loop to check.
265  // When k is small, we might want to apply some optimization,
266  // but let's consider it later. Most likely this is not the major bottleneck.
267 
268  // 0. obvious optimization.
269  if (requested.is_empty() || granted.is_empty()) {
270  return true;
271  }
272 
273  // 1. check gap. gap is totally orthogonal to any others, so this is it.
274  if (!is_compatible_element(requested.get_gap_mode(), granted.get_gap_mode())) {
275  return false;
276  }
277 
278  // 2. check key of the request.
279  // this is only key vs. key, just like intent lock mode compatibility.
280  if (!is_compatible_element(requested.get_key_mode(), granted.get_key_mode())) {
281  return false;
282  }
283 
284  // 3. check individual partitions of the request.
285  if (!requested.is_keylock_partition_empty() && !granted.is_keylock_partition_empty()) {
286  for (part_id part = 0; part < OKVL_PARTITIONS; ++part) {
287  if (_can_batch64(part)) {
288  uint64_t requested_batch = requested._get_batch64(part);
289  uint64_t granted_batch = granted._get_batch64(part);
290  if (requested_batch == 0 || granted_batch == 0) {
291  part += WORD_SIZE - 1; // skip bunch of zeros
292  continue;
293  }
294  }
295  element_lock_mode req = requested.get_partition_mode(part);
296  if (!is_compatible_element(req, granted.get_partition_mode(part))) {
297  return false;
298  }
299  }
300  }
301 
302  return true;
303 }
304 
305 inline bool okvl_mode::is_implied_by(const okvl_mode& superset) const {
306  // obvious case
307  element_lock_mode this_gap = get_gap_mode();
308  element_lock_mode this_key = get_key_mode();
309  element_lock_mode superset_gap = superset.get_gap_mode();
310  element_lock_mode superset_key = superset.get_key_mode();
311  if (!is_implied_by_element(this_gap, superset_gap)
312  || !is_implied_by_element(this_key, superset_key)) {
313  return false;
314  }
315 
316  // check individual partitions.
318  for (part_id part = 0; part < OKVL_PARTITIONS; ++part) {
319  if (_can_batch64(part)) {
320  uint64_t this_batch = _get_batch64(part);
321  uint64_t superset_batch = superset._get_batch64(part);
322  if (this_batch == 0 || this_batch == superset_batch) {
323  part += WORD_SIZE - 1; // skip bunch of zeros or exactly same locks
324  continue;
325  }
326  }
327  if (!is_implied_by_element(get_partition_mode(part), superset.get_partition_mode(part))) {
328  return false;
329  }
330  }
331  }
332 
333  return true;
334 }
335 
336 inline okvl_mode::part_id okvl_mode::compute_part_id(const void* uniquefier, int uniquefier_length) {
337  const uint32_t HASH_SEED_32 = 0x35D0B891;
338  const unsigned char HASH_SEED_8 = 0xDB;
339  const int W = sizeof(uint32_t);
340  uint64_t hash = 0;
341  for (int word = 0; word < uniquefier_length / W; ++word) {
342  hash = (hash * HASH_SEED_32) + reinterpret_cast<const uint32_t*>(uniquefier)[word];
343  }
344 
345  for (int remaining = uniquefier_length / W * W; remaining < uniquefier_length; ++remaining) {
346  hash = (hash * HASH_SEED_8) + reinterpret_cast<const unsigned char*>(uniquefier)[remaining];
347  }
348 
349  // so far simply mod on hash. mod/div is expensive, but probably not an issue.
350  return (okvl_mode::part_id)(hash % OKVL_PARTITIONS);
351 }
352 
353 inline okvl_mode okvl_mode::combine(const okvl_mode& left, const okvl_mode& right) {
354  // trivial optimization.
355  // if either one has no individual partition mode, no need to combine them.
356  if (left.is_keylock_partition_empty()) {
357  okvl_mode ret(right);
360  return ret;
361  } else if (right.is_keylock_partition_empty()) {
362  okvl_mode ret(left);
365  return ret;
366  }
367 
368  okvl_mode ret;
369  for (part_id part = 0; part < OKVL_PARTITIONS; ++part) {
370  if (OKVL_PARTITIONS - part >= WORD_SIZE && part % WORD_SIZE == 0) {
371  uint64_t left_batch = left._get_batch64(part);
372  uint64_t right_batch = right._get_batch64(part);
373  if (left_batch == 0 || right_batch == 0 || left_batch == right_batch) {
374  uint64_t result_batch = 0;
375  if (left_batch == 0) {
376  result_batch = right_batch;
377  } else if (right_batch == 0) {
378  // this means right_batch == 0 or left_batch == right_batch
379  // in either case:
380  result_batch = left_batch;
381  }
382  // batch-process bunch of zeros or exactly same locks
383  ret._get_batch64_ref(part) = result_batch;
384  part += WORD_SIZE - 1;
385  continue;
386  }
387  }
388  // here, we do not use set_partition_mode() to skip setting the intent modes on key.
389  // as far as both left and right are in consistent state, just combining key alone is enough.
390  ret.modes[part] = (unsigned char)combined_lock_modes[left.get_partition_mode(part)][right.get_partition_mode(
391  part)];
392  }
395  return ret;
396 }
397 
398 inline bool okvl_mode::operator==(const okvl_mode& r) const {
399  if (this == &r) {
400  return true; // quick check in case this and r are the same object.
401  } else if (get_key_mode() != r.get_key_mode()
402  || get_gap_mode() != r.get_gap_mode()) {
403  // another quick check.
404  return false;
406  // then, if individual partitions are both empty, we are done.
407  return true;
408  }
409  return ::memcmp(modes, r.modes, OKVL_PARTITIONS) == 0;
410 }
411 
412 inline bool okvl_mode::operator!=(const okvl_mode& r) const {
413  return !(operator==(r));
414 }
415 
416 inline std::ostream& operator<<(std::ostream& o, const okvl_mode& v) {
417  if (v.is_empty()) {
418  o << "<Empty>";
419  } else {
420  for (okvl_mode::part_id part = 0; part < OKVL_PARTITIONS; ++part) {
421  if (v.get_partition_mode(part) != okvl_mode::N) {
422  o << "<key_" << part << "=" << element_mode_names[v.get_partition_mode(part)] << ">,";
423  }
424  }
425  if (v.get_key_mode() != okvl_mode::N) {
426  o << "<key_*=" << element_mode_names[v.get_key_mode()] << ">,";
427  }
428  if (v.get_gap_mode() != okvl_mode::N) {
429  o << "<gap=" << element_mode_names[v.get_gap_mode()] << ">";
430  }
431  }
432  return o;
433 }
434 
435 #endif // __W_OKVL_INL_H
std::ostream & operator<<(std::ostream &o, const okvl_mode &v)
Definition: w_okvl_inl.h:416
element_lock_mode get_gap_mode() const
Definition: w_okvl_inl.h:170
void set_key_mode(element_lock_mode mode)
Definition: w_okvl_inl.h:239
unsigned char modes[OKVL_MODE_COUNT]
Definition: w_okvl.h:122
void set_partition_mode(part_id partition, element_lock_mode mode)
Definition: w_okvl_inl.h:231
const okvl_mode ALL_X_GAP_X(okvl_mode::X, okvl_mode::X)
bool operator==(const okvl_mode &r) const
Definition: w_okvl_inl.h:398
const bool implication_table[okvl_mode::COUNT][okvl_mode::COUNT]
Definition: w_okvl_inl.h:71
uint64_t & _get_batch64_ref(part_id part)
Definition: w_okvl_inl.h:198
bool is_compatible_request(const okvl_mode &requested) const
Definition: w_okvl_inl.h:251
Definition: w_okvl.h:113
bool is_empty() const
Definition: w_okvl_inl.h:174
static bool is_implied_by_element(element_lock_mode left, element_lock_mode right)
Definition: w_okvl_inl.h:128
element_lock_mode get_key_mode() const
Definition: w_okvl_inl.h:166
#define F
Definition: w_okvl_inl.h:46
Definition: w_okvl.h:112
const bool compatibility_table[okvl_mode::COUNT][okvl_mode::COUNT]
Definition: w_okvl_inl.h:52
static bool is_compatible(const okvl_mode &requested, const okvl_mode &granted)
Definition: w_okvl_inl.h:261
element_lock_mode
Lock mode for one OKVL component (key, partition, or gap).
Definition: w_okvl.h:107
static bool is_compatible_element(element_lock_mode requested, element_lock_mode granted)
Definition: w_okvl_inl.h:122
const okvl_mode ALL_S_GAP_S(okvl_mode::S, okvl_mode::S)
bool contains_dirty_lock() const
Returns whether this contains any lock mode that implies data update directly in the resource this lo...
Definition: w_okvl_inl.h:202
const uint32_t OKVL_MODE_COUNT
Definition: w_okvl.h:84
void clear()
Definition: w_okvl_inl.h:247
const char *const element_mode_names[]
Definition: w_okvl_inl.h:16
bool is_keylock_empty() const
Definition: w_okvl_inl.h:180
Definition: w_okvl.h:108
bool is_implied_by(const okvl_mode &superset) const
Definition: w_okvl_inl.h:305
const okvl_mode ALL_S_GAP_N(okvl_mode::S, okvl_mode::N)
uint16_t part_id
Definition: w_okvl.h:97
element_lock_mode get_partition_mode(part_id partition) const
Definition: w_okvl_inl.h:162
const okvl_mode ALL_X_GAP_N(okvl_mode::X, okvl_mode::N)
const okvl_mode ALL_S_GAP_X(okvl_mode::S, okvl_mode::X)
okvl_mode()
Definition: w_okvl_inl.h:134
okvl_mode & operator=(const okvl_mode &r)
Definition: w_okvl_inl.h:142
bool is_keylock_partition_empty() const
Definition: w_okvl_inl.h:185
const okvl_mode ALL_N_GAP_S(okvl_mode::N, okvl_mode::S)
Represents a lock mode of one key entry in the OKVL lock manager.
Definition: w_okvl.h:95
const okvl_mode::element_lock_mode parent_lock_mode[]
Definition: w_okvl_inl.h:93
uint64_t _get_batch64(part_id part) const
Definition: w_okvl_inl.h:194
bool is_compatible_grant(const okvl_mode &granted) const
Definition: w_okvl_inl.h:256
static okvl_mode combine(const okvl_mode &left, const okvl_mode &right)
Definition: w_okvl_inl.h:353
bool contains_dirty_key_lock() const
Definition: w_okvl_inl.h:213
Definition: w_okvl.h:109
Definition: w_okvl.h:114
static bool _can_batch64(part_id part)
Definition: w_okvl_inl.h:190
const uint32_t OKVL_PARTITIONS
The number of partitions in OKVL.
Definition: w_okvl.h:78
Definition: w_okvl.h:110
bool operator!=(const okvl_mode &r) const
Definition: w_okvl_inl.h:412
static part_id compute_part_id(const void *uniquefier, int uniquefier_length)
Definition: w_okvl_inl.h:336
const okvl_mode::element_lock_mode combined_lock_modes[okvl_mode::COUNT][okvl_mode::COUNT]
Definition: w_okvl_inl.h:107
const okvl_mode ALL_N_GAP_X(okvl_mode::N, okvl_mode::X)
const okvl_mode ALL_N_GAP_N(okvl_mode::N, okvl_mode::N)
Pre-defines frequently used lock modes as const objects.
void set_gap_mode(element_lock_mode mode)
Definition: w_okvl_inl.h:243
Definition: w_okvl.h:226
#define T
Definition: w_okvl_inl.h:45
Definition: w_okvl.h:111
const okvl_mode ALL_X_GAP_S(okvl_mode::X, okvl_mode::S)