diff --git a/LICENSE b/LICENSE index 716ad9e74..b13290186 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ BSD License For rocksdb software -Copyright (c) 2013, Facebook, Inc. +Copyright (c) 2014, Facebook, Inc. All rights reserved. --------------------------------------------------------------------- diff --git a/Makefile b/Makefile index 85c9d521e..81fd0032a 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ else PLATFORM_CCFLAGS += $(JEMALLOC_INCLUDE) -DHAVE_JEMALLOC endif -WARNING_FLAGS = -Wall -Werror +WARNING_FLAGS = -Wall -Werror -Wno-sign-compare CFLAGS += -g $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) CXXFLAGS += -g $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) -Woverloaded-virtual diff --git a/db/db_iter.cc b/db/db_iter.cc index b8d9038a1..e7491f7e3 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -379,10 +379,10 @@ void DBIter::FindPrevUserEntry() { uint64_t num_skipped = 0; ValueType value_type = kTypeDeletion; + bool saved_key_valid = true; if (iter_->Valid()) { do { ParsedInternalKey ikey; - bool saved_key_cleared = false; if (ParseKey(&ikey) && ikey.sequence <= sequence_) { if ((value_type != kTypeDeletion) && user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { @@ -393,7 +393,7 @@ void DBIter::FindPrevUserEntry() { if (value_type == kTypeDeletion) { saved_key_.clear(); ClearSavedValue(); - saved_key_cleared = true; + saved_key_valid = false; } else { Slice raw_value = iter_->value(); if (saved_value_.capacity() > raw_value.size() + 1048576) { @@ -403,13 +403,17 @@ void DBIter::FindPrevUserEntry() { SaveKey(ExtractUserKey(iter_->key()), &saved_key_); saved_value_.assign(raw_value.data(), raw_value.size()); } + } else { + // In the case of ikey.sequence > sequence_, we might have already + // iterated to a different user key. + saved_key_valid = false; } num_skipped++; // If we have sequentially iterated via numerous keys and still not // found the prev user-key, then it is better to seek so that we can // avoid too many key comparisons. We seek to the first occurence of // our current key by looking for max sequence number. - if (!saved_key_cleared && num_skipped > max_skip_) { + if (saved_key_valid && num_skipped > max_skip_) { num_skipped = 0; std::string last_key; AppendInternalKey(&last_key, diff --git a/db/db_test.cc b/db/db_test.cc index f0df3d3f3..cce43ae9d 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -1504,6 +1504,75 @@ TEST(DBTest, IterSeekBeforePrev) { delete iter; } +TEST(DBTest, IterNextWithNewerSeq) { + ASSERT_OK(Put("0", "0")); + dbfull()->Flush(FlushOptions()); + ASSERT_OK(Put("a", "b")); + ASSERT_OK(Put("c", "d")); + ASSERT_OK(Put("d", "e")); + auto iter = db_->NewIterator(ReadOptions()); + + // Create a key that needs to be skipped for Seq too new + for (uint64_t i = 0; i < last_options_.max_sequential_skip_in_iterations + 1; + i++) { + ASSERT_OK(Put("b", "f")); + } + + iter->Seek(Slice("a")); + ASSERT_EQ(IterStatus(iter), "a->b"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->d"); + delete iter; +} + +TEST(DBTest, IterPrevWithNewerSeq) { + ASSERT_OK(Put("0", "0")); + dbfull()->Flush(FlushOptions()); + ASSERT_OK(Put("a", "b")); + ASSERT_OK(Put("c", "d")); + ASSERT_OK(Put("d", "e")); + auto iter = db_->NewIterator(ReadOptions()); + + // Create a key that needs to be skipped for Seq too new + for (uint64_t i = 0; i < last_options_.max_sequential_skip_in_iterations + 1; + i++) { + ASSERT_OK(Put("b", "f")); + } + + iter->Seek(Slice("d")); + ASSERT_EQ(IterStatus(iter), "d->e"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "c->d"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->b"); + + iter->Prev(); + delete iter; +} + +TEST(DBTest, IterPrevWithNewerSeq2) { + ASSERT_OK(Put("0", "0")); + dbfull()->Flush(FlushOptions()); + ASSERT_OK(Put("a", "b")); + ASSERT_OK(Put("c", "d")); + ASSERT_OK(Put("d", "e")); + auto iter = db_->NewIterator(ReadOptions()); + iter->Seek(Slice("c")); + ASSERT_EQ(IterStatus(iter), "c->d"); + + // Create a key that needs to be skipped for Seq too new + for (uint64_t i = 0; i < last_options_.max_sequential_skip_in_iterations + 1; + i++) { + ASSERT_OK(Put("b", "f")); + } + + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->b"); + + iter->Prev(); + delete iter; +} + TEST(DBTest, IterEmpty) { do { CreateAndReopenWithCF({"pikachu"}); diff --git a/db/log_test.cc b/db/log_test.cc index b28343e63..6577a6a9c 100644 --- a/db/log_test.cc +++ b/db/log_test.cc @@ -451,7 +451,7 @@ TEST(LogTest, TruncatedTrailingRecordIsIgnored) { ShrinkSize(4); // Drop all payload as well as a header byte ASSERT_EQ("EOF", Read()); // Truncated last record is ignored, not treated as an error - ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ(0U, DroppedBytes()); ASSERT_EQ("", ReportMessage()); } @@ -470,7 +470,7 @@ TEST(LogTest, BadLengthAtEndIsIgnored) { Write("foo"); ShrinkSize(1); ASSERT_EQ("EOF", Read()); - ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ(0U, DroppedBytes()); ASSERT_EQ("", ReportMessage()); } @@ -528,7 +528,7 @@ TEST(LogTest, MissingLastIsIgnored) { ShrinkSize(14); ASSERT_EQ("EOF", Read()); ASSERT_EQ("", ReportMessage()); - ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ(0U, DroppedBytes()); } TEST(LogTest, PartialLastIsIgnored) { @@ -537,7 +537,7 @@ TEST(LogTest, PartialLastIsIgnored) { ShrinkSize(1); ASSERT_EQ("EOF", Read()); ASSERT_EQ("", ReportMessage()); - ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ(0U, DroppedBytes()); } TEST(LogTest, ErrorJoinsRecords) { diff --git a/tools/db_stress.cc b/tools/db_stress.cc index 3e0e41dcc..5ee26e556 100644 --- a/tools/db_stress.cc +++ b/tools/db_stress.cc @@ -972,10 +972,10 @@ class StressTest { prefixes[i].resize(FLAGS_prefix_size); prefix_slices[i] = Slice(prefixes[i]); readoptionscopy[i] = readoptions; - readoptionscopy[i].prefix = &prefix_slices[i]; + readoptionscopy[i].prefix_seek = true; readoptionscopy[i].snapshot = snapshot; iters[i] = db_->NewIterator(readoptionscopy[i], column_family); - iters[i]->SeekToFirst(); + iters[i]->Seek(prefix_slices[i]); } int count = 0; @@ -1157,11 +1157,11 @@ class StressTest { // prefix if (!FLAGS_test_batches_snapshots) { Slice prefix = Slice(key.data(), FLAGS_prefix_size); - read_opts.prefix = &prefix; + read_opts.prefix_seek = true; Iterator* iter = db_->NewIterator(read_opts, column_family); int64_t count = 0; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - assert(iter->key().starts_with(prefix)); + for (iter->Seek(prefix); + iter->Valid() && iter->key().starts_with(prefix); iter->Next()) { ++count; } assert(count <= @@ -1175,7 +1175,6 @@ class StressTest { } else { MultiPrefixScan(thread, read_opts, column_family, key); } - read_opts.prefix = nullptr; } else if (prefixBound <= prob_op && prob_op < writeBound) { // OPERATION write uint32_t value_base = thread->rand.Next(); diff --git a/util/env_test.cc b/util/env_test.cc index e17027a39..00d813fa4 100644 --- a/util/env_test.cc +++ b/util/env_test.cc @@ -172,8 +172,8 @@ TEST(EnvPosixTest, TwoPools) { env_->SetBackgroundThreads(kLowPoolSize); env_->SetBackgroundThreads(kHighPoolSize, Env::Priority::HIGH); - ASSERT_EQ(0, env_->GetThreadPoolQueueLen(Env::Priority::LOW)); - ASSERT_EQ(0, env_->GetThreadPoolQueueLen(Env::Priority::HIGH)); + ASSERT_EQ(0U, env_->GetThreadPoolQueueLen(Env::Priority::LOW)); + ASSERT_EQ(0U, env_->GetThreadPoolQueueLen(Env::Priority::HIGH)); // schedule same number of jobs in each pool for (int i = 0; i < kJobs; i++) { @@ -182,10 +182,11 @@ TEST(EnvPosixTest, TwoPools) { } // Wait a short while for the jobs to be dispatched. Env::Default()->SleepForMicroseconds(kDelayMicros); - ASSERT_EQ(kJobs - kLowPoolSize, env_->GetThreadPoolQueueLen()); - ASSERT_EQ(kJobs - kLowPoolSize, + ASSERT_EQ((unsigned int)(kJobs - kLowPoolSize), + env_->GetThreadPoolQueueLen()); + ASSERT_EQ((unsigned int)(kJobs - kLowPoolSize), env_->GetThreadPoolQueueLen(Env::Priority::LOW)); - ASSERT_EQ(kJobs - kHighPoolSize, + ASSERT_EQ((unsigned int)(kJobs - kHighPoolSize), env_->GetThreadPoolQueueLen(Env::Priority::HIGH)); // wait for all jobs to finish @@ -194,8 +195,8 @@ TEST(EnvPosixTest, TwoPools) { env_->SleepForMicroseconds(kDelayMicros); } - ASSERT_EQ(0, env_->GetThreadPoolQueueLen(Env::Priority::LOW)); - ASSERT_EQ(0, env_->GetThreadPoolQueueLen(Env::Priority::HIGH)); + ASSERT_EQ(0U, env_->GetThreadPoolQueueLen(Env::Priority::LOW)); + ASSERT_EQ(0U, env_->GetThreadPoolQueueLen(Env::Priority::HIGH)); } bool IsSingleVarint(const std::string& s) { @@ -296,18 +297,18 @@ TEST(EnvPosixTest, AllocateTest) { struct stat f_stat; stat(fname.c_str(), &f_stat); - ASSERT_EQ(data.size(), f_stat.st_size); + ASSERT_EQ((unsigned int)data.size(), f_stat.st_size); // verify that blocks are preallocated - ASSERT_EQ(kPreallocateSize / kBlockSize, f_stat.st_blocks); + ASSERT_EQ((unsigned int)(kPreallocateSize / kBlockSize), f_stat.st_blocks); // close the file, should deallocate the blocks wfile.reset(); stat(fname.c_str(), &f_stat); - ASSERT_EQ(data.size(), f_stat.st_size); + ASSERT_EQ((unsigned int)data.size(), f_stat.st_size); // verify that preallocated blocks were deallocated on file close size_t data_blocks_pages = ((data.size() + kPageSize - 1) / kPageSize); - ASSERT_EQ(data_blocks_pages * kPageSize / kBlockSize, f_stat.st_blocks); + ASSERT_EQ((unsigned int)(data_blocks_pages * kPageSize / kBlockSize), f_stat.st_blocks); } #endif