10225501448 李度 10225101546 陈胤遒 10215501422 高宇菲
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
11 KiB

1 month ago
Release 1.18 Changes are: * Update version number to 1.18 * Replace the basic fprintf call with a call to fwrite in order to work around the apparent compiler optimization/rewrite failure that we are seeing with the new toolchain/iOS SDKs provided with Xcode6 and iOS8. * Fix ALL the header guards. * Createed a README.md with the LevelDB project description. * A new CONTRIBUTING file. * Don't implicitly convert uint64_t to size_t or int. Either preserve it as uint64_t, or explicitly cast. This fixes MSVC warnings about possible value truncation when compiling this code in Chromium. * Added a DumpFile() library function that encapsulates the guts of the "leveldbutil dump" command. This will allow clients to dump data to their log files instead of stdout. It will also allow clients to supply their own environment. * leveldb: Remove unused function 'ConsumeChar'. * leveldbutil: Remove unused member variables from WriteBatchItemPrinter. * OpenBSD, NetBSD and DragonflyBSD have _LITTLE_ENDIAN, so define PLATFORM_IS_LITTLE_ENDIAN like on FreeBSD. This fixes: * issue #143 * issue #198 * issue #249 * Switch from <cstdatomic> to <atomic>. The former never made it into the standard and doesn't exist in modern gcc versions at all. The later contains everything that leveldb was using from the former. This problem was noticed when porting to Portable Native Client where no memory barrier is defined. The fact that <cstdatomic> is missing normally goes unnoticed since memory barriers are defined for most architectures. * Make Hash() treat its input as unsigned. Before this change LevelDB files from platforms with different signedness of char were not compatible. This change fixes: issue #243 * Verify checksums of index/meta/filter blocks when paranoid_checks set. * Invoke all tools for iOS with xcrun. (This was causing problems with the new XCode 5.1.1 image on pulse.) * include <sys/stat.h> only once, and fix the following linter warning: "Found C system header after C++ system header" * When encountering a corrupted table file, return Status::Corruption instead of Status::InvalidArgument. * Support cygwin as build platform, patch is from https://code.google.com/p/leveldb/issues/detail?id=188 * Fix typo, merge patch from https://code.google.com/p/leveldb/issues/detail?id=159 * Fix typos and comments, and address the following two issues: * issue #166 * issue #241 * Add missing db synchronize after "fillseq" in the benchmark. * Removed unused variable in SeekRandom: value (issue #201)
10 years ago
  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_
  5. #define STORAGE_LEVELDB_DB_SKIPLIST_H_
  6. // Thread safety
  7. // -------------
  8. //
  9. // Writes require external synchronization, most likely a mutex.
  10. // Reads require a guarantee that the SkipList will not be destroyed
  11. // while the read is in progress. Apart from that, reads progress
  12. // without any internal locking or synchronization.
  13. //
  14. // Invariants:
  15. //
  16. // (1) Allocated nodes are never deleted until the SkipList is
  17. // destroyed. This is trivially guaranteed by the code since we
  18. // never delete any skip list nodes.
  19. //
  20. // (2) The contents of a Node except for the next/prev pointers are
  21. // immutable after the Node has been linked into the SkipList.
  22. // Only Insert() modifies the list, and it is careful to initialize
  23. // a node and use release-stores to publish the nodes in one or
  24. // more lists.
  25. //
  26. // ... prev vs. next pointer ordering ...
  27. #include <atomic>
  28. #include <cassert>
  29. #include <cstdlib>
  30. #include "util/arena.h"
  31. #include "util/random.h"
  32. namespace leveldb {
  33. template <typename Key, class Comparator>
  34. class SkipList {
  35. private:
  36. struct Node;
  37. public:
  38. // Create a new SkipList object that will use "cmp" for comparing keys,
  39. // and will allocate memory using "*arena". Objects allocated in the arena
  40. // must remain allocated for the lifetime of the skiplist object.
  41. explicit SkipList(Comparator cmp, Arena* arena);
  42. SkipList(const SkipList&) = delete;
  43. SkipList& operator=(const SkipList&) = delete;
  44. // Insert key into the list.
  45. // REQUIRES: nothing that compares equal to key is currently in the list.
  46. void Insert(const Key& key);
  47. // Returns true iff an entry that compares equal to key is in the list.
  48. bool Contains(const Key& key) const;
  49. // Iteration over the contents of a skip list
  50. class Iterator {
  51. public:
  52. // Initialize an iterator over the specified list.
  53. // The returned iterator is not valid.
  54. explicit Iterator(const SkipList* list);
  55. // Returns true iff the iterator is positioned at a valid node.
  56. bool Valid() const;
  57. // Returns the key at the current position.
  58. // REQUIRES: Valid()
  59. const Key& key() const;
  60. // Advances to the next position.
  61. // REQUIRES: Valid()
  62. void Next();
  63. // Advances to the previous position.
  64. // REQUIRES: Valid()
  65. void Prev();
  66. // Advance to the first entry with a key >= target
  67. void Seek(const Key& target);
  68. // Position at the first entry in list.
  69. // Final state of iterator is Valid() iff list is not empty.
  70. void SeekToFirst();
  71. // Position at the last entry in list.
  72. // Final state of iterator is Valid() iff list is not empty.
  73. void SeekToLast();
  74. Comparator get_comparator() const {return list_->compare_;}
  75. private:
  76. const SkipList* list_;
  77. Node* node_;
  78. // Intentionally copyable
  79. };
  80. private:
  81. enum { kMaxHeight = 12 };
  82. inline int GetMaxHeight() const {
  83. return max_height_.load(std::memory_order_relaxed);
  84. }
  85. Node* NewNode(const Key& key, int height);
  86. int RandomHeight();
  87. bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }
  88. // Return true if key is greater than the data stored in "n"
  89. bool KeyIsAfterNode(const Key& key, Node* n) const;
  90. // Return the earliest node that comes at or after key.
  91. // Return nullptr if there is no such node.
  92. //
  93. // If prev is non-null, fills prev[level] with pointer to previous
  94. // node at "level" for every level in [0..max_height_-1].
  95. Node* FindGreaterOrEqual(const Key& key, Node** prev) const;
  96. // Return the latest node with a key < key.
  97. // Return head_ if there is no such node.
  98. Node* FindLessThan(const Key& key) const;
  99. // Return the last node in the list.
  100. // Return head_ if list is empty.
  101. Node* FindLast() const;
  102. // Immutable after construction
  103. Comparator const compare_;
  104. Arena* const arena_; // Arena used for allocations of nodes
  105. Node* const head_;
  106. // Modified only by Insert(). Read racily by readers, but stale
  107. // values are ok.
  108. std::atomic<int> max_height_; // Height of the entire list
  109. // Read/written only by Insert().
  110. Random rnd_;
  111. };
  112. // Implementation details follow
  113. template <typename Key, class Comparator>
  114. struct SkipList<Key, Comparator>::Node {
  115. explicit Node(const Key& k) : key(k) {}
  116. Key const key;
  117. // Accessors/mutators for links. Wrapped in methods so we can
  118. // add the appropriate barriers as necessary.
  119. Node* Next(int n) {
  120. assert(n >= 0);
  121. // Use an 'acquire load' so that we observe a fully initialized
  122. // version of the returned Node.
  123. return next_[n].load(std::memory_order_acquire);
  124. }
  125. void SetNext(int n, Node* x) {
  126. assert(n >= 0);
  127. // Use a 'release store' so that anybody who reads through this
  128. // pointer observes a fully initialized version of the inserted node.
  129. next_[n].store(x, std::memory_order_release);
  130. }
  131. // No-barrier variants that can be safely used in a few locations.
  132. Node* NoBarrier_Next(int n) {
  133. assert(n >= 0);
  134. return next_[n].load(std::memory_order_relaxed);
  135. }
  136. void NoBarrier_SetNext(int n, Node* x) {
  137. assert(n >= 0);
  138. next_[n].store(x, std::memory_order_relaxed);
  139. }
  140. private:
  141. // Array of length equal to the node height. next_[0] is lowest level link.
  142. std::atomic<Node*> next_[1];
  143. };
  144. template <typename Key, class Comparator>
  145. typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::NewNode(
  146. const Key& key, int height) {
  147. char* const node_memory = arena_->AllocateAligned(
  148. sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1));
  149. return new (node_memory) Node(key);
  150. }
  151. template <typename Key, class Comparator>
  152. inline SkipList<Key, Comparator>::Iterator::Iterator(const SkipList* list) {
  153. list_ = list;
  154. node_ = nullptr;
  155. }
  156. template <typename Key, class Comparator>
  157. inline bool SkipList<Key, Comparator>::Iterator::Valid() const {
  158. return node_ != nullptr;
  159. }
  160. template <typename Key, class Comparator>
  161. inline const Key& SkipList<Key, Comparator>::Iterator::key() const {
  162. assert(Valid());
  163. return node_->key;
  164. }
  165. template <typename Key, class Comparator>
  166. inline void SkipList<Key, Comparator>::Iterator::Next() {
  167. assert(Valid());
  168. node_ = node_->Next(0);
  169. }
  170. template <typename Key, class Comparator>
  171. inline void SkipList<Key, Comparator>::Iterator::Prev() {
  172. // Instead of using explicit "prev" links, we just search for the
  173. // last node that falls before key.
  174. assert(Valid());
  175. node_ = list_->FindLessThan(node_->key);
  176. if (node_ == list_->head_) {
  177. node_ = nullptr;
  178. }
  179. }
  180. template <typename Key, class Comparator>
  181. inline void SkipList<Key, Comparator>::Iterator::Seek(const Key& target) {
  182. node_ = list_->FindGreaterOrEqual(target, nullptr);
  183. }
  184. template <typename Key, class Comparator>
  185. inline void SkipList<Key, Comparator>::Iterator::SeekToFirst() {
  186. node_ = list_->head_->Next(0);
  187. }
  188. template <typename Key, class Comparator>
  189. inline void SkipList<Key, Comparator>::Iterator::SeekToLast() {
  190. node_ = list_->FindLast();
  191. if (node_ == list_->head_) {
  192. node_ = nullptr;
  193. }
  194. }
  195. template <typename Key, class Comparator>
  196. int SkipList<Key, Comparator>::RandomHeight() {
  197. // Increase height with probability 1 in kBranching
  198. static const unsigned int kBranching = 4;
  199. int height = 1;
  200. while (height < kMaxHeight && rnd_.OneIn(kBranching)) {
  201. height++;
  202. }
  203. assert(height > 0);
  204. assert(height <= kMaxHeight);
  205. return height;
  206. }
  207. template <typename Key, class Comparator>
  208. bool SkipList<Key, Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
  209. // null n is considered infinite
  210. return (n != nullptr) && (compare_(n->key, key) < 0);
  211. }
  212. template <typename Key, class Comparator>
  213. typename SkipList<Key, Comparator>::Node*
  214. SkipList<Key, Comparator>::FindGreaterOrEqual(const Key& key,
  215. Node** prev) const {
  216. Node* x = head_;
  217. int level = GetMaxHeight() - 1;
  218. while (true) {
  219. Node* next = x->Next(level);
  220. if (KeyIsAfterNode(key, next)) {
  221. // Keep searching in this list
  222. x = next;
  223. } else {
  224. if (prev != nullptr) prev[level] = x;
  225. if (level == 0) {
  226. return next;
  227. } else {
  228. // Switch to next list
  229. level--;
  230. }
  231. }
  232. }
  233. }
  234. template <typename Key, class Comparator>
  235. typename SkipList<Key, Comparator>::Node*
  236. SkipList<Key, Comparator>::FindLessThan(const Key& key) const {
  237. Node* x = head_;
  238. int level = GetMaxHeight() - 1;
  239. while (true) {
  240. assert(x == head_ || compare_(x->key, key) < 0);
  241. Node* next = x->Next(level);
  242. if (next == nullptr || compare_(next->key, key) >= 0) {
  243. if (level == 0) {
  244. return x;
  245. } else {
  246. // Switch to next list
  247. level--;
  248. }
  249. } else {
  250. x = next;
  251. }
  252. }
  253. }
  254. template <typename Key, class Comparator>
  255. typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::FindLast()
  256. const {
  257. Node* x = head_;
  258. int level = GetMaxHeight() - 1;
  259. while (true) {
  260. Node* next = x->Next(level);
  261. if (next == nullptr) {
  262. if (level == 0) {
  263. return x;
  264. } else {
  265. // Switch to next list
  266. level--;
  267. }
  268. } else {
  269. x = next;
  270. }
  271. }
  272. }
  273. template <typename Key, class Comparator>
  274. SkipList<Key, Comparator>::SkipList(Comparator cmp, Arena* arena)
  275. : compare_(cmp),
  276. arena_(arena),
  277. head_(NewNode(0 /* any key will do */, kMaxHeight)),
  278. max_height_(1),
  279. rnd_(0xdeadbeef) {
  280. for (int i = 0; i < kMaxHeight; i++) {
  281. head_->SetNext(i, nullptr);
  282. }
  283. }
  284. template <typename Key, class Comparator>
  285. void SkipList<Key, Comparator>::Insert(const Key& key) {
  286. // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
  287. // here since Insert() is externally synchronized.
  288. Node* prev[kMaxHeight];
  289. Node* x = FindGreaterOrEqual(key, prev);
  290. // Our data structure does not allow duplicate insertion
  291. assert(x == nullptr || !Equal(key, x->key));
  292. int height = RandomHeight();
  293. if (height > GetMaxHeight()) {
  294. for (int i = GetMaxHeight(); i < height; i++) {
  295. prev[i] = head_;
  296. }
  297. // It is ok to mutate max_height_ without any synchronization
  298. // with concurrent readers. A concurrent reader that observes
  299. // the new value of max_height_ will see either the old value of
  300. // new level pointers from head_ (nullptr), or a new value set in
  301. // the loop below. In the former case the reader will
  302. // immediately drop to the next level since nullptr sorts after all
  303. // keys. In the latter case the reader will use the new node.
  304. max_height_.store(height, std::memory_order_relaxed);
  305. }
  306. x = NewNode(key, height);
  307. for (int i = 0; i < height; i++) {
  308. // NoBarrier_SetNext() suffices since we will add a barrier when
  309. // we publish a pointer to "x" in prev[i].
  310. x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
  311. prev[i]->SetNext(i, x);
  312. }
  313. }
  314. template <typename Key, class Comparator>
  315. bool SkipList<Key, Comparator>::Contains(const Key& key) const {
  316. Node* x = FindGreaterOrEqual(key, nullptr);
  317. if (x != nullptr && Equal(key, x->key)) {
  318. return true;
  319. } else {
  320. return false;
  321. }
  322. }
  323. } // namespace leveldb
  324. #endif // STORAGE_LEVELDB_DB_SKIPLIST_H_