cache_reservation_manager_test.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include "cache/cache_reservation_manager.h"
  10. #include <cstddef>
  11. #include <cstring>
  12. #include <memory>
  13. #include "cache/cache_entry_roles.h"
  14. #include "rocksdb/cache.h"
  15. #include "rocksdb/slice.h"
  16. #include "test_util/testharness.h"
  17. #include "util/coding.h"
  18. namespace ROCKSDB_NAMESPACE {
  19. class CacheReservationManagerTest : public ::testing::Test {
  20. protected:
  21. static constexpr std::size_t kSizeDummyEntry =
  22. CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
  23. static constexpr std::size_t kCacheCapacity = 4096 * kSizeDummyEntry;
  24. static constexpr int kNumShardBits = 0; // 2^0 shard
  25. static constexpr std::size_t kMetaDataChargeOverhead = 10000;
  26. std::shared_ptr<Cache> cache = NewLRUCache(kCacheCapacity, kNumShardBits);
  27. std::shared_ptr<CacheReservationManager> test_cache_rev_mng;
  28. CacheReservationManagerTest() {
  29. test_cache_rev_mng =
  30. std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
  31. cache);
  32. }
  33. };
  34. TEST_F(CacheReservationManagerTest, GenerateCacheKey) {
  35. std::size_t new_mem_used = 1 * kSizeDummyEntry;
  36. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  37. ASSERT_EQ(s, Status::OK());
  38. ASSERT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry);
  39. ASSERT_LT(cache->GetPinnedUsage(),
  40. 1 * kSizeDummyEntry + kMetaDataChargeOverhead);
  41. // Next unique Cache key
  42. CacheKey ckey = CacheKey::CreateUniqueForCacheLifetime(cache.get());
  43. // Get to the underlying values
  44. uint64_t* ckey_data = reinterpret_cast<uint64_t*>(&ckey);
  45. // Back it up to the one used by CRM (using CacheKey implementation details)
  46. ckey_data[1]--;
  47. // Specific key (subject to implementation details)
  48. EXPECT_EQ(ckey_data[0], 0);
  49. EXPECT_EQ(ckey_data[1], 2);
  50. Cache::Handle* handle = cache->Lookup(ckey.AsSlice());
  51. EXPECT_NE(handle, nullptr)
  52. << "Failed to generate the cache key for the dummy entry correctly";
  53. // Clean up the returned handle from Lookup() to prevent memory leak
  54. cache->Release(handle);
  55. }
  56. TEST_F(CacheReservationManagerTest, KeepCacheReservationTheSame) {
  57. std::size_t new_mem_used = 1 * kSizeDummyEntry;
  58. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  59. ASSERT_EQ(s, Status::OK());
  60. ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  61. 1 * kSizeDummyEntry);
  62. ASSERT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used);
  63. std::size_t initial_pinned_usage = cache->GetPinnedUsage();
  64. ASSERT_GE(initial_pinned_usage, 1 * kSizeDummyEntry);
  65. ASSERT_LT(initial_pinned_usage,
  66. 1 * kSizeDummyEntry + kMetaDataChargeOverhead);
  67. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  68. EXPECT_EQ(s, Status::OK())
  69. << "Failed to keep cache reservation the same when new_mem_used equals "
  70. "to current cache reservation";
  71. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  72. 1 * kSizeDummyEntry)
  73. << "Failed to bookkeep correctly when new_mem_used equals to current "
  74. "cache reservation";
  75. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  76. << "Failed to bookkeep the used memory correctly when new_mem_used "
  77. "equals to current cache reservation";
  78. EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
  79. << "Failed to keep underlying dummy entries the same when new_mem_used "
  80. "equals to current cache reservation";
  81. }
  82. TEST_F(CacheReservationManagerTest,
  83. IncreaseCacheReservationByMultiplesOfDummyEntrySize) {
  84. std::size_t new_mem_used = 2 * kSizeDummyEntry;
  85. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  86. EXPECT_EQ(s, Status::OK())
  87. << "Failed to increase cache reservation correctly";
  88. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  89. 2 * kSizeDummyEntry)
  90. << "Failed to bookkeep cache reservation increase correctly";
  91. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  92. << "Failed to bookkeep the used memory correctly";
  93. EXPECT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry)
  94. << "Failed to increase underlying dummy entries in cache correctly";
  95. EXPECT_LT(cache->GetPinnedUsage(),
  96. 2 * kSizeDummyEntry + kMetaDataChargeOverhead)
  97. << "Failed to increase underlying dummy entries in cache correctly";
  98. }
  99. TEST_F(CacheReservationManagerTest,
  100. IncreaseCacheReservationNotByMultiplesOfDummyEntrySize) {
  101. std::size_t new_mem_used = 2 * kSizeDummyEntry + kSizeDummyEntry / 2;
  102. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  103. EXPECT_EQ(s, Status::OK())
  104. << "Failed to increase cache reservation correctly";
  105. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  106. 3 * kSizeDummyEntry)
  107. << "Failed to bookkeep cache reservation increase correctly";
  108. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  109. << "Failed to bookkeep the used memory correctly";
  110. EXPECT_GE(cache->GetPinnedUsage(), 3 * kSizeDummyEntry)
  111. << "Failed to increase underlying dummy entries in cache correctly";
  112. EXPECT_LT(cache->GetPinnedUsage(),
  113. 3 * kSizeDummyEntry + kMetaDataChargeOverhead)
  114. << "Failed to increase underlying dummy entries in cache correctly";
  115. }
  116. TEST(CacheReservationManagerIncreaseReservcationOnFullCacheTest,
  117. IncreaseCacheReservationOnFullCache) {
  118. constexpr std::size_t kSizeDummyEntry =
  119. CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
  120. constexpr std::size_t kSmallCacheCapacity = 4 * kSizeDummyEntry;
  121. constexpr std::size_t kBigCacheCapacity = 4096 * kSizeDummyEntry;
  122. constexpr std::size_t kMetaDataChargeOverhead = 10000;
  123. LRUCacheOptions lo;
  124. lo.capacity = kSmallCacheCapacity;
  125. lo.num_shard_bits = 0; // 2^0 shard
  126. lo.strict_capacity_limit = true;
  127. std::shared_ptr<Cache> cache = NewLRUCache(lo);
  128. std::shared_ptr<CacheReservationManager> test_cache_rev_mng =
  129. std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
  130. cache);
  131. std::size_t new_mem_used = kSmallCacheCapacity + 1;
  132. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  133. EXPECT_EQ(s, Status::MemoryLimit())
  134. << "Failed to return status to indicate failure of dummy entry insertion "
  135. "during cache reservation on full cache";
  136. EXPECT_GE(test_cache_rev_mng->GetTotalReservedCacheSize(),
  137. 1 * kSizeDummyEntry)
  138. << "Failed to bookkeep correctly before cache resevation failure happens "
  139. "due to full cache";
  140. EXPECT_LE(test_cache_rev_mng->GetTotalReservedCacheSize(),
  141. kSmallCacheCapacity)
  142. << "Failed to bookkeep correctly (i.e, bookkeep only successful dummy "
  143. "entry insertions) when encountering cache resevation failure due to "
  144. "full cache";
  145. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  146. << "Failed to bookkeep the used memory correctly";
  147. EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
  148. << "Failed to insert underlying dummy entries correctly when "
  149. "encountering cache resevation failure due to full cache";
  150. EXPECT_LE(cache->GetPinnedUsage(), kSmallCacheCapacity)
  151. << "Failed to insert underlying dummy entries correctly when "
  152. "encountering cache resevation failure due to full cache";
  153. new_mem_used = kSmallCacheCapacity / 2; // 2 dummy entries
  154. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  155. EXPECT_EQ(s, Status::OK())
  156. << "Failed to decrease cache reservation after encountering cache "
  157. "reservation failure due to full cache";
  158. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  159. 2 * kSizeDummyEntry)
  160. << "Failed to bookkeep cache reservation decrease correctly after "
  161. "encountering cache reservation due to full cache";
  162. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  163. << "Failed to bookkeep the used memory correctly";
  164. EXPECT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry)
  165. << "Failed to release underlying dummy entries correctly on cache "
  166. "reservation decrease after encountering cache resevation failure due "
  167. "to full cache";
  168. EXPECT_LT(cache->GetPinnedUsage(),
  169. 2 * kSizeDummyEntry + kMetaDataChargeOverhead)
  170. << "Failed to release underlying dummy entries correctly on cache "
  171. "reservation decrease after encountering cache resevation failure due "
  172. "to full cache";
  173. // Create cache full again for subsequent tests
  174. new_mem_used = kSmallCacheCapacity + 1;
  175. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  176. EXPECT_EQ(s, Status::MemoryLimit())
  177. << "Failed to return status to indicate failure of dummy entry insertion "
  178. "during cache reservation on full cache";
  179. EXPECT_GE(test_cache_rev_mng->GetTotalReservedCacheSize(),
  180. 1 * kSizeDummyEntry)
  181. << "Failed to bookkeep correctly before cache resevation failure happens "
  182. "due to full cache";
  183. EXPECT_LE(test_cache_rev_mng->GetTotalReservedCacheSize(),
  184. kSmallCacheCapacity)
  185. << "Failed to bookkeep correctly (i.e, bookkeep only successful dummy "
  186. "entry insertions) when encountering cache resevation failure due to "
  187. "full cache";
  188. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  189. << "Failed to bookkeep the used memory correctly";
  190. EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
  191. << "Failed to insert underlying dummy entries correctly when "
  192. "encountering cache resevation failure due to full cache";
  193. EXPECT_LE(cache->GetPinnedUsage(), kSmallCacheCapacity)
  194. << "Failed to insert underlying dummy entries correctly when "
  195. "encountering cache resevation failure due to full cache";
  196. // Increase cache capacity so the previously failed insertion can fully
  197. // succeed
  198. cache->SetCapacity(kBigCacheCapacity);
  199. new_mem_used = kSmallCacheCapacity + 1;
  200. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  201. EXPECT_EQ(s, Status::OK())
  202. << "Failed to increase cache reservation after increasing cache capacity "
  203. "and mitigating cache full error";
  204. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  205. 5 * kSizeDummyEntry)
  206. << "Failed to bookkeep cache reservation increase correctly after "
  207. "increasing cache capacity and mitigating cache full error";
  208. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  209. << "Failed to bookkeep the used memory correctly";
  210. EXPECT_GE(cache->GetPinnedUsage(), 5 * kSizeDummyEntry)
  211. << "Failed to insert underlying dummy entries correctly after increasing "
  212. "cache capacity and mitigating cache full error";
  213. EXPECT_LT(cache->GetPinnedUsage(),
  214. 5 * kSizeDummyEntry + kMetaDataChargeOverhead)
  215. << "Failed to insert underlying dummy entries correctly after increasing "
  216. "cache capacity and mitigating cache full error";
  217. }
  218. TEST_F(CacheReservationManagerTest,
  219. DecreaseCacheReservationByMultiplesOfDummyEntrySize) {
  220. std::size_t new_mem_used = 2 * kSizeDummyEntry;
  221. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  222. ASSERT_EQ(s, Status::OK());
  223. ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  224. 2 * kSizeDummyEntry);
  225. ASSERT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used);
  226. ASSERT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry);
  227. ASSERT_LT(cache->GetPinnedUsage(),
  228. 2 * kSizeDummyEntry + kMetaDataChargeOverhead);
  229. new_mem_used = 1 * kSizeDummyEntry;
  230. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  231. EXPECT_EQ(s, Status::OK())
  232. << "Failed to decrease cache reservation correctly";
  233. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  234. 1 * kSizeDummyEntry)
  235. << "Failed to bookkeep cache reservation decrease correctly";
  236. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  237. << "Failed to bookkeep the used memory correctly";
  238. EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
  239. << "Failed to decrease underlying dummy entries in cache correctly";
  240. EXPECT_LT(cache->GetPinnedUsage(),
  241. 1 * kSizeDummyEntry + kMetaDataChargeOverhead)
  242. << "Failed to decrease underlying dummy entries in cache correctly";
  243. }
  244. TEST_F(CacheReservationManagerTest,
  245. DecreaseCacheReservationNotByMultiplesOfDummyEntrySize) {
  246. std::size_t new_mem_used = 2 * kSizeDummyEntry;
  247. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  248. ASSERT_EQ(s, Status::OK());
  249. ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  250. 2 * kSizeDummyEntry);
  251. ASSERT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used);
  252. ASSERT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry);
  253. ASSERT_LT(cache->GetPinnedUsage(),
  254. 2 * kSizeDummyEntry + kMetaDataChargeOverhead);
  255. new_mem_used = kSizeDummyEntry / 2;
  256. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  257. EXPECT_EQ(s, Status::OK())
  258. << "Failed to decrease cache reservation correctly";
  259. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  260. 1 * kSizeDummyEntry)
  261. << "Failed to bookkeep cache reservation decrease correctly";
  262. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  263. << "Failed to bookkeep the used memory correctly";
  264. EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
  265. << "Failed to decrease underlying dummy entries in cache correctly";
  266. EXPECT_LT(cache->GetPinnedUsage(),
  267. 1 * kSizeDummyEntry + kMetaDataChargeOverhead)
  268. << "Failed to decrease underlying dummy entries in cache correctly";
  269. }
  270. TEST(CacheReservationManagerWithDelayedDecreaseTest,
  271. DecreaseCacheReservationWithDelayedDecrease) {
  272. constexpr std::size_t kSizeDummyEntry =
  273. CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
  274. constexpr std::size_t kCacheCapacity = 4096 * kSizeDummyEntry;
  275. constexpr std::size_t kMetaDataChargeOverhead = 10000;
  276. LRUCacheOptions lo;
  277. lo.capacity = kCacheCapacity;
  278. lo.num_shard_bits = 0;
  279. std::shared_ptr<Cache> cache = NewLRUCache(lo);
  280. std::shared_ptr<CacheReservationManager> test_cache_rev_mng =
  281. std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
  282. cache, true /* delayed_decrease */);
  283. std::size_t new_mem_used = 8 * kSizeDummyEntry;
  284. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  285. ASSERT_EQ(s, Status::OK());
  286. ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  287. 8 * kSizeDummyEntry);
  288. ASSERT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used);
  289. std::size_t initial_pinned_usage = cache->GetPinnedUsage();
  290. ASSERT_GE(initial_pinned_usage, 8 * kSizeDummyEntry);
  291. ASSERT_LT(initial_pinned_usage,
  292. 8 * kSizeDummyEntry + kMetaDataChargeOverhead);
  293. new_mem_used = 6 * kSizeDummyEntry;
  294. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  295. EXPECT_EQ(s, Status::OK()) << "Failed to delay decreasing cache reservation";
  296. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  297. 8 * kSizeDummyEntry)
  298. << "Failed to bookkeep correctly when delaying cache reservation "
  299. "decrease";
  300. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  301. << "Failed to bookkeep the used memory correctly";
  302. EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
  303. << "Failed to delay decreasing underlying dummy entries in cache";
  304. new_mem_used = 7 * kSizeDummyEntry;
  305. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  306. EXPECT_EQ(s, Status::OK()) << "Failed to delay decreasing cache reservation";
  307. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  308. 8 * kSizeDummyEntry)
  309. << "Failed to bookkeep correctly when delaying cache reservation "
  310. "decrease";
  311. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  312. << "Failed to bookkeep the used memory correctly";
  313. EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
  314. << "Failed to delay decreasing underlying dummy entries in cache";
  315. new_mem_used = 6 * kSizeDummyEntry - 1;
  316. s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  317. EXPECT_EQ(s, Status::OK())
  318. << "Failed to decrease cache reservation correctly when new_mem_used < "
  319. "GetTotalReservedCacheSize() * 3 / 4 on delayed decrease mode";
  320. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
  321. 6 * kSizeDummyEntry)
  322. << "Failed to bookkeep correctly when new_mem_used < "
  323. "GetTotalReservedCacheSize() * 3 / 4 on delayed decrease mode";
  324. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), new_mem_used)
  325. << "Failed to bookkeep the used memory correctly";
  326. EXPECT_GE(cache->GetPinnedUsage(), 6 * kSizeDummyEntry)
  327. << "Failed to decrease underlying dummy entries in cache when "
  328. "new_mem_used < GetTotalReservedCacheSize() * 3 / 4 on delayed "
  329. "decrease mode";
  330. EXPECT_LT(cache->GetPinnedUsage(),
  331. 6 * kSizeDummyEntry + kMetaDataChargeOverhead)
  332. << "Failed to decrease underlying dummy entries in cache when "
  333. "new_mem_used < GetTotalReservedCacheSize() * 3 / 4 on delayed "
  334. "decrease mode";
  335. }
  336. TEST(CacheReservationManagerDestructorTest,
  337. ReleaseRemainingDummyEntriesOnDestruction) {
  338. constexpr std::size_t kSizeDummyEntry =
  339. CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
  340. constexpr std::size_t kCacheCapacity = 4096 * kSizeDummyEntry;
  341. constexpr std::size_t kMetaDataChargeOverhead = 10000;
  342. LRUCacheOptions lo;
  343. lo.capacity = kCacheCapacity;
  344. lo.num_shard_bits = 0;
  345. std::shared_ptr<Cache> cache = NewLRUCache(lo);
  346. {
  347. std::shared_ptr<CacheReservationManager> test_cache_rev_mng =
  348. std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
  349. cache);
  350. std::size_t new_mem_used = 1 * kSizeDummyEntry;
  351. Status s = test_cache_rev_mng->UpdateCacheReservation(new_mem_used);
  352. ASSERT_EQ(s, Status::OK());
  353. ASSERT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry);
  354. ASSERT_LT(cache->GetPinnedUsage(),
  355. 1 * kSizeDummyEntry + kMetaDataChargeOverhead);
  356. }
  357. EXPECT_EQ(cache->GetPinnedUsage(), 0 * kSizeDummyEntry)
  358. << "Failed to release remaining underlying dummy entries in cache in "
  359. "CacheReservationManager's destructor";
  360. }
  361. TEST(CacheReservationHandleTest, HandleTest) {
  362. constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
  363. constexpr std::size_t kSizeDummyEntry = 256 * 1024;
  364. constexpr std::size_t kMetaDataChargeOverhead = 10000;
  365. LRUCacheOptions lo;
  366. lo.capacity = kOneGigabyte;
  367. lo.num_shard_bits = 0;
  368. std::shared_ptr<Cache> cache = NewLRUCache(lo);
  369. std::shared_ptr<CacheReservationManager> test_cache_rev_mng(
  370. std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
  371. cache));
  372. std::size_t mem_used = 0;
  373. const std::size_t incremental_mem_used_handle_1 = 1 * kSizeDummyEntry;
  374. const std::size_t incremental_mem_used_handle_2 = 2 * kSizeDummyEntry;
  375. std::unique_ptr<CacheReservationManager::CacheReservationHandle> handle_1,
  376. handle_2;
  377. // To test consecutive CacheReservationManager::MakeCacheReservation works
  378. // correctly in terms of returning the handle as well as updating cache
  379. // reservation and the latest total memory used
  380. Status s = test_cache_rev_mng->MakeCacheReservation(
  381. incremental_mem_used_handle_1, &handle_1);
  382. mem_used = mem_used + incremental_mem_used_handle_1;
  383. ASSERT_EQ(s, Status::OK());
  384. EXPECT_TRUE(handle_1 != nullptr);
  385. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(), mem_used);
  386. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), mem_used);
  387. EXPECT_GE(cache->GetPinnedUsage(), mem_used);
  388. EXPECT_LT(cache->GetPinnedUsage(), mem_used + kMetaDataChargeOverhead);
  389. s = test_cache_rev_mng->MakeCacheReservation(incremental_mem_used_handle_2,
  390. &handle_2);
  391. mem_used = mem_used + incremental_mem_used_handle_2;
  392. ASSERT_EQ(s, Status::OK());
  393. EXPECT_TRUE(handle_2 != nullptr);
  394. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(), mem_used);
  395. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), mem_used);
  396. EXPECT_GE(cache->GetPinnedUsage(), mem_used);
  397. EXPECT_LT(cache->GetPinnedUsage(), mem_used + kMetaDataChargeOverhead);
  398. // To test
  399. // CacheReservationManager::CacheReservationHandle::~CacheReservationHandle()
  400. // works correctly in releasing the cache reserved for the handle
  401. handle_1.reset();
  402. EXPECT_TRUE(handle_1 == nullptr);
  403. mem_used = mem_used - incremental_mem_used_handle_1;
  404. EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(), mem_used);
  405. EXPECT_EQ(test_cache_rev_mng->GetTotalMemoryUsed(), mem_used);
  406. EXPECT_GE(cache->GetPinnedUsage(), mem_used);
  407. EXPECT_LT(cache->GetPinnedUsage(), mem_used + kMetaDataChargeOverhead);
  408. // To test the actual CacheReservationManager object won't be deallocated
  409. // as long as there remain handles pointing to it.
  410. // We strongly recommend deallocating CacheReservationManager object only
  411. // after all its handles are deallocated to keep things easy to reasonate
  412. test_cache_rev_mng.reset();
  413. EXPECT_GE(cache->GetPinnedUsage(), mem_used);
  414. EXPECT_LT(cache->GetPinnedUsage(), mem_used + kMetaDataChargeOverhead);
  415. handle_2.reset();
  416. // The CacheReservationManager object is now deallocated since all the handles
  417. // and its original pointer is gone
  418. mem_used = mem_used - incremental_mem_used_handle_2;
  419. EXPECT_EQ(mem_used, 0);
  420. EXPECT_EQ(cache->GetPinnedUsage(), mem_used);
  421. }
  422. } // namespace ROCKSDB_NAMESPACE
  423. int main(int argc, char** argv) {
  424. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  425. ::testing::InitGoogleTest(&argc, argv);
  426. return RUN_ALL_TESTS();
  427. }