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 #pragma once
7 
8 #include <cinttypes>
9 
10 #include "util/set_comparator.h"
11 
12 namespace ROCKSDB_NAMESPACE {
13 // During recovery if the memtable is flushed we cannot rely on its help on
14 // duplicate key detection and as key insert will not be attempted. This class
15 // will be used as a emulator of memtable to tell if insertion of a key/seq
16 // would have resulted in duplication.
17 class DuplicateDetector {
18  public:
DuplicateDetector(DBImpl * db)19   explicit DuplicateDetector(DBImpl* db) : db_(db) {}
IsDuplicateKeySeq(uint32_t cf,const Slice & key,SequenceNumber seq)20   bool IsDuplicateKeySeq(uint32_t cf, const Slice& key, SequenceNumber seq) {
21     assert(seq >= batch_seq_);
22     if (batch_seq_ != seq) {  // it is a new batch
23       keys_.clear();
24     }
25     batch_seq_ = seq;
26     CFKeys& cf_keys = keys_[cf];
27     if (cf_keys.size() == 0) {  // just inserted
28       InitWithComp(cf);
29     }
30     auto it = cf_keys.insert(key);
31     if (it.second == false) {  // second is false if a element already existed.
32       keys_.clear();
33       InitWithComp(cf);
34       keys_[cf].insert(key);
35       return true;
36     }
37     return false;
38   }
39 
40  private:
41   SequenceNumber batch_seq_ = 0;
42   DBImpl* db_;
43   using CFKeys = std::set<Slice, SetComparator>;
44   std::map<uint32_t, CFKeys> keys_;
InitWithComp(const uint32_t cf)45   void InitWithComp(const uint32_t cf) {
46     auto h = db_->GetColumnFamilyHandle(cf);
47     if (!h) {
48       // TODO(myabandeh): This is not a concern in MyRocks as drop cf is not
49       // implemented yet. When it does, we should return proper error instead
50       // of throwing exception.
51       ROCKS_LOG_FATAL(
52           db_->immutable_db_options().info_log,
53           "Recovering an entry from the dropped column family %" PRIu32
54           ". WAL must must have been emptied before dropping the column "
55           "family", cf);
56 #ifndef ROCKSDB_LITE
57       throw std::runtime_error(
58           "Recovering an entry from a dropped column family. "
59           "WAL must must have been flushed before dropping the column "
60           "family");
61 #endif
62       return;
63     }
64     auto cmp = h->GetComparator();
65     keys_[cf] = CFKeys(SetComparator(cmp));
66   }
67 };
68 }  // namespace ROCKSDB_NAMESPACE
69