cache_test.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. #include "leveldb/cache.h"
  5. #include <vector>
  6. #include "util/coding.h"
  7. #include "util/testharness.h"
  8. namespace leveldb {
  9. // Conversions between numeric keys/values and the types expected by Cache.
  10. static std::string EncodeKey(int k) {
  11. std::string result;
  12. PutFixed32(&result, k);
  13. return result;
  14. }
  15. static int DecodeKey(const Slice& k) {
  16. assert(k.size() == 4);
  17. return DecodeFixed32(k.data());
  18. }
  19. static void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); }
  20. static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); }
  21. class CacheTest {
  22. public:
  23. static CacheTest* current_;
  24. static void Deleter(const Slice& key, void* v) {
  25. current_->deleted_keys_.push_back(DecodeKey(key));
  26. current_->deleted_values_.push_back(DecodeValue(v));
  27. }
  28. static const int kCacheSize = 1000;
  29. std::vector<int> deleted_keys_;
  30. std::vector<int> deleted_values_;
  31. Cache* cache_;
  32. CacheTest() : cache_(NewLRUCache(kCacheSize)) {
  33. current_ = this;
  34. }
  35. ~CacheTest() {
  36. delete cache_;
  37. }
  38. int Lookup(int key) {
  39. Cache::Handle* handle = cache_->Lookup(EncodeKey(key));
  40. const int r = (handle == nullptr) ? -1 : DecodeValue(cache_->Value(handle));
  41. if (handle != nullptr) {
  42. cache_->Release(handle);
  43. }
  44. return r;
  45. }
  46. void Insert(int key, int value, int charge = 1) {
  47. cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge,
  48. &CacheTest::Deleter));
  49. }
  50. Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) {
  51. return cache_->Insert(EncodeKey(key), EncodeValue(value), charge,
  52. &CacheTest::Deleter);
  53. }
  54. void Erase(int key) {
  55. cache_->Erase(EncodeKey(key));
  56. }
  57. };
  58. CacheTest* CacheTest::current_;
  59. TEST(CacheTest, HitAndMiss) {
  60. ASSERT_EQ(-1, Lookup(100));
  61. Insert(100, 101);
  62. ASSERT_EQ(101, Lookup(100));
  63. ASSERT_EQ(-1, Lookup(200));
  64. ASSERT_EQ(-1, Lookup(300));
  65. Insert(200, 201);
  66. ASSERT_EQ(101, Lookup(100));
  67. ASSERT_EQ(201, Lookup(200));
  68. ASSERT_EQ(-1, Lookup(300));
  69. Insert(100, 102);
  70. ASSERT_EQ(102, Lookup(100));
  71. ASSERT_EQ(201, Lookup(200));
  72. ASSERT_EQ(-1, Lookup(300));
  73. ASSERT_EQ(1, deleted_keys_.size());
  74. ASSERT_EQ(100, deleted_keys_[0]);
  75. ASSERT_EQ(101, deleted_values_[0]);
  76. }
  77. TEST(CacheTest, Erase) {
  78. Erase(200);
  79. ASSERT_EQ(0, deleted_keys_.size());
  80. Insert(100, 101);
  81. Insert(200, 201);
  82. Erase(100);
  83. ASSERT_EQ(-1, Lookup(100));
  84. ASSERT_EQ(201, Lookup(200));
  85. ASSERT_EQ(1, deleted_keys_.size());
  86. ASSERT_EQ(100, deleted_keys_[0]);
  87. ASSERT_EQ(101, deleted_values_[0]);
  88. Erase(100);
  89. ASSERT_EQ(-1, Lookup(100));
  90. ASSERT_EQ(201, Lookup(200));
  91. ASSERT_EQ(1, deleted_keys_.size());
  92. }
  93. TEST(CacheTest, EntriesArePinned) {
  94. Insert(100, 101);
  95. Cache::Handle* h1 = cache_->Lookup(EncodeKey(100));
  96. ASSERT_EQ(101, DecodeValue(cache_->Value(h1)));
  97. Insert(100, 102);
  98. Cache::Handle* h2 = cache_->Lookup(EncodeKey(100));
  99. ASSERT_EQ(102, DecodeValue(cache_->Value(h2)));
  100. ASSERT_EQ(0, deleted_keys_.size());
  101. cache_->Release(h1);
  102. ASSERT_EQ(1, deleted_keys_.size());
  103. ASSERT_EQ(100, deleted_keys_[0]);
  104. ASSERT_EQ(101, deleted_values_[0]);
  105. Erase(100);
  106. ASSERT_EQ(-1, Lookup(100));
  107. ASSERT_EQ(1, deleted_keys_.size());
  108. cache_->Release(h2);
  109. ASSERT_EQ(2, deleted_keys_.size());
  110. ASSERT_EQ(100, deleted_keys_[1]);
  111. ASSERT_EQ(102, deleted_values_[1]);
  112. }
  113. TEST(CacheTest, EvictionPolicy) {
  114. Insert(100, 101);
  115. Insert(200, 201);
  116. Insert(300, 301);
  117. Cache::Handle* h = cache_->Lookup(EncodeKey(300));
  118. // Frequently used entry must be kept around,
  119. // as must things that are still in use.
  120. for (int i = 0; i < kCacheSize + 100; i++) {
  121. Insert(1000+i, 2000+i);
  122. ASSERT_EQ(2000+i, Lookup(1000+i));
  123. ASSERT_EQ(101, Lookup(100));
  124. }
  125. ASSERT_EQ(101, Lookup(100));
  126. ASSERT_EQ(-1, Lookup(200));
  127. ASSERT_EQ(301, Lookup(300));
  128. cache_->Release(h);
  129. }
  130. TEST(CacheTest, UseExceedsCacheSize) {
  131. // Overfill the cache, keeping handles on all inserted entries.
  132. std::vector<Cache::Handle*> h;
  133. for (int i = 0; i < kCacheSize + 100; i++) {
  134. h.push_back(InsertAndReturnHandle(1000+i, 2000+i));
  135. }
  136. // Check that all the entries can be found in the cache.
  137. for (int i = 0; i < h.size(); i++) {
  138. ASSERT_EQ(2000+i, Lookup(1000+i));
  139. }
  140. for (int i = 0; i < h.size(); i++) {
  141. cache_->Release(h[i]);
  142. }
  143. }
  144. TEST(CacheTest, HeavyEntries) {
  145. // Add a bunch of light and heavy entries and then count the combined
  146. // size of items still in the cache, which must be approximately the
  147. // same as the total capacity.
  148. const int kLight = 1;
  149. const int kHeavy = 10;
  150. int added = 0;
  151. int index = 0;
  152. while (added < 2*kCacheSize) {
  153. const int weight = (index & 1) ? kLight : kHeavy;
  154. Insert(index, 1000+index, weight);
  155. added += weight;
  156. index++;
  157. }
  158. int cached_weight = 0;
  159. for (int i = 0; i < index; i++) {
  160. const int weight = (i & 1 ? kLight : kHeavy);
  161. int r = Lookup(i);
  162. if (r >= 0) {
  163. cached_weight += weight;
  164. ASSERT_EQ(1000+i, r);
  165. }
  166. }
  167. ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10);
  168. }
  169. TEST(CacheTest, NewId) {
  170. uint64_t a = cache_->NewId();
  171. uint64_t b = cache_->NewId();
  172. ASSERT_NE(a, b);
  173. }
  174. TEST(CacheTest, Prune) {
  175. Insert(1, 100);
  176. Insert(2, 200);
  177. Cache::Handle* handle = cache_->Lookup(EncodeKey(1));
  178. ASSERT_TRUE(handle);
  179. cache_->Prune();
  180. cache_->Release(handle);
  181. ASSERT_EQ(100, Lookup(1));
  182. ASSERT_EQ(-1, Lookup(2));
  183. }
  184. TEST(CacheTest, ZeroSizeCache) {
  185. delete cache_;
  186. cache_ = NewLRUCache(0);
  187. Insert(1, 100);
  188. ASSERT_EQ(-1, Lookup(1));
  189. }
  190. } // namespace leveldb
  191. int main(int argc, char** argv) {
  192. return leveldb::test::RunAllTests();
  193. }