| // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
| // This source code is licensed under both the GPLv2 (found in the |
| // COPYING file in the root directory) and Apache 2.0 License |
| // (found in the LICENSE.Apache file in the root directory). |
| // |
| // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. See the AUTHORS file for names of contributors. |
| |
| #include "rocksdb/write_buffer_manager.h" |
| #include "util/testharness.h" |
| |
| namespace rocksdb { |
| |
| class WriteBufferManagerTest : public testing::Test {}; |
| |
| #ifndef ROCKSDB_LITE |
| TEST_F(WriteBufferManagerTest, ShouldFlush) { |
| // A write buffer manager of size 10MB |
| std::unique_ptr<WriteBufferManager> wbf( |
| new WriteBufferManager(10 * 1024 * 1024)); |
| |
| wbf->ReserveMem(8 * 1024 * 1024); |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| // 90% of the hard limit will hit the condition |
| wbf->ReserveMem(1 * 1024 * 1024); |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| // Scheduling for freeing will release the condition |
| wbf->ScheduleFreeMem(1 * 1024 * 1024); |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| |
| wbf->ReserveMem(2 * 1024 * 1024); |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| wbf->ScheduleFreeMem(4 * 1024 * 1024); |
| // 11MB total, 6MB mutable. hard limit still hit |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| wbf->ScheduleFreeMem(2 * 1024 * 1024); |
| // 11MB total, 4MB mutable. hard limit stills but won't flush because more |
| // than half data is already being flushed. |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| |
| wbf->ReserveMem(4 * 1024 * 1024); |
| // 15 MB total, 8MB mutable. |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| wbf->FreeMem(7 * 1024 * 1024); |
| // 9MB total, 8MB mutable. |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| } |
| |
| TEST_F(WriteBufferManagerTest, CacheCost) { |
| // 1GB cache |
| std::shared_ptr<Cache> cache = NewLRUCache(1024 * 1024 * 1024, 4); |
| // A write buffer manager of size 50MB |
| std::unique_ptr<WriteBufferManager> wbf( |
| new WriteBufferManager(50 * 1024 * 1024, cache)); |
| |
| // Allocate 1.5MB will allocate 2MB |
| wbf->ReserveMem(1536 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 2 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 2 * 1024 * 1024 + 10000); |
| |
| // Allocate another 2MB |
| wbf->ReserveMem(2 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 4 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 4 * 1024 * 1024 + 10000); |
| |
| // Allocate another 20MB |
| wbf->ReserveMem(20 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 24 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 24 * 1024 * 1024 + 10000); |
| |
| // Free 2MB will not cause any change in cache cost |
| wbf->FreeMem(2 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 24 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 24 * 1024 * 1024 + 10000); |
| |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| |
| // Allocate another 30MB |
| wbf->ReserveMem(30 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 52 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 52 * 1024 * 1024 + 10000); |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| wbf->ScheduleFreeMem(20 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 52 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 52 * 1024 * 1024 + 10000); |
| |
| // Still need flush as the hard limit hits |
| ASSERT_TRUE(wbf->ShouldFlush()); |
| |
| // Free 20MB will releae 1MB from cache |
| wbf->FreeMem(20 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 + 10000); |
| |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| |
| // Every free will release 1MB if still not hit 3/4 |
| wbf->FreeMem(16 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 50 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 50 * 1024 * 1024 + 10000); |
| |
| wbf->FreeMem(16 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 49 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 49 * 1024 * 1024 + 10000); |
| |
| // Free 2MB will not cause any change in cache cost |
| wbf->ReserveMem(2 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 49 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 49 * 1024 * 1024 + 10000); |
| |
| wbf->FreeMem(16 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 48 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 48 * 1024 * 1024 + 10000); |
| |
| // Destory write buffer manger should free everything |
| wbf.reset(); |
| ASSERT_LT(cache->GetPinnedUsage(), 1024 * 1024); |
| } |
| |
| TEST_F(WriteBufferManagerTest, NoCapCacheCost) { |
| // 1GB cache |
| std::shared_ptr<Cache> cache = NewLRUCache(1024 * 1024 * 1024, 4); |
| // A write buffer manager of size 256MB |
| std::unique_ptr<WriteBufferManager> wbf(new WriteBufferManager(0, cache)); |
| // Allocate 1.5MB will allocate 2MB |
| wbf->ReserveMem(10 * 1024 * 1024); |
| ASSERT_GE(cache->GetPinnedUsage(), 10 * 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 10 * 1024 * 1024 + 10000); |
| ASSERT_FALSE(wbf->ShouldFlush()); |
| |
| wbf->FreeMem(9 * 1024 * 1024); |
| for (int i = 0; i < 10; i++) { |
| wbf->FreeMem(16 * 1024); |
| } |
| ASSERT_GE(cache->GetPinnedUsage(), 1024 * 1024); |
| ASSERT_LT(cache->GetPinnedUsage(), 1024 * 1024 + 10000); |
| } |
| #endif // ROCKSDB_LITE |
| } // namespace rocksdb |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |