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 
10 #include "rocksdb/write_buffer_manager.h"
11 #include "test_util/testharness.h"
12 
13 namespace rocksdb {
14 
15 class WriteBufferManagerTest : public testing::Test {};
16 
17 #ifndef ROCKSDB_LITE
TEST_F(WriteBufferManagerTest,ShouldFlush)18 TEST_F(WriteBufferManagerTest, ShouldFlush) {
19   // A write buffer manager of size 10MB
20   std::unique_ptr<WriteBufferManager> wbf(
21       new WriteBufferManager(10 * 1024 * 1024));
22 
23   wbf->ReserveMem(8 * 1024 * 1024);
24   ASSERT_FALSE(wbf->ShouldFlush());
25   // 90% of the hard limit will hit the condition
26   wbf->ReserveMem(1 * 1024 * 1024);
27   ASSERT_TRUE(wbf->ShouldFlush());
28   // Scheduling for freeing will release the condition
29   wbf->ScheduleFreeMem(1 * 1024 * 1024);
30   ASSERT_FALSE(wbf->ShouldFlush());
31 
32   wbf->ReserveMem(2 * 1024 * 1024);
33   ASSERT_TRUE(wbf->ShouldFlush());
34 
35   wbf->ScheduleFreeMem(4 * 1024 * 1024);
36   // 11MB total, 6MB mutable. hard limit still hit
37   ASSERT_TRUE(wbf->ShouldFlush());
38 
39   wbf->ScheduleFreeMem(2 * 1024 * 1024);
40   // 11MB total, 4MB mutable. hard limit stills but won't flush because more
41   // than half data is already being flushed.
42   ASSERT_FALSE(wbf->ShouldFlush());
43 
44   wbf->ReserveMem(4 * 1024 * 1024);
45   // 15 MB total, 8MB mutable.
46   ASSERT_TRUE(wbf->ShouldFlush());
47 
48   wbf->FreeMem(7 * 1024 * 1024);
49   // 9MB total, 8MB mutable.
50   ASSERT_FALSE(wbf->ShouldFlush());
51 }
52 
TEST_F(WriteBufferManagerTest,CacheCost)53 TEST_F(WriteBufferManagerTest, CacheCost) {
54   LRUCacheOptions co;
55   // 1GB cache
56   co.capacity = 1024 * 1024 * 1024;
57   co.num_shard_bits = 4;
58   co.metadata_charge_policy = kDontChargeCacheMetadata;
59   std::shared_ptr<Cache> cache = NewLRUCache(co);
60   // A write buffer manager of size 50MB
61   std::unique_ptr<WriteBufferManager> wbf(
62       new WriteBufferManager(50 * 1024 * 1024, cache));
63 
64   // Allocate 333KB will allocate 512KB
65   wbf->ReserveMem(333 * 1024);
66   ASSERT_GE(cache->GetPinnedUsage(), 2 * 256 * 1024);
67   ASSERT_LT(cache->GetPinnedUsage(), 2 * 256 * 1024 + 10000);
68 
69   // Allocate another 512KB
70   wbf->ReserveMem(512 * 1024);
71   ASSERT_GE(cache->GetPinnedUsage(), 4 * 256 * 1024);
72   ASSERT_LT(cache->GetPinnedUsage(), 4 * 256 * 1024 + 10000);
73 
74   // Allocate another 10MB
75   wbf->ReserveMem(10 * 1024 * 1024);
76   ASSERT_GE(cache->GetPinnedUsage(), 11 * 1024 * 1024);
77   ASSERT_LT(cache->GetPinnedUsage(), 11 * 1024 * 1024 + 10000);
78 
79   // Free 1MB will not cause any change in cache cost
80   wbf->FreeMem(1024 * 1024);
81   ASSERT_GE(cache->GetPinnedUsage(), 11 * 1024 * 1024);
82   ASSERT_LT(cache->GetPinnedUsage(), 11 * 1024 * 1024 + 10000);
83 
84   ASSERT_FALSE(wbf->ShouldFlush());
85 
86   // Allocate another 41MB
87   wbf->ReserveMem(41 * 1024 * 1024);
88   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024);
89   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 + 10000);
90   ASSERT_TRUE(wbf->ShouldFlush());
91 
92   ASSERT_TRUE(wbf->ShouldFlush());
93 
94   wbf->ScheduleFreeMem(20 * 1024 * 1024);
95   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024);
96   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 + 10000);
97 
98   // Still need flush as the hard limit hits
99   ASSERT_TRUE(wbf->ShouldFlush());
100 
101   // Free 20MB will releae 256KB from cache
102   wbf->FreeMem(20 * 1024 * 1024);
103   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 256 * 1024);
104   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 256 * 1024 + 10000);
105 
106   ASSERT_FALSE(wbf->ShouldFlush());
107 
108   // Every free will release 256KB if still not hit 3/4
109   wbf->FreeMem(16 * 1024);
110   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 2 * 256 * 1024);
111   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 2 * 256 * 1024 + 10000);
112 
113   wbf->FreeMem(16 * 1024);
114   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024);
115   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024 + 10000);
116 
117   // Reserve 512KB will not cause any change in cache cost
118   wbf->ReserveMem(512 * 1024);
119   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024);
120   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024 + 10000);
121 
122   wbf->FreeMem(16 * 1024);
123   ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 4 * 256 * 1024);
124   ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 4 * 256 * 1024 + 10000);
125 
126   // Destory write buffer manger should free everything
127   wbf.reset();
128   ASSERT_LT(cache->GetPinnedUsage(), 1024 * 1024);
129 }
130 
TEST_F(WriteBufferManagerTest,NoCapCacheCost)131 TEST_F(WriteBufferManagerTest, NoCapCacheCost) {
132   // 1GB cache
133   std::shared_ptr<Cache> cache = NewLRUCache(1024 * 1024 * 1024, 4);
134   // A write buffer manager of size 256MB
135   std::unique_ptr<WriteBufferManager> wbf(new WriteBufferManager(0, cache));
136   // Allocate 1.5MB will allocate 2MB
137   wbf->ReserveMem(10 * 1024 * 1024);
138   ASSERT_GE(cache->GetPinnedUsage(), 10 * 1024 * 1024);
139   ASSERT_LT(cache->GetPinnedUsage(), 10 * 1024 * 1024 + 10000);
140   ASSERT_FALSE(wbf->ShouldFlush());
141 
142   wbf->FreeMem(9 * 1024 * 1024);
143   for (int i = 0; i < 40; i++) {
144     wbf->FreeMem(4 * 1024);
145   }
146   ASSERT_GE(cache->GetPinnedUsage(), 1024 * 1024);
147   ASSERT_LT(cache->GetPinnedUsage(), 1024 * 1024 + 10000);
148 }
149 #endif  // ROCKSDB_LITE
150 }  // namespace rocksdb
151 
main(int argc,char ** argv)152 int main(int argc, char** argv) {
153   ::testing::InitGoogleTest(&argc, argv);
154   return RUN_ALL_TESTS();
155 }
156