MiniOB 1
MiniOB is one mini database, helping developers to learn how database works.
载入中...
搜索中...
未找到
ob_skiplist.h
1/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2miniob is licensed under Mulan PSL v2.
3You can use this software according to the terms and conditions of the Mulan PSL v2.
4You may obtain a copy of Mulan PSL v2 at:
5 http://license.coscl.org.cn/MulanPSL2
6THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9See the Mulan PSL v2 for more details. */
10
11// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
12// Use of this source code is governed by a BSD-style license that can be
13// found in the LICENSE file. See the AUTHORS file for names of contributors.
14
15#pragma once
16
17// Thread safety
18// -------------
19//
20// Writes require external synchronization, most likely a mutex.
21// Reads require a guarantee that the ObSkipList will not be destroyed
22// while the read is in progress. Apart from that, reads progress
23// without any internal locking or synchronization.
24//
25// Invariants:
26//
27// (1) Allocated nodes are never deleted until the ObSkipList is
28// destroyed. This is trivially guaranteed by the code since we
29// never delete any skip list nodes.
30//
31// (2) The contents of a Node except for the next/prev pointers are
32// immutable after the Node has been linked into the ObSkipList.
33// Only insert() modifies the list, and it is careful to initialize
34// a node and use release-stores to publish the nodes in one or
35// more lists.
36//
37// ... prev vs. next pointer ordering ...
38
39#include "common/math/random_generator.h"
40#include "common/lang/atomic.h"
41#include "common/lang/vector.h"
42#include "common/log/log.h"
43
44namespace oceanbase {
45
46template <typename Key, class ObComparator>
48{
49private:
50 struct Node;
51
52public:
56 explicit ObSkipList(ObComparator cmp);
57
58 ObSkipList(const ObSkipList &) = delete;
59 ObSkipList &operator=(const ObSkipList &) = delete;
61
66 void insert(const Key &key);
67
68 void insert_concurrently(const Key &key);
69
75 bool contains(const Key &key) const;
76
81 {
82 public:
87 explicit Iterator(const ObSkipList *list);
88
92 bool valid() const;
93
98 const Key &key() const;
99
104 void next();
105
110 void prev();
111
115 void seek(const Key &target);
116
122
128
129 private:
130 const ObSkipList *list_;
131 Node *node_;
132 };
133
134private:
135 enum
136 {
137 kMaxHeight = 12
138 };
139
140 inline int get_max_height() const { return max_height_.load(std::memory_order_relaxed); }
141
142 Node *new_node(const Key &key, int height);
143 int random_height();
144 bool equal(const Key &a, const Key &b) const { return (compare_(a, b) == 0); }
145
146 // Return the earliest node that comes at or after key.
147 // Return nullptr if there is no such node.
148 //
149 // If prev is non-null, fills prev[level] with pointer to previous
150 // node at "level" for every level in [0..max_height_-1].
151 Node *find_greater_or_equal(const Key &key, Node **prev) const;
152
153 // Return the latest node with a key < key.
154 // Return head_ if there is no such node.
155 Node *find_less_than(const Key &key) const;
156
157 // Return the last node in the list.
158 // Return head_ if list is empty.
159 Node *find_last() const;
160
161 // Immutable after construction
162 ObComparator const compare_;
163
164 Node *const head_;
165
166 // Modified only by insert(). Read racily by readers, but stale
167 // values are ok.
168 atomic<int> max_height_; // Height of the entire list
169
170 static common::RandomGenerator rnd;
171};
172
173template <typename Key, class ObComparator>
174common::RandomGenerator ObSkipList<Key, ObComparator>::rnd = common::RandomGenerator();
175
176// Implementation details follow
177template <typename Key, class ObComparator>
179{
180 explicit Node(const Key &k) : key(k) {}
181
182 Key const key;
183
184 // Accessors/mutators for links. Wrapped in methods so we can
185 // add the appropriate barriers as necessary.
186 Node *next(int n)
187 {
188 ASSERT(n >= 0, "n >= 0");
189 // Use an 'acquire load' so that we observe a fully initialized
190 // version of the returned Node.
191 return next_[n].load(std::memory_order_acquire);
192 }
193 void set_next(int n, Node *x)
194 {
195 ASSERT(n >= 0, "n >= 0");
196 // Use a 'release store' so that anybody who reads through this
197 // pointer observes a fully initialized version of the inserted node.
198 next_[n].store(x, std::memory_order_release);
199 }
200
201 // No-barrier variants that can be safely used in a few locations.
202 Node *nobarrier_next(int n)
203 {
204 ASSERT(n >= 0, "n >= 0");
205 return next_[n].load(std::memory_order_relaxed);
206 }
207 void nobarrier_set_next(int n, Node *x)
208 {
209 ASSERT(n >= 0, "n >= 0");
210 next_[n].store(x, std::memory_order_relaxed);
211 }
212
213 bool cas_next(int n, Node *expected, Node *x)
214 {
215 ASSERT(n >= 0, "n >= 0");
216 return next_[n].compare_exchange_strong(expected, x);
217 }
218
219private:
220 // Array of length equal to the node height. next_[0] is lowest level link.
221 atomic<Node *> next_[1];
222};
223
224template <typename Key, class ObComparator>
226{
227 char *const node_memory = reinterpret_cast<char *>(malloc(sizeof(Node) + sizeof(atomic<Node *>) * (height - 1)));
228 return new (node_memory) Node(key);
229}
230
231template <typename Key, class ObComparator>
233{
234 list_ = list;
235 node_ = nullptr;
236}
237
238template <typename Key, class ObComparator>
240{
241 return node_ != nullptr;
242}
243
244template <typename Key, class ObComparator>
246{
247 ASSERT(valid(), "valid");
248 return node_->key;
249}
250
251template <typename Key, class ObComparator>
253{
254 ASSERT(valid(), "valid");
255 node_ = node_->next(0);
256}
257
258template <typename Key, class ObComparator>
260{
261 // Instead of using explicit "prev" links, we just search for the
262 // last node that falls before key.
263 ASSERT(valid(), "valid");
264 node_ = list_->find_less_than(node_->key);
265 if (node_ == list_->head_) {
266 node_ = nullptr;
267 }
268}
269
270template <typename Key, class ObComparator>
272{
273 node_ = list_->find_greater_or_equal(target, nullptr);
274}
275
276template <typename Key, class ObComparator>
278{
279 node_ = list_->head_->next(0);
280}
281
282template <typename Key, class ObComparator>
284{
285 node_ = list_->find_last();
286 if (node_ == list_->head_) {
287 node_ = nullptr;
288 }
289}
290
291template <typename Key, class ObComparator>
293{
294 // Increase height with probability 1 in kBranching
295 static const unsigned int kBranching = 4;
296 int height = 1;
297 while (height < kMaxHeight && rnd.next(kBranching) == 0) {
298 height++;
299 }
300 ASSERT(height > 0, "height > 0");
301 ASSERT(height <= kMaxHeight, "height <= kMaxHeight");
302 return height;
303}
304
305template <typename Key, class ObComparator>
306typename ObSkipList<Key, ObComparator>::Node *ObSkipList<Key, ObComparator>::find_greater_or_equal(
307 const Key &key, Node **prev) const
308{
309 // your code here
310 return nullptr;
311}
312
313template <typename Key, class ObComparator>
314typename ObSkipList<Key, ObComparator>::Node *ObSkipList<Key, ObComparator>::find_less_than(const Key &key) const
315{
316 Node *x = head_;
317 int level = get_max_height() - 1;
318 while (true) {
319 ASSERT(x == head_ || compare_(x->key, key) < 0, "x == head_ || compare_(x->key, key) < 0");
320 Node *next = x->next(level);
321 if (next == nullptr || compare_(next->key, key) >= 0) {
322 if (level == 0) {
323 return x;
324 } else {
325 // Switch to next list
326 level--;
327 }
328 } else {
329 x = next;
330 }
331 }
332}
333
334template <typename Key, class ObComparator>
335typename ObSkipList<Key, ObComparator>::Node *ObSkipList<Key, ObComparator>::find_last() const
336{
337 Node *x = head_;
338 int level = get_max_height() - 1;
339 while (true) {
340 Node *next = x->next(level);
341 if (next == nullptr) {
342 if (level == 0) {
343 return x;
344 } else {
345 // Switch to next list
346 level--;
347 }
348 } else {
349 x = next;
350 }
351 }
352}
353
354template <typename Key, class ObComparator>
356 : compare_(cmp), head_(new_node(0 /* any key will do */, kMaxHeight)), max_height_(1)
357{
358 for (int i = 0; i < kMaxHeight; i++) {
359 head_->set_next(i, nullptr);
360 }
361}
362
363template <typename Key, class ObComparator>
365{
366 typename std::vector<Node *> nodes;
367 nodes.reserve(max_height_.load(std::memory_order_relaxed));
368 for (Node *x = head_; x != nullptr; x = x->next(0)) {
369 nodes.push_back(x);
370 }
371 for (auto node : nodes) {
372 node->~Node();
373 free(node);
374 }
375}
376
377template <typename Key, class ObComparator>
379{}
380
381template <typename Key, class ObComparator>
383{
384 // your code here
385}
386
387template <typename Key, class ObComparator>
389{
390 Node *x = find_greater_or_equal(key, nullptr);
391 if (x != nullptr && equal(key, x->key)) {
392 return true;
393 } else {
394 return false;
395 }
396}
397
398} // namespace oceanbase
Definition: random_generator.h:25
base class of all comparators
Definition: ob_comparator.h:21
Iteration over the contents of a skip list
Definition: ob_skiplist.h:81
void seek_to_last()
Position at the last entry in list.
Definition: ob_skiplist.h:283
void seek(const Key &target)
Advance to the first entry with a key >= target
Definition: ob_skiplist.h:271
void next()
Advance to the next entry in the list. REQUIRES: valid()
Definition: ob_skiplist.h:252
const Key & key() const
Returns the key at the current position. REQUIRES: valid()
Definition: ob_skiplist.h:245
Iterator(const ObSkipList *list)
Initialize an iterator over the specified list.
Definition: ob_skiplist.h:232
void seek_to_first()
Position at the first entry in list.
Definition: ob_skiplist.h:277
void prev()
Advances to the previous position. REQUIRES: valid()
Definition: ob_skiplist.h:259
bool valid() const
Returns true iff the iterator is positioned at a valid node.
Definition: ob_skiplist.h:239
Definition: ob_skiplist.h:48
ObSkipList(ObComparator cmp)
Create a new ObSkipList object that will use "cmp" for comparing keys.
Definition: ob_skiplist.h:355
bool contains(const Key &key) const
Returns true if an entry that compares equal to key is in the list.
Definition: ob_skiplist.h:388
void insert(const Key &key)
Insert key into the list. REQUIRES: nothing that compares equal to key is currently in the list
Definition: ob_skiplist.h:378
Definition: cas.cpp:24
Definition: ob_skiplist.h:179