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.

253 lines
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. }