// 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 "db/db_test_util.h" #include "port/stack_trace.h" namespace rocksdb { class DBTestInPlaceUpdate : public DBTestBase { public: DBTestInPlaceUpdate() : DBTestBase("/db_inplace_update_test") {} }; TEST_F(DBTestInPlaceUpdate, InPlaceUpdate) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Update key with values of smaller size int numValues = 10; for (int i = numValues; i > 0; i--) { std::string value = DummyString(i, 'a'); ASSERT_OK(Put(1, "key", value)); ASSERT_EQ(value, Get(1, "key")); } // Only 1 instance for that key. validateNumberOfEntries(1, 1); } while (ChangeCompactOptions()); } TEST_F(DBTestInPlaceUpdate, InPlaceUpdateLargeNewValue) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Update key with values of larger size int numValues = 10; for (int i = 0; i < numValues; i++) { std::string value = DummyString(i, 'a'); ASSERT_OK(Put(1, "key", value)); ASSERT_EQ(value, Get(1, "key")); } // All 10 updates exist in the internal iterator validateNumberOfEntries(numValues, 1); } while (ChangeCompactOptions()); } TEST_F(DBTestInPlaceUpdate, InPlaceUpdateCallbackSmallerSize) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.inplace_callback = rocksdb::DBTestInPlaceUpdate::updateInPlaceSmallerSize; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Update key with values of smaller size int numValues = 10; ASSERT_OK(Put(1, "key", DummyString(numValues, 'a'))); ASSERT_EQ(DummyString(numValues, 'c'), Get(1, "key")); for (int i = numValues; i > 0; i--) { ASSERT_OK(Put(1, "key", DummyString(i, 'a'))); ASSERT_EQ(DummyString(i - 1, 'b'), Get(1, "key")); } // Only 1 instance for that key. validateNumberOfEntries(1, 1); } while (ChangeCompactOptions()); } TEST_F(DBTestInPlaceUpdate, InPlaceUpdateCallbackSmallerVarintSize) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.inplace_callback = rocksdb::DBTestInPlaceUpdate::updateInPlaceSmallerVarintSize; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Update key with values of smaller varint size int numValues = 265; ASSERT_OK(Put(1, "key", DummyString(numValues, 'a'))); ASSERT_EQ(DummyString(numValues, 'c'), Get(1, "key")); for (int i = numValues; i > 0; i--) { ASSERT_OK(Put(1, "key", DummyString(i, 'a'))); ASSERT_EQ(DummyString(1, 'b'), Get(1, "key")); } // Only 1 instance for that key. validateNumberOfEntries(1, 1); } while (ChangeCompactOptions()); } TEST_F(DBTestInPlaceUpdate, InPlaceUpdateCallbackLargeNewValue) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.inplace_callback = rocksdb::DBTestInPlaceUpdate::updateInPlaceLargerSize; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Update key with values of larger size int numValues = 10; for (int i = 0; i < numValues; i++) { ASSERT_OK(Put(1, "key", DummyString(i, 'a'))); ASSERT_EQ(DummyString(i, 'c'), Get(1, "key")); } // No inplace updates. All updates are puts with new seq number // All 10 updates exist in the internal iterator validateNumberOfEntries(numValues, 1); } while (ChangeCompactOptions()); } TEST_F(DBTestInPlaceUpdate, InPlaceUpdateCallbackNoAction) { do { Options options = CurrentOptions(); options.create_if_missing = true; options.inplace_update_support = true; options.env = env_; options.write_buffer_size = 100000; options.inplace_callback = rocksdb::DBTestInPlaceUpdate::updateInPlaceNoAction; options.allow_concurrent_memtable_write = false; Reopen(options); CreateAndReopenWithCF({"pikachu"}, options); // Callback function requests no actions from db ASSERT_OK(Put(1, "key", DummyString(1, 'a'))); ASSERT_EQ(Get(1, "key"), "NOT_FOUND"); } while (ChangeCompactOptions()); } } // namespace rocksdb int main(int argc, char** argv) { rocksdb::port::InstallStackTraceHandler(); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }