Add further tests to ASSERT_STATUS_CHECKED (1) (#7679)

Summary:
First batch of adding more tests to ASSERT_STATUS_CHECKED.

* db_iterator_test
* db_memtable_test
* db_merge_operator_test
* db_merge_operand_test
* write_batch_test
* write_batch_with_index_test

Pull Request resolved: https://github.com/facebook/rocksdb/pull/7679

Reviewed By: ajkr

Differential Revision: D25399270

Pulled By: pdillinger

fbshipit-source-id: 3017d0a686aec5cd2d743fc2acbbf75df239f3ba
main
Adam Retter 4 years ago committed by Facebook GitHub Bot
parent 66e54c5984
commit 7b2216c906
  1. 6
      Makefile
  2. 106
      db/db_iterator_test.cc
  3. 5
      db/db_memtable_test.cc
  4. 94
      db/db_merge_operand_test.cc
  5. 29
      db/db_merge_operator_test.cc
  6. 10
      db/db_test_util.cc
  7. 8
      db/forward_iterator.cc
  8. 2
      db/write_batch_test.cc
  9. 403
      utilities/write_batch_with_index/write_batch_with_index_test.cc

@ -595,6 +595,10 @@ ifdef ASSERT_STATUS_CHECKED
db_basic_test \
db_blob_basic_test \
db_flush_test \
db_iterator_test \
db_memtable_test \
db_merge_operand_test \
db_merge_operator_test \
db_with_timestamp_basic_test \
db_with_timestamp_compaction_test \
db_options_test \
@ -677,6 +681,8 @@ ifdef ASSERT_STATUS_CHECKED
import_column_family_test \
memory_test \
table_test \
write_batch_test \
write_batch_with_index_test \
ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
TESTS_PASSING_ASC += folly_synchronization_distributed_mutex_test

@ -67,8 +67,8 @@ TEST_P(DBIteratorTest, IteratorProperty) {
// The test needs to be changed if kPersistedTier is supported in iterator.
Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu"}, options);
Put(1, "1", "2");
Delete(1, "2");
ASSERT_OK(Put(1, "1", "2"));
ASSERT_OK(Delete(1, "2"));
ReadOptions ropt;
ropt.pin_data = false;
{
@ -172,10 +172,10 @@ TEST_P(DBIteratorTest, NonBlockingIteration) {
TEST_P(DBIteratorTest, IterSeekBeforePrev) {
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("0", "f"));
ASSERT_OK(Put("1", "h"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("2", "j"));
auto iter = NewIterator(ReadOptions());
iter->Seek(Slice("c"));
@ -199,7 +199,7 @@ TEST_P(DBIteratorTest, IterReseekNewUpperBound) {
ASSERT_OK(Put("aabb", rnd.RandomString(400)));
ASSERT_OK(Put("aaef", rnd.RandomString(400)));
ASSERT_OK(Put("b", rnd.RandomString(400)));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ReadOptions opts;
Slice ub = Slice("aa");
opts.iterate_upper_bound = &ub;
@ -215,10 +215,10 @@ TEST_P(DBIteratorTest, IterReseekNewUpperBound) {
TEST_P(DBIteratorTest, IterSeekForPrevBeforeNext) {
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("0", "f"));
ASSERT_OK(Put("1", "h"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("2", "j"));
auto iter = NewIterator(ReadOptions());
iter->SeekForPrev(Slice("0"));
@ -238,7 +238,7 @@ TEST_P(DBIteratorTest, IterLongKeys) {
ASSERT_OK(Put(MakeLongKey(20, 0), "0"));
ASSERT_OK(Put(MakeLongKey(32, 2), "2"));
ASSERT_OK(Put("a", "b"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put(MakeLongKey(50, 1), "1"));
ASSERT_OK(Put(MakeLongKey(127, 3), "3"));
ASSERT_OK(Put(MakeLongKey(64, 4), "4"));
@ -276,7 +276,7 @@ TEST_P(DBIteratorTest, IterLongKeys) {
TEST_P(DBIteratorTest, IterNextWithNewerSeq) {
ASSERT_OK(Put("0", "0"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("d", "e"));
@ -302,7 +302,7 @@ TEST_P(DBIteratorTest, IterNextWithNewerSeq) {
TEST_P(DBIteratorTest, IterPrevWithNewerSeq) {
ASSERT_OK(Put("0", "0"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("d", "e"));
@ -333,7 +333,7 @@ TEST_P(DBIteratorTest, IterPrevWithNewerSeq) {
TEST_P(DBIteratorTest, IterPrevWithNewerSeq2) {
ASSERT_OK(Put("0", "0"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("a", "b"));
ASSERT_OK(Put("c", "d"));
ASSERT_OK(Put("e", "f"));
@ -377,6 +377,8 @@ TEST_P(DBIteratorTest, IterEmpty) {
iter->SeekForPrev("foo");
ASSERT_EQ(IterStatus(iter), "(invalid)");
ASSERT_OK(iter->status());
delete iter;
} while (ChangeCompactOptions());
}
@ -783,18 +785,18 @@ TEST_P(DBIteratorTest, IterWithSnapshot) {
TEST_P(DBIteratorTest, IteratorPinsRef) {
do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
Put(1, "foo", "hello");
ASSERT_OK(Put(1, "foo", "hello"));
// Get iterator that will yield the current contents of the DB.
Iterator* iter = NewIterator(ReadOptions(), handles_[1]);
// Write to force compactions
Put(1, "foo", "newvalue1");
ASSERT_OK(Put(1, "foo", "newvalue1"));
for (int i = 0; i < 100; i++) {
// 100K values
ASSERT_OK(Put(1, Key(i), Key(i) + std::string(100000, 'v')));
}
Put(1, "foo", "newvalue2");
ASSERT_OK(Put(1, "foo", "newvalue2"));
iter->SeekToFirst();
ASSERT_TRUE(iter->Valid());
@ -809,8 +811,8 @@ TEST_P(DBIteratorTest, IteratorPinsRef) {
TEST_P(DBIteratorTest, IteratorDeleteAfterCfDelete) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
Put(1, "foo", "delete-cf-then-delete-iter");
Put(1, "hello", "value2");
ASSERT_OK(Put(1, "foo", "delete-cf-then-delete-iter"));
ASSERT_OK(Put(1, "hello", "value2"));
ColumnFamilyHandle* cf = handles_[1];
ReadOptions ro;
@ -820,7 +822,7 @@ TEST_P(DBIteratorTest, IteratorDeleteAfterCfDelete) {
ASSERT_EQ(IterStatus(iter), "foo->delete-cf-then-delete-iter");
// delete CF handle
db_->DestroyColumnFamilyHandle(cf);
EXPECT_OK(db_->DestroyColumnFamilyHandle(cf));
handles_.erase(std::begin(handles_) + 1);
// delete Iterator after CF handle is deleted
@ -832,7 +834,7 @@ TEST_P(DBIteratorTest, IteratorDeleteAfterCfDelete) {
TEST_P(DBIteratorTest, IteratorDeleteAfterCfDrop) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
Put(1, "foo", "drop-cf-then-delete-iter");
ASSERT_OK(Put(1, "foo", "drop-cf-then-delete-iter"));
ReadOptions ro;
ColumnFamilyHandle* cf = handles_[1];
@ -842,8 +844,8 @@ TEST_P(DBIteratorTest, IteratorDeleteAfterCfDrop) {
ASSERT_EQ(IterStatus(iter), "foo->drop-cf-then-delete-iter");
// drop and delete CF
db_->DropColumnFamily(cf);
db_->DestroyColumnFamilyHandle(cf);
EXPECT_OK(db_->DropColumnFamily(cf));
EXPECT_OK(db_->DestroyColumnFamilyHandle(cf));
handles_.erase(std::begin(handles_) + 1);
// delete Iterator after CF handle is dropped
@ -1307,9 +1309,9 @@ TEST_P(DBIteratorTest, PrevAfterAndNextAfterMerge) {
// write three entries with different keys using Merge()
WriteOptions wopts;
db_->Merge(wopts, "1", "data1");
db_->Merge(wopts, "2", "data2");
db_->Merge(wopts, "3", "data3");
ASSERT_OK(db_->Merge(wopts, "1", "data1"));
ASSERT_OK(db_->Merge(wopts, "2", "data2"));
ASSERT_OK(db_->Merge(wopts, "3", "data3"));
std::unique_ptr<Iterator> it(NewIterator(ReadOptions()));
@ -1393,7 +1395,7 @@ class DBIteratorTestForPinnedData : public DBIteratorTest {
if (run_config == TestConfig::FLUSH_EVERY_1000) {
if (i && i % 1000 == 0) {
Flush();
ASSERT_OK(Flush());
}
}
}
@ -1402,7 +1404,7 @@ class DBIteratorTestForPinnedData : public DBIteratorTest {
Close();
Reopen(options);
} else if (run_config == TestConfig::COMPACT_BEFORE_READ) {
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
}
ReadOptions ro;
@ -1768,6 +1770,7 @@ TEST_P(DBIteratorTest, IterSeekForPrevCrossingFiles) {
Iterator* iter = NewIterator(ro);
iter->SeekForPrev("c2");
ASSERT_TRUE(!iter->Valid());
ASSERT_OK(iter->status());
delete iter;
}
}
@ -1823,6 +1826,7 @@ TEST_P(DBIteratorTest, IterSeekForPrevCrossingFilesCustomPrefixExtractor) {
Iterator* iter = NewIterator(ro);
iter->SeekForPrev("c2");
ASSERT_TRUE(!iter->Valid());
ASSERT_OK(iter->status());
delete iter;
}
}
@ -2151,19 +2155,19 @@ TEST_P(DBIteratorTest, ReadAhead) {
std::string value(1024, 'a');
for (int i = 0; i < 100; i++) {
Put(Key(i), value);
ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
MoveFilesToLevel(2);
for (int i = 0; i < 100; i++) {
Put(Key(i), value);
ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
MoveFilesToLevel(1);
for (int i = 0; i < 100; i++) {
Put(Key(i), value);
ASSERT_OK(Put(Key(i), value));
}
ASSERT_OK(Flush());
#ifndef ROCKSDB_LITE
@ -2270,6 +2274,7 @@ TEST_P(DBIteratorTest, Refresh) {
ASSERT_OK(Put("x", "y"));
std::unique_ptr<Iterator> iter(NewIterator(ReadOptions()));
ASSERT_OK(iter->status());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(iter->key().compare(Slice("x")), 0);
@ -2284,7 +2289,8 @@ TEST_P(DBIteratorTest, Refresh) {
iter->Next();
ASSERT_FALSE(iter->Valid());
iter->Refresh();
ASSERT_OK(iter->status());
ASSERT_OK(iter->Refresh());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
@ -2295,7 +2301,7 @@ TEST_P(DBIteratorTest, Refresh) {
iter->Next();
ASSERT_FALSE(iter->Valid());
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("m", "n"));
@ -2308,7 +2314,8 @@ TEST_P(DBIteratorTest, Refresh) {
iter->Next();
ASSERT_FALSE(iter->Valid());
iter->Refresh();
ASSERT_OK(iter->status());
ASSERT_OK(iter->Refresh());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
@ -2331,6 +2338,7 @@ TEST_P(DBIteratorTest, RefreshWithSnapshot) {
ReadOptions options;
options.snapshot = snapshot;
Iterator* iter = NewIterator(options);
ASSERT_OK(iter->status());
iter->Seek(Slice("a"));
ASSERT_TRUE(iter->Valid());
@ -2346,8 +2354,8 @@ TEST_P(DBIteratorTest, RefreshWithSnapshot) {
iter->Next();
ASSERT_FALSE(iter->Valid());
Status s;
s = iter->Refresh();
ASSERT_OK(iter->status());
Status s = iter->Refresh();
ASSERT_TRUE(s.IsNotSupported());
db_->ReleaseSnapshot(snapshot);
delete iter;
@ -2405,14 +2413,14 @@ TEST_P(DBIteratorTest, UpperBoundWithChangeDirection) {
TEST_P(DBIteratorTest, TableFilter) {
ASSERT_OK(Put("a", "1"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("b", "2"));
ASSERT_OK(Put("c", "3"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
ASSERT_OK(Put("d", "4"));
ASSERT_OK(Put("e", "5"));
ASSERT_OK(Put("f", "6"));
dbfull()->Flush(FlushOptions());
EXPECT_OK(dbfull()->Flush(FlushOptions()));
// Ensure the table_filter callback is called once for each table.
{
@ -2597,13 +2605,13 @@ TEST_P(DBIteratorTest, SeekAfterHittingManyInternalKeys) {
ReadOptions ropts;
ropts.max_skippable_internal_keys = 2;
Put("1", "val_1");
ASSERT_OK(Put("1", "val_1"));
// Add more tombstones than max_skippable_internal_keys so that Next() fails.
Delete("2");
Delete("3");
Delete("4");
Delete("5");
Put("6", "val_6");
ASSERT_OK(Delete("2"));
ASSERT_OK(Delete("3"));
ASSERT_OK(Delete("4"));
ASSERT_OK(Delete("5"));
ASSERT_OK(Put("6", "val_6"));
std::unique_ptr<Iterator> iter(NewIterator(ropts));
iter->SeekToFirst();
@ -2645,9 +2653,9 @@ TEST_P(DBIteratorTest, NonBlockingIterationBugRepro) {
DestroyAndReopen(options);
// Two records in sst file, each in its own block.
Put("b", "");
Put("d", "");
Flush();
ASSERT_OK(Put("b", ""));
ASSERT_OK(Put("d", ""));
ASSERT_OK(Flush());
// Create a nonblocking iterator before writing to memtable.
ReadOptions ropt;
@ -2657,7 +2665,7 @@ TEST_P(DBIteratorTest, NonBlockingIterationBugRepro) {
// Overwrite a key in memtable many times to hit
// max_sequential_skip_in_iterations (which is 8 by default).
for (int i = 0; i < 20; ++i) {
Put("c", "");
ASSERT_OK(Put("c", ""));
}
// Load the second block in sst file into the block cache.
@ -2674,9 +2682,9 @@ TEST_P(DBIteratorTest, NonBlockingIterationBugRepro) {
}
TEST_P(DBIteratorTest, SeekBackwardAfterOutOfUpperBound) {
Put("a", "");
Put("b", "");
Flush();
ASSERT_OK(Put("a", ""));
ASSERT_OK(Put("b", ""));
ASSERT_OK(Flush());
ReadOptions ropt;
Slice ub = "b";

@ -129,7 +129,6 @@ class TestPrefixExtractor : public SliceTransform {
TEST_F(DBMemTableTest, DuplicateSeq) {
SequenceNumber seq = 123;
std::string value;
Status s;
MergeContext merge_context;
Options options;
InternalKeyComparator ikey_cmp(options.comparator);
@ -162,7 +161,7 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
if (!insert_dup) {
seq++;
}
s = mem->Add(seq, kTypeValue, "foo", "value" + ToString(seq));
Status s = mem->Add(seq, kTypeValue, "foo", "value" + ToString(seq));
if (insert_dup) {
ASSERT_TRUE(s.IsTryAgain());
} else {
@ -200,7 +199,6 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
TEST_F(DBMemTableTest, ConcurrentMergeWrite) {
int num_ops = 1000;
std::string value;
Status s;
MergeContext merge_context;
Options options;
// A merge operator that is not sensitive to concurrent writes since in this
@ -252,6 +250,7 @@ TEST_F(DBMemTableTest, ConcurrentMergeWrite) {
LookupKey lkey("key", kMaxSequenceNumber);
bool res = mem->Get(lkey, &value, /*timestamp=*/nullptr, &status,
&merge_context, &max_covering_tombstone_seq, roptions);
ASSERT_OK(status);
ASSERT_TRUE(res);
uint64_t ivalue = DecodeFixed64(Slice(value).data());
uint64_t sum = 0;

@ -59,29 +59,29 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
merge_operands_info.expected_max_number_of_operands = num_records;
// k0 value in memtable
Put("k0", "PutARock");
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k0",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(Put("k0", "PutARock"));
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k0", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "PutARock");
// k0.1 value in SST
Put("k0.1", "RockInSST");
ASSERT_OK(Put("k0.1", "RockInSST"));
ASSERT_OK(Flush());
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k0.1",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k0.1", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "RockInSST");
// All k1 values are in memtable.
ASSERT_OK(Merge("k1", "a"));
Put("k1", "x");
ASSERT_OK(Put("k1", "x"));
ASSERT_OK(Merge("k1", "b"));
ASSERT_OK(Merge("k1", "c"));
ASSERT_OK(Merge("k1", "d"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k1",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k1", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "x");
ASSERT_EQ(values[1], "b");
ASSERT_EQ(values[2], "c");
@ -98,13 +98,13 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
// All k1.1 values are in memtable.
ASSERT_OK(Merge("k1.1", "r"));
Delete("k1.1");
ASSERT_OK(Delete("k1.1"));
ASSERT_OK(Merge("k1.1", "c"));
ASSERT_OK(Merge("k1.1", "k"));
ASSERT_OK(Merge("k1.1", "s"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k1.1",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k1.1", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "c");
ASSERT_EQ(values[1], "k");
ASSERT_EQ(values[2], "s");
@ -115,9 +115,9 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
ASSERT_OK(Merge("k2", "e"));
ASSERT_OK(Merge("k2", "r"));
ASSERT_OK(Flush());
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k2", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "q");
ASSERT_EQ(values[1], "w");
ASSERT_EQ(values[2], "e");
@ -125,30 +125,30 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
// All k2.1 values are flushed to L0 into a single file.
ASSERT_OK(Merge("k2.1", "m"));
Put("k2.1", "l");
ASSERT_OK(Put("k2.1", "l"));
ASSERT_OK(Merge("k2.1", "n"));
ASSERT_OK(Merge("k2.1", "o"));
ASSERT_OK(Flush());
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2.1",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k2.1", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "l,n,o");
// All k2.2 values are flushed to L0 into a single file.
ASSERT_OK(Merge("k2.2", "g"));
Delete("k2.2");
ASSERT_OK(Delete("k2.2"));
ASSERT_OK(Merge("k2.2", "o"));
ASSERT_OK(Merge("k2.2", "t"));
ASSERT_OK(Flush());
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k2.2",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k2.2", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "o,t");
// Do some compaction that will make the following tests more predictable
// Slice start("PutARock");
// Slice end("t");
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
// All k3 values are flushed and are in different files.
ASSERT_OK(Merge("k3", "ab"));
@ -158,9 +158,9 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
ASSERT_OK(Merge("k3", "cd"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3", "de"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k3", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "ab");
ASSERT_EQ(values[1], "bc");
ASSERT_EQ(values[2], "cd");
@ -169,14 +169,14 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
// All k3.1 values are flushed and are in different files.
ASSERT_OK(Merge("k3.1", "ab"));
ASSERT_OK(Flush());
Put("k3.1", "bc");
ASSERT_OK(Put("k3.1", "bc"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3.1", "cd"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3.1", "de"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3.1",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k3.1", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "bc");
ASSERT_EQ(values[1], "cd");
ASSERT_EQ(values[2], "de");
@ -184,14 +184,14 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
// All k3.2 values are flushed and are in different files.
ASSERT_OK(Merge("k3.2", "ab"));
ASSERT_OK(Flush());
Delete("k3.2");
ASSERT_OK(Delete("k3.2"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3.2", "cd"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3.2", "de"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k3.2",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k3.2", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "cd");
ASSERT_EQ(values[1], "de");
@ -206,9 +206,9 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
ASSERT_OK(Flush());
MoveFilesToLevel(1);
ASSERT_OK(Merge("k4", "ed"));
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k4",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k4", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "ba");
ASSERT_EQ(values[1], "cb");
ASSERT_EQ(values[2], "dc");
@ -219,14 +219,14 @@ TEST_F(DBMergeOperandTest, GetMergeOperandsBasic) {
ASSERT_OK(Merge("k5", "am"));
ASSERT_OK(Merge("k5", "i"));
ASSERT_OK(Flush());
Put("k5", "remember");
ASSERT_OK(Put("k5", "remember"));
ASSERT_OK(Merge("k5", "i"));
ASSERT_OK(Merge("k5", "am"));
ASSERT_OK(Merge("k5", "rocks"));
dbfull()->TEST_SwitchMemtable();
db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(), "k5",
values.data(), &merge_operands_info,
&number_of_operands);
ASSERT_OK(dbfull()->TEST_SwitchMemtable());
ASSERT_OK(db_->GetMergeOperands(ReadOptions(), db_->DefaultColumnFamily(),
"k5", values.data(), &merge_operands_info,
&number_of_operands));
ASSERT_EQ(values[0], "remember");
ASSERT_EQ(values[1], "i");
ASSERT_EQ(values[2], "am");

@ -94,7 +94,7 @@ TEST_F(DBMergeOperatorTest, LimitMergeOperands) {
ASSERT_OK(Merge("k1", "c"));
ASSERT_OK(Merge("k1", "d"));
std::string value;
ASSERT_TRUE(db_->Get(ReadOptions(), "k1", &value).ok());
ASSERT_OK(db_->Get(ReadOptions(), "k1", &value));
// Make sure that only the latest two merge operands are used. If this was
// not the case the value would be "a,b,c,d".
ASSERT_EQ(value, "c,d");
@ -105,7 +105,7 @@ TEST_F(DBMergeOperatorTest, LimitMergeOperands) {
ASSERT_OK(Merge("k2", "c"));
ASSERT_OK(Merge("k2", "d"));
ASSERT_OK(Flush());
ASSERT_TRUE(db_->Get(ReadOptions(), "k2", &value).ok());
ASSERT_OK(db_->Get(ReadOptions(), "k2", &value));
ASSERT_EQ(value, "c,d");
// All K3 values are flushed and are in different files.
@ -116,7 +116,7 @@ TEST_F(DBMergeOperatorTest, LimitMergeOperands) {
ASSERT_OK(Merge("k3", "cd"));
ASSERT_OK(Flush());
ASSERT_OK(Merge("k3", "de"));
ASSERT_TRUE(db_->Get(ReadOptions(), "k3", &value).ok());
ASSERT_OK(db_->Get(ReadOptions(), "k3", &value));
ASSERT_EQ(value, "cd,de");
// All K4 values are in different levels
@ -130,7 +130,7 @@ TEST_F(DBMergeOperatorTest, LimitMergeOperands) {
ASSERT_OK(Flush());
MoveFilesToLevel(1);
ASSERT_OK(Merge("k4", "de"));
ASSERT_TRUE(db_->Get(ReadOptions(), "k4", &value).ok());
ASSERT_OK(db_->Get(ReadOptions(), "k4", &value));
ASSERT_EQ(value, "cd,de");
}
@ -344,8 +344,9 @@ TEST_P(MergeOperatorPinningTest, EvictCacheBeforeMerge) {
// Code executed before merge operation
merge_hook->before_merge_ = [&]() {
// Evict all tables from cache before every merge operation
auto* table_cache = dbfull()->TEST_table_cache();
for (uint64_t num : file_numbers) {
TableCache::Evict(dbfull()->TEST_table_cache(), num);
TableCache::Evict(table_cache, num);
}
// Decrease cache capacity to force all unrefed blocks to be evicted
if (bbto.block_cache) {
@ -366,7 +367,7 @@ TEST_P(MergeOperatorPinningTest, EvictCacheBeforeMerge) {
VerifyDBFromMap(true_data, &total_reads);
ASSERT_EQ(merge_cnt, total_reads);
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
VerifyDBFromMap(true_data, &total_reads);
}
@ -385,7 +386,7 @@ TEST_P(MergeOperatorPinningTest, TailingIterator) {
std::function<void()> writer_func = [&]() {
int k = 0;
for (int i = 0; i < kNumWrites; i++) {
db_->Merge(WriteOptions(), Key(k), Key(k));
ASSERT_OK(db_->Merge(WriteOptions(), Key(k), Key(k)));
if (i && i % kNumOperands == 0) {
k++;
@ -403,7 +404,7 @@ TEST_P(MergeOperatorPinningTest, TailingIterator) {
ReadOptions ro;
ro.tailing = true;
Iterator* iter = db_->NewIterator(ro);
ASSERT_OK(iter->status());
iter->SeekToFirst();
for (int i = 0; i < (kNumWrites / kNumOperands); i++) {
while (!iter->Valid()) {
@ -416,6 +417,7 @@ TEST_P(MergeOperatorPinningTest, TailingIterator) {
iter->Next();
}
ASSERT_OK(iter->status());
delete iter;
};
@ -449,12 +451,13 @@ TEST_F(DBMergeOperatorTest, TailingIteratorMemtableUnrefedBySomeoneElse) {
// ForwardIterator to not pin it in some circumstances. This test
// reproduces it.
db_->Merge(WriteOptions(), "key", "sst");
db_->Flush(FlushOptions()); // Switch to SuperVersion A
db_->Merge(WriteOptions(), "key", "memtable");
ASSERT_OK(db_->Merge(WriteOptions(), "key", "sst"));
ASSERT_OK(db_->Flush(FlushOptions())); // Switch to SuperVersion A
ASSERT_OK(db_->Merge(WriteOptions(), "key", "memtable"));
// Pin SuperVersion A
std::unique_ptr<Iterator> someone_else(db_->NewIterator(ReadOptions()));
ASSERT_OK(someone_else->status());
bool pushed_first_operand = false;
bool stepped_to_next_operand = false;
@ -462,7 +465,7 @@ TEST_F(DBMergeOperatorTest, TailingIteratorMemtableUnrefedBySomeoneElse) {
"DBIter::MergeValuesNewToOld:PushedFirstOperand", [&](void*) {
EXPECT_FALSE(pushed_first_operand);
pushed_first_operand = true;
db_->Flush(FlushOptions()); // Switch to SuperVersion B
EXPECT_OK(db_->Flush(FlushOptions())); // Switch to SuperVersion B
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"DBIter::MergeValuesNewToOld:SteppedToNextOperand", [&](void*) {
@ -477,7 +480,7 @@ TEST_F(DBMergeOperatorTest, TailingIteratorMemtableUnrefedBySomeoneElse) {
std::unique_ptr<Iterator> iter(db_->NewIterator(ro));
iter->Seek("key");
ASSERT_TRUE(iter->status().ok());
ASSERT_OK(iter->status());
ASSERT_TRUE(iter->Valid());
EXPECT_EQ(std::string("sst,memtable"), iter->value().ToString());
EXPECT_TRUE(pushed_first_operand);

@ -200,28 +200,28 @@ bool DBTestBase::ChangeCompactOptions() {
Destroy(last_options_);
auto options = CurrentOptions();
options.create_if_missing = true;
TryReopen(options);
Reopen(options);
return true;
} else if (option_config_ == kUniversalCompaction) {
option_config_ = kUniversalCompactionMultiLevel;
Destroy(last_options_);
auto options = CurrentOptions();
options.create_if_missing = true;
TryReopen(options);
Reopen(options);
return true;
} else if (option_config_ == kUniversalCompactionMultiLevel) {
option_config_ = kLevelSubcompactions;
Destroy(last_options_);
auto options = CurrentOptions();
assert(options.max_subcompactions > 1);
TryReopen(options);
Reopen(options);
return true;
} else if (option_config_ == kLevelSubcompactions) {
option_config_ = kUniversalSubcompactions;
Destroy(last_options_);
auto options = CurrentOptions();
assert(options.max_subcompactions > 1);
TryReopen(options);
Reopen(options);
return true;
} else {
return false;
@ -680,7 +680,7 @@ void DBTestBase::Close() {
void DBTestBase::DestroyAndReopen(const Options& options) {
// Destroy using last options
Destroy(last_options_);
ASSERT_OK(TryReopen(options));
Reopen(options);
}
void DBTestBase::Destroy(const Options& options, bool delete_cf_paths) {

@ -46,7 +46,13 @@ class ForwardLevelIterator : public InternalIterator {
file_iter_(nullptr),
pinned_iters_mgr_(nullptr),
prefix_extractor_(prefix_extractor),
allow_unprepared_value_(allow_unprepared_value) {}
allow_unprepared_value_(allow_unprepared_value) {
/*
NOTE needed for ASSERT_STATUS_CHECKED
in MergeOperatorPinningTest/MergeOperatorPinningTest.TailingIterator
*/
status_.PermitUncheckedError();
}
~ForwardLevelIterator() override {
// Reset current pointer

@ -64,6 +64,7 @@ static std::string PrintContents(WriteBatch* b,
if (iter == nullptr) {
continue;
}
EXPECT_OK(iter->status());
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
ParsedInternalKey ikey;
ikey.clear();
@ -117,6 +118,7 @@ static std::string PrintContents(WriteBatch* b,
state.append("@");
state.append(NumberToString(ikey.sequence));
}
EXPECT_OK(iter->status());
}
if (s.ok()) {
EXPECT_EQ(b->HasPut(), put_count > 0);

@ -96,11 +96,11 @@ void TestValueAsSecondaryIndexHelper(std::vector<Entry> entries,
ColumnFamilyHandleImplDummy index(8, BytewiseComparator());
for (auto& e : entries) {
if (e.type == kPutRecord) {
batch->Put(&data, e.key, e.value);
batch->Put(&index, e.value, e.key);
ASSERT_OK(batch->Put(&data, e.key, e.value));
ASSERT_OK(batch->Put(&index, e.value, e.key));
} else if (e.type == kMergeRecord) {
batch->Merge(&data, e.key, e.value);
batch->Put(&index, e.value, e.key);
ASSERT_OK(batch->Merge(&data, e.key, e.value));
ASSERT_OK(batch->Put(&index, e.value, e.key));
} else {
assert(e.type == kDeleteRecord);
std::unique_ptr<WBWIIterator> iter(batch->NewIterator(&data));
@ -109,8 +109,8 @@ void TestValueAsSecondaryIndexHelper(std::vector<Entry> entries,
auto write_entry = iter->Entry();
ASSERT_EQ(e.key, write_entry.key.ToString());
ASSERT_EQ(e.value, write_entry.value.ToString());
batch->Delete(&data, e.key);
batch->Put(&index, e.value, "");
ASSERT_OK(batch->Delete(&data, e.key));
ASSERT_OK(batch->Put(&index, e.value, ""));
}
}
@ -243,7 +243,7 @@ void TestValueAsSecondaryIndexHelper(std::vector<Entry> entries,
// Verify WriteBatch can be iterated
TestHandler handler;
batch->GetWriteBatch()->Iterate(&handler);
ASSERT_OK(batch->GetWriteBatch()->Iterate(&handler));
// Verify data column family
{
@ -315,18 +315,18 @@ TEST_F(WriteBatchWithIndexTest, TestComparatorForCF) {
ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator());
WriteBatchWithIndex batch(BytewiseComparator(), 20);
batch.Put(&cf1, "ddd", "");
batch.Put(&cf2, "aaa", "");
batch.Put(&cf2, "eee", "");
batch.Put(&cf1, "ccc", "");
batch.Put(&reverse_cf, "a11", "");
batch.Put(&cf1, "bbb", "");
ASSERT_OK(batch.Put(&cf1, "ddd", ""));
ASSERT_OK(batch.Put(&cf2, "aaa", ""));
ASSERT_OK(batch.Put(&cf2, "eee", ""));
ASSERT_OK(batch.Put(&cf1, "ccc", ""));
ASSERT_OK(batch.Put(&reverse_cf, "a11", ""));
ASSERT_OK(batch.Put(&cf1, "bbb", ""));
Slice key_slices[] = {"a", "3", "3"};
Slice value_slice = "";
batch.Put(&reverse_cf, SliceParts(key_slices, 3),
SliceParts(&value_slice, 1));
batch.Put(&reverse_cf, "a22", "");
ASSERT_OK(batch.Put(&reverse_cf, SliceParts(key_slices, 3),
SliceParts(&value_slice, 1)));
ASSERT_OK(batch.Put(&reverse_cf, "a22", ""));
{
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1));
@ -402,20 +402,20 @@ TEST_F(WriteBatchWithIndexTest, TestOverwriteKey) {
ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator());
WriteBatchWithIndex batch(BytewiseComparator(), 20, true);
batch.Put(&cf1, "ddd", "");
batch.Merge(&cf1, "ddd", "");
batch.Delete(&cf1, "ddd");
batch.Put(&cf2, "aaa", "");
batch.Delete(&cf2, "aaa");
batch.Put(&cf2, "aaa", "aaa");
batch.Put(&cf2, "eee", "eee");
batch.Put(&cf1, "ccc", "");
batch.Put(&reverse_cf, "a11", "");
batch.Delete(&cf1, "ccc");
batch.Put(&reverse_cf, "a33", "a33");
batch.Put(&reverse_cf, "a11", "a11");
ASSERT_OK(batch.Put(&cf1, "ddd", ""));
ASSERT_OK(batch.Merge(&cf1, "ddd", ""));
ASSERT_OK(batch.Delete(&cf1, "ddd"));
ASSERT_OK(batch.Put(&cf2, "aaa", ""));
ASSERT_OK(batch.Delete(&cf2, "aaa"));
ASSERT_OK(batch.Put(&cf2, "aaa", "aaa"));
ASSERT_OK(batch.Put(&cf2, "eee", "eee"));
ASSERT_OK(batch.Put(&cf1, "ccc", ""));
ASSERT_OK(batch.Put(&reverse_cf, "a11", ""));
ASSERT_OK(batch.Delete(&cf1, "ccc"));
ASSERT_OK(batch.Put(&reverse_cf, "a33", "a33"));
ASSERT_OK(batch.Put(&reverse_cf, "a11", "a11"));
Slice slices[] = {"a", "3", "3"};
batch.Delete(&reverse_cf, SliceParts(slices, 3));
ASSERT_OK(batch.Delete(&reverse_cf, SliceParts(slices, 3)));
{
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1));
@ -570,10 +570,10 @@ TEST_F(WriteBatchWithIndexTest, TestRandomIteraratorWithBase) {
WriteBatchWithIndex batch(BytewiseComparator(), 20, true);
if (rand_seed % 2 == 0) {
batch.Put(&cf2, "zoo", "bar");
ASSERT_OK(batch.Put(&cf2, "zoo", "bar"));
}
if (rand_seed % 4 == 1) {
batch.Put(&cf3, "zoo", "bar");
ASSERT_OK(batch.Put(&cf3, "zoo", "bar"));
}
KVMap map;
@ -589,24 +589,24 @@ TEST_F(WriteBatchWithIndexTest, TestRandomIteraratorWithBase) {
break;
case 1:
// only delta has it
batch.Put(&cf1, key, value);
ASSERT_OK(batch.Put(&cf1, key, value));
map[key] = value;
merged_map[key] = value;
break;
case 2:
// both has it. Delta should win
batch.Put(&cf1, key, value);
ASSERT_OK(batch.Put(&cf1, key, value));
map[key] = "wrong_value";
merged_map[key] = value;
break;
case 3:
// both has it. Delta is delete
batch.Delete(&cf1, key);
ASSERT_OK(batch.Delete(&cf1, key));
map[key] = "wrong_value";
break;
case 4:
// only delta has it. Delta is delete
batch.Delete(&cf1, key);
ASSERT_OK(batch.Delete(&cf1, key));
map[key] = "wrong_value";
break;
default:
@ -675,6 +675,8 @@ TEST_F(WriteBatchWithIndexTest, TestRandomIteraratorWithBase) {
AssertItersEqual(iter.get(), result_iter.get());
is_valid = iter->Valid();
}
ASSERT_OK(iter->status());
}
}
@ -722,8 +724,8 @@ TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBase) {
}
// Test the case that there is one element in the write batch
batch.Put(&cf2, "zoo", "bar");
batch.Put(&cf1, "a", "aa");
ASSERT_OK(batch.Put(&cf2, "zoo", "bar"));
ASSERT_OK(batch.Put(&cf1, "a", "aa"));
{
KVMap empty_map;
std::unique_ptr<Iterator> iter(
@ -736,10 +738,10 @@ TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBase) {
ASSERT_TRUE(!iter->Valid());
}
batch.Delete(&cf1, "b");
batch.Put(&cf1, "c", "cc");
batch.Put(&cf1, "d", "dd");
batch.Delete(&cf1, "e");
ASSERT_OK(batch.Delete(&cf1, "b"));
ASSERT_OK(batch.Put(&cf1, "c", "cc"));
ASSERT_OK(batch.Put(&cf1, "d", "dd"));
ASSERT_OK(batch.Delete(&cf1, "e"));
{
KVMap map;
@ -847,8 +849,8 @@ TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBaseReverseCmp) {
WriteBatchWithIndex batch(BytewiseComparator(), 20, true);
// Test the case that there is one element in the write batch
batch.Put(&cf2, "zoo", "bar");
batch.Put(&cf1, "a", "aa");
ASSERT_OK(batch.Put(&cf2, "zoo", "bar"));
ASSERT_OK(batch.Put(&cf1, "a", "aa"));
{
KVMap empty_map;
std::unique_ptr<Iterator> iter(
@ -861,7 +863,7 @@ TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBaseReverseCmp) {
ASSERT_TRUE(!iter->Valid());
}
batch.Put(&cf1, "c", "cc");
ASSERT_OK(batch.Put(&cf1, "c", "cc"));
{
KVMap map;
std::unique_ptr<Iterator> iter(
@ -894,7 +896,7 @@ TEST_F(WriteBatchWithIndexTest, TestIteraratorWithBaseReverseCmp) {
}
// default column family
batch.Put("a", "b");
ASSERT_OK(batch.Put("a", "b"));
{
KVMap map;
map["b"] = "";
@ -936,14 +938,14 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatch) {
s = batch.GetFromBatch(options, "b", &value);
ASSERT_TRUE(s.IsNotFound());
batch.Put("a", "a");
batch.Put("b", "b");
batch.Put("c", "c");
batch.Put("a", "z");
batch.Delete("c");
batch.Delete("d");
batch.Delete("e");
batch.Put("e", "e");
ASSERT_OK(batch.Put("a", "a"));
ASSERT_OK(batch.Put("b", "b"));
ASSERT_OK(batch.Put("c", "c"));
ASSERT_OK(batch.Put("a", "z"));
ASSERT_OK(batch.Delete("c"));
ASSERT_OK(batch.Delete("d"));
ASSERT_OK(batch.Delete("e"));
ASSERT_OK(batch.Put("e", "e"));
s = batch.GetFromBatch(options, "b", &value);
ASSERT_OK(s);
@ -966,7 +968,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatch) {
ASSERT_OK(s);
ASSERT_EQ("e", value);
batch.Merge("z", "z");
ASSERT_OK(batch.Merge("z", "z"));
s = batch.GetFromBatch(options, "z", &value);
ASSERT_NOK(s); // No merge operator specified.
@ -984,7 +986,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge) {
std::string dbname = test::PerThreadDBPath("write_batch_with_index_test");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
ASSERT_OK(s);
@ -995,18 +997,18 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge) {
s = batch.GetFromBatch(options, "x", &value);
ASSERT_TRUE(s.IsNotFound());
batch.Put("x", "X");
ASSERT_OK(batch.Put("x", "X"));
std::string expected = "X";
for (int i = 0; i < 5; i++) {
batch.Merge("x", ToString(i));
ASSERT_OK(batch.Merge("x", ToString(i)));
expected = expected + "," + ToString(i);
if (i % 2 == 0) {
batch.Put("y", ToString(i / 2));
ASSERT_OK(batch.Put("y", ToString(i / 2)));
}
batch.Merge("z", "z");
ASSERT_OK(batch.Merge("z", "z"));
s = batch.GetFromBatch(column_family, options, "x", &value);
ASSERT_OK(s);
@ -1021,7 +1023,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge) {
}
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge2) {
@ -1032,7 +1034,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge2) {
std::string dbname = test::PerThreadDBPath("write_batch_with_index_test");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
ASSERT_OK(s);
@ -1045,43 +1047,43 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchMerge2) {
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsNotFound());
batch.Put(column_family, "X", "x");
ASSERT_OK(batch.Put(column_family, "X", "x"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_OK(s);
ASSERT_EQ("x", value);
batch.Put(column_family, "X", "x2");
ASSERT_OK(batch.Put(column_family, "X", "x2"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_OK(s);
ASSERT_EQ("x2", value);
batch.Merge(column_family, "X", "aaa");
ASSERT_OK(batch.Merge(column_family, "X", "aaa"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsMergeInProgress());
batch.Merge(column_family, "X", "bbb");
ASSERT_OK(batch.Merge(column_family, "X", "bbb"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsMergeInProgress());
batch.Put(column_family, "X", "x3");
ASSERT_OK(batch.Put(column_family, "X", "x3"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_OK(s);
ASSERT_EQ("x3", value);
batch.Merge(column_family, "X", "ccc");
ASSERT_OK(batch.Merge(column_family, "X", "ccc"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsMergeInProgress());
batch.Delete(column_family, "X");
ASSERT_OK(batch.Delete(column_family, "X"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsNotFound());
batch.Merge(column_family, "X", "ddd");
ASSERT_OK(batch.Merge(column_family, "X", "ddd"));
s = batch.GetFromBatch(column_family, options, "X", &value);
ASSERT_TRUE(s.IsMergeInProgress());
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDB) {
@ -1090,7 +1092,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDB) {
options.create_if_missing = true;
std::string dbname = test::PerThreadDBPath("write_batch_with_index_test");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
ASSERT_OK(s);
@ -1108,8 +1110,8 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDB) {
s = db->Put(write_options, "c", "c");
ASSERT_OK(s);
batch.Put("a", "batch.a");
batch.Delete("b");
ASSERT_OK(batch.Put("a", "batch.a"));
ASSERT_OK(batch.Delete("b"));
s = batch.GetFromBatchAndDB(db, read_options, "a", &value);
ASSERT_OK(s);
@ -1125,13 +1127,13 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDB) {
s = batch.GetFromBatchAndDB(db, read_options, "x", &value);
ASSERT_TRUE(s.IsNotFound());
db->Delete(write_options, "x");
ASSERT_OK(db->Delete(write_options, "x"));
s = batch.GetFromBatchAndDB(db, read_options, "x", &value);
ASSERT_TRUE(s.IsNotFound());
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
@ -1143,9 +1145,9 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
assert(s.ok());
ASSERT_OK(s);
WriteBatchWithIndex batch;
ReadOptions read_options;
@ -1167,11 +1169,11 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
s = db->Merge(write_options, "d", "d0");
ASSERT_OK(s);
batch.Merge("a", "a1");
batch.Merge("a", "a2");
batch.Merge("b", "b2");
batch.Merge("d", "d1");
batch.Merge("e", "e0");
ASSERT_OK(batch.Merge("a", "a1"));
ASSERT_OK(batch.Merge("a", "a2"));
ASSERT_OK(batch.Merge("b", "b2"));
ASSERT_OK(batch.Merge("d", "d1"));
ASSERT_OK(batch.Merge("e", "e0"));
s = batch.GetFromBatchAndDB(db, read_options, "a", &value);
ASSERT_OK(s);
@ -1214,7 +1216,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
ASSERT_OK(s);
ASSERT_EQ("a0,a1,a2", value);
batch.Delete("a");
ASSERT_OK(batch.Delete("a"));
s = batch.GetFromBatchAndDB(db, read_options, "a", &value);
ASSERT_TRUE(s.IsNotFound());
@ -1257,7 +1259,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
db->ReleaseSnapshot(snapshot);
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge2) {
@ -1269,9 +1271,9 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge2) {
options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
assert(s.ok());
ASSERT_OK(s);
// Test batch with overwrite_key=true
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
@ -1283,12 +1285,12 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge2) {
s = batch.GetFromBatchAndDB(db, read_options, "A", &value);
ASSERT_TRUE(s.IsNotFound());
batch.Merge("A", "xxx");
ASSERT_OK(batch.Merge("A", "xxx"));
s = batch.GetFromBatchAndDB(db, read_options, "A", &value);
ASSERT_TRUE(s.IsMergeInProgress());
batch.Merge("A", "yyy");
ASSERT_OK(batch.Merge("A", "yyy"));
s = batch.GetFromBatchAndDB(db, read_options, "A", &value);
ASSERT_TRUE(s.IsMergeInProgress());
@ -1299,13 +1301,13 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge2) {
s = batch.GetFromBatchAndDB(db, read_options, "A", &value);
ASSERT_TRUE(s.IsMergeInProgress());
batch.Delete("A");
ASSERT_OK(batch.Delete("A"));
s = batch.GetFromBatchAndDB(db, read_options, "A", &value);
ASSERT_TRUE(s.IsNotFound());
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge3) {
@ -1317,9 +1319,9 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge3) {
options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
Status s = DB::Open(options, dbname, &db);
assert(s.ok());
ASSERT_OK(s);
ReadOptions read_options;
WriteOptions write_options;
@ -1336,7 +1338,7 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge3) {
ASSERT_EQ(value, "1,2");
delete db;
DestroyDB(dbname, options);
EXPECT_OK(DestroyDB(dbname, options));
}
void AssertKey(std::string key, WBWIIterator* iter) {
@ -1354,7 +1356,7 @@ void AssertValue(std::string value, WBWIIterator* iter) {
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingCorrectnessTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
ASSERT_OK(batch.Put(std::string(1, c), std::string(1, c)));
}
std::unique_ptr<WBWIIterator> iter(batch.NewIterator());
@ -1362,14 +1364,14 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingCorrectnessTest) {
AssertKey("k", iter.get());
iter->Next();
AssertKey("l", iter.get());
batch.Put("ab", "cc");
ASSERT_OK(batch.Put("ab", "cc"));
iter->Next();
AssertKey("m", iter.get());
batch.Put("mm", "kk");
ASSERT_OK(batch.Put("mm", "kk"));
iter->Next();
AssertKey("mm", iter.get());
AssertValue("kk", iter.get());
batch.Delete("mm");
ASSERT_OK(batch.Delete("mm"));
iter->Next();
AssertKey("n", iter.get());
@ -1379,7 +1381,7 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingCorrectnessTest) {
iter->Seek("ab");
AssertKey("ab", iter.get());
batch.Delete("x");
ASSERT_OK(batch.Delete("x"));
iter->Seek("x");
AssertKey("x", iter.get());
ASSERT_EQ(kDeleteRecord, iter->Entry().type);
@ -1401,7 +1403,7 @@ void AssertIterValue(std::string value, Iterator* iter) {
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
ASSERT_OK(batch.Put(std::string(1, c), std::string(1, c)));
}
KVMap map;
@ -1416,14 +1418,14 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
AssertIterKey("k", iter.get());
iter->Next();
AssertIterKey("l", iter.get());
batch.Put("ab", "cc");
ASSERT_OK(batch.Put("ab", "cc"));
iter->Next();
AssertIterKey("m", iter.get());
batch.Put("mm", "kk");
ASSERT_OK(batch.Put("mm", "kk"));
iter->Next();
AssertIterKey("mm", iter.get());
AssertIterValue("kk", iter.get());
batch.Delete("mm");
ASSERT_OK(batch.Delete("mm"));
iter->Next();
AssertIterKey("n", iter.get());
iter->Prev();
@ -1436,13 +1438,13 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
AssertIterKey("aa", iter.get());
iter->Prev();
AssertIterKey("a", iter.get());
batch.Delete("aa");
ASSERT_OK(batch.Delete("aa"));
iter->Next();
AssertIterKey("ab", iter.get());
iter->Prev();
AssertIterKey("a", iter.get());
batch.Delete("x");
ASSERT_OK(batch.Delete("x"));
iter->Seek("x");
AssertIterKey("y", iter.get());
iter->Next();
@ -1451,11 +1453,11 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
iter->Prev();
AssertIterKey("w", iter.get());
batch.Delete("e");
ASSERT_OK(batch.Delete("e"));
iter->Seek("e");
AssertIterKey("ee", iter.get());
AssertIterValue("ee", iter.get());
batch.Put("ee", "xx");
ASSERT_OK(batch.Put("ee", "xx"));
// still the same value
AssertIterValue("ee", iter.get());
iter->Next();
@ -1463,13 +1465,15 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
iter->Prev();
// new value
AssertIterValue("xx", iter.get());
ASSERT_OK(iter->status());
}
// stress testing mutations with IteratorWithBase
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseStressTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
ASSERT_OK(batch.Put(std::string(1, c), std::string(1, c)));
}
KVMap map;
@ -1486,16 +1490,16 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseStressTest) {
char c = static_cast<char>(rnd.Uniform(26) + 'a');
switch (random) {
case 0:
batch.Put(std::string(1, c), "xxx");
ASSERT_OK(batch.Put(std::string(1, c), "xxx"));
break;
case 1:
batch.Put(std::string(2, c), "xxx");
ASSERT_OK(batch.Put(std::string(2, c), "xxx"));
break;
case 2:
batch.Delete(std::string(1, c));
ASSERT_OK(batch.Delete(std::string(1, c)));
break;
case 3:
batch.Delete(std::string(2, c));
ASSERT_OK(batch.Delete(std::string(2, c)));
break;
case 4:
iter->Seek(std::string(1, c));
@ -1517,12 +1521,12 @@ TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseStressTest) {
assert(false);
}
}
ASSERT_OK(iter->status());
}
static std::string PrintContents(WriteBatchWithIndex* batch,
ColumnFamilyHandle* column_family) {
std::string result;
static void PrintContents(WriteBatchWithIndex* batch,
ColumnFamilyHandle* column_family,
std::string* result) {
WBWIIterator* iter;
if (column_family == nullptr) {
iter = batch->NewIterator();
@ -1532,41 +1536,50 @@ static std::string PrintContents(WriteBatchWithIndex* batch,
iter->SeekToFirst();
while (iter->Valid()) {
ASSERT_OK(iter->status());
WriteEntry e = iter->Entry();
if (e.type == kPutRecord) {
result.append("PUT(");
result.append(e.key.ToString());
result.append("):");
result.append(e.value.ToString());
result->append("PUT(");
result->append(e.key.ToString());
result->append("):");
result->append(e.value.ToString());
} else if (e.type == kMergeRecord) {
result.append("MERGE(");
result.append(e.key.ToString());
result.append("):");
result.append(e.value.ToString());
result->append("MERGE(");
result->append(e.key.ToString());
result->append("):");
result->append(e.value.ToString());
} else if (e.type == kSingleDeleteRecord) {
result.append("SINGLE-DEL(");
result.append(e.key.ToString());
result.append(")");
result->append("SINGLE-DEL(");
result->append(e.key.ToString());
result->append(")");
} else {
assert(e.type == kDeleteRecord);
result.append("DEL(");
result.append(e.key.ToString());
result.append(")");
result->append("DEL(");
result->append(e.key.ToString());
result->append(")");
}
result.append(",");
result->append(",");
iter->Next();
}
ASSERT_OK(iter->status());
delete iter;
return result;
}
static std::string PrintContents(WriteBatchWithIndex* batch, KVMap* base_map,
static std::string PrintContents(WriteBatchWithIndex* batch,
ColumnFamilyHandle* column_family) {
std::string result;
PrintContents(batch, column_family, &result);
return result;
}
static void PrintContents(WriteBatchWithIndex* batch, KVMap* base_map,
ColumnFamilyHandle* column_family,
std::string* result) {
Iterator* iter;
if (column_family == nullptr) {
iter = batch->NewIteratorWithBase(new KVIter(base_map));
@ -1576,20 +1589,28 @@ static std::string PrintContents(WriteBatchWithIndex* batch, KVMap* base_map,
iter->SeekToFirst();
while (iter->Valid()) {
assert(iter->status().ok());
ASSERT_OK(iter->status());
Slice key = iter->key();
Slice value = iter->value();
result.append(key.ToString());
result.append(":");
result.append(value.ToString());
result.append(",");
result->append(key.ToString());
result->append(":");
result->append(value.ToString());
result->append(",");
iter->Next();
}
ASSERT_OK(iter->status());
delete iter;
}
static std::string PrintContents(WriteBatchWithIndex* batch, KVMap* base_map,
ColumnFamilyHandle* column_family) {
std::string result;
PrintContents(batch, base_map, column_family, &result);
return result;
}
@ -1598,34 +1619,34 @@ TEST_F(WriteBatchWithIndexTest, SavePointTest) {
ColumnFamilyHandleImplDummy cf1(1, BytewiseComparator());
Status s;
batch.Put("A", "a");
batch.Put("B", "b");
batch.Put("A", "aa");
batch.Put(&cf1, "A", "a1");
batch.Delete(&cf1, "B");
batch.Put(&cf1, "C", "c1");
batch.Put(&cf1, "E", "e1");
ASSERT_OK(batch.Put("A", "a"));
ASSERT_OK(batch.Put("B", "b"));
ASSERT_OK(batch.Put("A", "aa"));
ASSERT_OK(batch.Put(&cf1, "A", "a1"));
ASSERT_OK(batch.Delete(&cf1, "B"));
ASSERT_OK(batch.Put(&cf1, "C", "c1"));
ASSERT_OK(batch.Put(&cf1, "E", "e1"));
batch.SetSavePoint(); // 1
batch.Put("C", "cc");
batch.Put("B", "bb");
batch.Delete("A");
batch.Put(&cf1, "B", "b1");
batch.Delete(&cf1, "A");
batch.SingleDelete(&cf1, "E");
ASSERT_OK(batch.Put("C", "cc"));
ASSERT_OK(batch.Put("B", "bb"));
ASSERT_OK(batch.Delete("A"));
ASSERT_OK(batch.Put(&cf1, "B", "b1"));
ASSERT_OK(batch.Delete(&cf1, "A"));
ASSERT_OK(batch.SingleDelete(&cf1, "E"));
batch.SetSavePoint(); // 2
batch.Put("A", "aaa");
batch.Put("A", "xxx");
batch.Delete("B");
batch.Put(&cf1, "B", "b2");
batch.Delete(&cf1, "C");
ASSERT_OK(batch.Put("A", "aaa"));
ASSERT_OK(batch.Put("A", "xxx"));
ASSERT_OK(batch.Delete("B"));
ASSERT_OK(batch.Put(&cf1, "B", "b2"));
ASSERT_OK(batch.Delete(&cf1, "C"));
batch.SetSavePoint(); // 3
batch.SetSavePoint(); // 4
batch.SingleDelete("D");
batch.Delete(&cf1, "D");
batch.Delete(&cf1, "E");
ASSERT_OK(batch.SingleDelete("D"));
ASSERT_OK(batch.Delete(&cf1, "D"));
ASSERT_OK(batch.Delete(&cf1, "E"));
ASSERT_EQ(
"PUT(A):a,PUT(A):aa,DEL(A),PUT(A):aaa,PUT(A):xxx,PUT(B):b,PUT(B):bb,DEL("
@ -1672,7 +1693,7 @@ TEST_F(WriteBatchWithIndexTest, SavePointTest) {
PrintContents(&batch, &cf1));
batch.SetSavePoint(); // 5
batch.Put("X", "x");
ASSERT_OK(batch.Put("X", "x"));
ASSERT_EQ("PUT(A):a,PUT(A):aa,DEL(A),PUT(B):b,PUT(B):bb,PUT(C):cc,PUT(X):x,",
PrintContents(&batch, nullptr));
@ -1715,7 +1736,7 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) {
std::string value;
DBOptions db_options;
batch.SingleDelete("A");
ASSERT_OK(batch.SingleDelete("A"));
s = batch.GetFromBatch(db_options, "A", &value);
ASSERT_TRUE(s.IsNotFound());
@ -1725,10 +1746,10 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) {
ASSERT_EQ("SINGLE-DEL(A),", value);
batch.Clear();
batch.Put("A", "a");
batch.Put("A", "a2");
batch.Put("B", "b");
batch.SingleDelete("A");
ASSERT_OK(batch.Put("A", "a"));
ASSERT_OK(batch.Put("A", "a2"));
ASSERT_OK(batch.Put("B", "b"));
ASSERT_OK(batch.SingleDelete("A"));
s = batch.GetFromBatch(db_options, "A", &value);
ASSERT_TRUE(s.IsNotFound());
@ -1739,11 +1760,11 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) {
value = PrintContents(&batch, nullptr);
ASSERT_EQ("PUT(A):a,PUT(A):a2,SINGLE-DEL(A),PUT(B):b,", value);
batch.Put("C", "c");
batch.Put("A", "a3");
batch.Delete("B");
batch.SingleDelete("B");
batch.SingleDelete("C");
ASSERT_OK(batch.Put("C", "c"));
ASSERT_OK(batch.Put("A", "a3"));
ASSERT_OK(batch.Delete("B"));
ASSERT_OK(batch.SingleDelete("B"));
ASSERT_OK(batch.SingleDelete("C"));
s = batch.GetFromBatch(db_options, "A", &value);
ASSERT_OK(s);
@ -1761,12 +1782,12 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) {
",PUT(C):c,SINGLE-DEL(C),",
value);
batch.Put("B", "b4");
batch.Put("C", "c4");
batch.Put("D", "d4");
batch.SingleDelete("D");
batch.SingleDelete("D");
batch.Delete("A");
ASSERT_OK(batch.Put("B", "b4"));
ASSERT_OK(batch.Put("C", "c4"));
ASSERT_OK(batch.Put("D", "d4"));
ASSERT_OK(batch.SingleDelete("D"));
ASSERT_OK(batch.SingleDelete("D"));
ASSERT_OK(batch.Delete("A"));
s = batch.GetFromBatch(db_options, "A", &value);
ASSERT_TRUE(s.IsNotFound());
@ -1788,15 +1809,15 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteTest) {
}
TEST_F(WriteBatchWithIndexTest, SingleDeleteDeltaIterTest) {
Status s;
std::string value;
DBOptions db_options;
WriteBatchWithIndex batch(BytewiseComparator(), 20, true /* overwrite_key */);
batch.Put("A", "a");
batch.Put("A", "a2");
batch.Put("B", "b");
batch.SingleDelete("A");
batch.Delete("B");
ASSERT_OK(batch.Put("A", "a"));
ASSERT_OK(batch.Put("A", "a2"));
ASSERT_OK(batch.Put("B", "b"));
ASSERT_OK(batch.SingleDelete("A"));
ASSERT_OK(batch.Delete("B"));
KVMap map;
value = PrintContents(&batch, &map, nullptr);
@ -1806,20 +1827,20 @@ TEST_F(WriteBatchWithIndexTest, SingleDeleteDeltaIterTest) {
map["C"] = "cc";
map["D"] = "dd";
batch.SingleDelete("B");
batch.SingleDelete("C");
batch.SingleDelete("Z");
ASSERT_OK(batch.SingleDelete("B"));
ASSERT_OK(batch.SingleDelete("C"));
ASSERT_OK(batch.SingleDelete("Z"));
value = PrintContents(&batch, &map, nullptr);
ASSERT_EQ("D:dd,", value);
batch.Put("A", "a3");
batch.Put("B", "b3");
batch.SingleDelete("A");
batch.SingleDelete("A");
batch.SingleDelete("D");
batch.SingleDelete("D");
batch.Delete("D");
ASSERT_OK(batch.Put("A", "a3"));
ASSERT_OK(batch.Put("B", "b3"));
ASSERT_OK(batch.SingleDelete("A"));
ASSERT_OK(batch.SingleDelete("A"));
ASSERT_OK(batch.SingleDelete("D"));
ASSERT_OK(batch.SingleDelete("D"));
ASSERT_OK(batch.Delete("D"));
map["E"] = "ee";

Loading…
Cancel
Save