10225501448 李度 10225101546 陈胤遒 10215501422 高宇菲
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

253 lignes
6.5 KiB

  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. #if defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_ANDROID)
  5. #include <unordered_set>
  6. #elif defined(LEVELDB_PLATFORM_CHROMIUM)
  7. #include "base/hash_tables.h"
  8. #else
  9. #include <hash_set> // TODO(sanjay): Switch to unordered_set when possible.
  10. #endif
  11. #include <assert.h>
  12. #include "include/cache.h"
  13. #include "port/port.h"
  14. #include "util/hash.h"
  15. #include "util/mutexlock.h"
  16. namespace leveldb {
  17. Cache::~Cache() {
  18. }
  19. namespace {
  20. // LRU cache implementation
  21. // An entry is a variable length heap-allocated structure. Entries
  22. // are kept in a circular doubly linked list ordered by access time.
  23. struct LRUHandle {
  24. void* value;
  25. void (*deleter)(const Slice&, void* value);
  26. LRUHandle* next;
  27. LRUHandle* prev;
  28. size_t charge; // TODO(opt): Only allow uint32_t?
  29. size_t key_length;
  30. size_t refs; // TODO(opt): Pack with "key_length"?
  31. char key_data[1]; // Beginning of key
  32. Slice key() const {
  33. // For cheaper lookups, we allow a temporary Handle object
  34. // to store a pointer to a key in "value".
  35. if (next == this) {
  36. return *(reinterpret_cast<Slice*>(value));
  37. } else {
  38. return Slice(key_data, key_length);
  39. }
  40. }
  41. };
  42. // Pick a platform specific hash_set instantiation
  43. #if defined(LEVELDB_PLATFORM_CHROMIUM) && defined(OS_WIN)
  44. // Microsoft's hash_set deviates from the standard. See
  45. // http://msdn.microsoft.com/en-us/library/1t4xas78(v=vs.80).aspx
  46. // for details. Basically the 2 param () operator is a less than and
  47. // the 1 param () operator is a hash function.
  48. struct HandleHashCompare : public stdext::hash_compare<LRUHandle*> {
  49. size_t operator() (LRUHandle* h) const {
  50. Slice k = h->key();
  51. return Hash(k.data(), k.size(), 0);
  52. }
  53. bool operator() (LRUHandle* a, LRUHandle* b) const {
  54. return a->key().compare(b->key()) < 0;
  55. }
  56. };
  57. typedef base::hash_set<LRUHandle*, HandleHashCompare> HandleTable;
  58. #else
  59. struct HandleHash {
  60. inline size_t operator()(LRUHandle* h) const {
  61. Slice k = h->key();
  62. return Hash(k.data(), k.size(), 0);
  63. }
  64. };
  65. struct HandleEq {
  66. inline bool operator()(LRUHandle* a, LRUHandle* b) const {
  67. return a->key() == b->key();
  68. }
  69. };
  70. # if defined(LEVELDB_PLATFORM_CHROMIUM)
  71. typedef base::hash_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
  72. # elif defined(LEVELDB_PLATFORM_POSIX) || defined(LEVELDB_PLATFORM_ANDROID)
  73. typedef std::unordered_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
  74. # else
  75. typedef __gnu_cxx::hash_set<LRUHandle*, HandleHash, HandleEq> HandleTable;
  76. # endif
  77. #endif
  78. class LRUCache : public Cache {
  79. public:
  80. explicit LRUCache(size_t capacity);
  81. virtual ~LRUCache();
  82. virtual Handle* Insert(const Slice& key, void* value, size_t charge,
  83. void (*deleter)(const Slice& key, void* value));
  84. virtual Handle* Lookup(const Slice& key);
  85. virtual void Release(Handle* handle);
  86. virtual void* Value(Handle* handle);
  87. virtual void Erase(const Slice& key);
  88. virtual uint64_t NewId();
  89. private:
  90. void LRU_Remove(LRUHandle* e);
  91. void LRU_Append(LRUHandle* e);
  92. void Unref(LRUHandle* e);
  93. // Constructor parameters
  94. const size_t capacity_;
  95. // mutex_ protects the following state.
  96. port::Mutex mutex_;
  97. size_t usage_;
  98. uint64_t last_id_;
  99. // Dummy head of LRU list.
  100. // lru.prev is newest entry, lru.next is oldest entry.
  101. LRUHandle lru_;
  102. HandleTable table_;
  103. };
  104. LRUCache::LRUCache(size_t capacity)
  105. : capacity_(capacity),
  106. usage_(0),
  107. last_id_(0) {
  108. // Make empty circular linked list
  109. lru_.next = &lru_;
  110. lru_.prev = &lru_;
  111. }
  112. LRUCache::~LRUCache() {
  113. table_.clear();
  114. for (LRUHandle* e = lru_.next; e != &lru_; ) {
  115. LRUHandle* next = e->next;
  116. assert(e->refs == 1); // Error if caller has an unreleased handle
  117. Unref(e);
  118. e = next;
  119. }
  120. }
  121. void LRUCache::Unref(LRUHandle* e) {
  122. assert(e->refs > 0);
  123. e->refs--;
  124. if (e->refs <= 0) {
  125. usage_ -= e->charge;
  126. (*e->deleter)(e->key(), e->value);
  127. free(e);
  128. }
  129. }
  130. void LRUCache::LRU_Remove(LRUHandle* e) {
  131. e->next->prev = e->prev;
  132. e->prev->next = e->next;
  133. }
  134. void LRUCache::LRU_Append(LRUHandle* e) {
  135. // Make "e" newest entry by inserting just before lru_
  136. e->next = &lru_;
  137. e->prev = lru_.prev;
  138. e->prev->next = e;
  139. e->next->prev = e;
  140. }
  141. Cache::Handle* LRUCache::Lookup(const Slice& key) {
  142. MutexLock l(&mutex_);
  143. LRUHandle dummy;
  144. dummy.next = &dummy;
  145. dummy.value = const_cast<Slice*>(&key);
  146. HandleTable::iterator iter = table_.find(&dummy);
  147. if (iter == table_.end()) {
  148. return NULL;
  149. } else {
  150. LRUHandle* e = const_cast<LRUHandle*>(*iter);
  151. e->refs++;
  152. LRU_Remove(e);
  153. LRU_Append(e);
  154. return reinterpret_cast<Handle*>(e);
  155. }
  156. }
  157. void* LRUCache::Value(Handle* handle) {
  158. return reinterpret_cast<LRUHandle*>(handle)->value;
  159. }
  160. void LRUCache::Release(Handle* handle) {
  161. MutexLock l(&mutex_);
  162. Unref(reinterpret_cast<LRUHandle*>(handle));
  163. }
  164. Cache::Handle* LRUCache::Insert(const Slice& key, void* value, size_t charge,
  165. void (*deleter)(const Slice& key, void* value)) {
  166. MutexLock l(&mutex_);
  167. LRUHandle* e = reinterpret_cast<LRUHandle*>(
  168. malloc(sizeof(LRUHandle)-1 + key.size()));
  169. e->value = value;
  170. e->deleter = deleter;
  171. e->charge = charge;
  172. e->key_length = key.size();
  173. e->refs = 2; // One from LRUCache, one for the returned handle
  174. memcpy(e->key_data, key.data(), key.size());
  175. LRU_Append(e);
  176. usage_ += charge;
  177. std::pair<HandleTable::iterator,bool> p = table_.insert(e);
  178. if (!p.second) {
  179. // Kill existing entry
  180. LRUHandle* old = const_cast<LRUHandle*>(*(p.first));
  181. LRU_Remove(old);
  182. table_.erase(p.first);
  183. table_.insert(e);
  184. Unref(old);
  185. }
  186. while (usage_ > capacity_ && lru_.next != &lru_) {
  187. LRUHandle* old = lru_.next;
  188. LRU_Remove(old);
  189. table_.erase(old);
  190. Unref(old);
  191. }
  192. return reinterpret_cast<Handle*>(e);
  193. }
  194. void LRUCache::Erase(const Slice& key) {
  195. MutexLock l(&mutex_);
  196. LRUHandle dummy;
  197. dummy.next = &dummy;
  198. dummy.value = const_cast<Slice*>(&key);
  199. HandleTable::iterator iter = table_.find(&dummy);
  200. if (iter != table_.end()) {
  201. LRUHandle* e = const_cast<LRUHandle*>(*iter);
  202. LRU_Remove(e);
  203. table_.erase(iter);
  204. Unref(e);
  205. }
  206. }
  207. uint64_t LRUCache::NewId() {
  208. MutexLock l(&mutex_);
  209. return ++(last_id_);
  210. }
  211. } // end anonymous namespace
  212. Cache* NewLRUCache(size_t capacity) {
  213. return new LRUCache(capacity);
  214. }
  215. }