YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/docdb/docdb_test_util.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#ifndef YB_DOCDB_DOCDB_TEST_UTIL_H_
15
#define YB_DOCDB_DOCDB_TEST_UTIL_H_
16
17
#include <random>
18
#include <string>
19
#include <utility>
20
#include <vector>
21
22
#include "yb/docdb/docdb.h"
23
#include "yb/docdb/docdb_util.h"
24
#include "yb/docdb/in_mem_docdb.h"
25
#include "yb/docdb/subdocument.h"
26
27
#include "yb/util/strongly_typed_bool.h"
28
29
namespace yb {
30
namespace docdb {
31
32
using RandomNumberGenerator = std::mt19937_64;
33
34
// Maximum number of components in a randomly-generated DocKey.
35
static constexpr int kMaxNumRandomDocKeyParts = 10;
36
37
// Maximum number of subkeys in a randomly-generated SubDocKey.
38
static constexpr int kMaxNumRandomSubKeys = 10;
39
40
YB_STRONGLY_TYPED_BOOL(ResolveIntentsDuringRead);
41
YB_STRONGLY_TYPED_BOOL(UseHash);
42
43
// Intended only for testing, when we want to enable transaction aware code path for cases when we
44
// really have no transactions. This way we will test that transaction aware code path works
45
// correctly in absence of transactions and also doesn't use transaction status provider (it
46
// shouldn't because there are no transactions).
47
// TODO(dtxn) everywhere(?) in tests code where we use kNonTransactionalOperationContext we need
48
// to check both code paths - for transactional tables (passing kNonTransactionalOperationContext)
49
// and non-transactional tables (passing boost::none as transaction context).
50
// https://yugabyte.atlassian.net/browse/ENG-2177.
51
extern const TransactionOperationContext kNonTransactionalOperationContext;
52
53
// Note: test data generator methods below are using a non-const reference for the random number
54
// generator for simplicity, even though it is against Google C++ Style Guide. If we used a pointer,
55
// we would have to invoke the RNG as (*rng)().
56
57
// Generate a random primitive value.
58
PrimitiveValue GenRandomPrimitiveValue(RandomNumberGenerator* rng);
59
60
// Generate a random sequence of primitive values.
61
std::vector<PrimitiveValue> GenRandomPrimitiveValues(RandomNumberGenerator* rng,
62
                                                     int max_num = kMaxNumRandomDocKeyParts);
63
64
// Generate a "minimal" DocKey.
65
DocKey CreateMinimalDocKey(RandomNumberGenerator* rng, UseHash use_hash);
66
67
// Generate a random DocKey with up to the default number of components.
68
DocKey GenRandomDocKey(RandomNumberGenerator* rng, UseHash use_hash);
69
70
std::vector<DocKey> GenRandomDocKeys(RandomNumberGenerator* rng, UseHash use_hash, int num_keys);
71
72
std::vector<SubDocKey> GenRandomSubDocKeys(RandomNumberGenerator* rng,
73
                                           UseHash use_hash,
74
                                           int num_keys);
75
76
template<typename T>
77
0
const T& RandomElementOf(const std::vector<T>& v, RandomNumberGenerator* rng) {
78
0
  return v[(*rng)() % v.size()];
79
0
}
Unexecuted instantiation: _ZN2yb5docdb15RandomElementOfINS0_6DocKeyEEERKT_RKNSt3__16vectorIS3_NS6_9allocatorIS3_EEEEPNS6_23mersenne_twister_engineIyLm64ELm312ELm156ELm31ELy13043109905998158313ELm29ELy6148914691236517205ELm17ELy8202884508482404352ELm37ELy18444473444759240704ELm43ELy6364136223846793005EEE
Unexecuted instantiation: _ZN2yb5docdb15RandomElementOfINS0_14PrimitiveValueEEERKT_RKNSt3__16vectorIS3_NS6_9allocatorIS3_EEEEPNS6_23mersenne_twister_engineIyLm64ELm312ELm156ELm31ELy13043109905998158313ELm29ELy6148914691236517205ELm17ELy8202884508482404352ELm37ELy18444473444759240704ELm43ELy6364136223846793005EEE
80
81
// Represents a full logical snapshot of a RocksDB instance. An instance of this class will record
82
// the state of a RocksDB instance via Capture, which can then be written to a new RocksDB instance
83
// via RestoreTo.
84
class LogicalRocksDBDebugSnapshot {
85
 public:
86
0
  LogicalRocksDBDebugSnapshot() {}
87
  void Capture(rocksdb::DB* rocksdb);
88
  void RestoreTo(rocksdb::DB *rocksdb) const;
89
 private:
90
  std::vector<std::pair<std::string, std::string>> kvs;
91
  string docdb_debug_dump_str;
92
};
93
94
class DocDBRocksDBFixture : public DocDBRocksDBUtil {
95
 public:
96
  void AssertDocDbDebugDumpStrEq(const string &expected);
97
  void FullyCompactHistoryBefore(HybridTime history_cutoff);
98
99
  // num_files_to_compact - number of files that should participate in the minor compaction
100
  // start_index - the index of the file to start with (0 = the oldest file, -1 = compact
101
  //               num_files_to_compact newest files).
102
  void MinorCompaction(
103
      HybridTime history_cutoff, size_t num_files_to_compact, ssize_t start_index = -1);
104
105
  size_t NumSSTableFiles();
106
  StringVector SSTableFileNames();
107
108
  CHECKED_STATUS InitRocksDBDir() override;
109
  CHECKED_STATUS InitRocksDBOptions() override;
110
  TabletId tablet_id() override;
111
  CHECKED_STATUS FormatDocWriteBatch(const DocWriteBatch& dwb, std::string* dwb_str);
112
};
113
114
// Perform a major compaction on the given database.
115
CHECKED_STATUS FullyCompactDB(rocksdb::DB* rocksdb);
116
117
class DocDBLoadGenerator {
118
 public:
119
  static constexpr uint64_t kDefaultRandomSeed = 23874297385L;
120
121
  DocDBLoadGenerator(DocDBRocksDBFixture* fixture,
122
                     int num_doc_keys,
123
                     int num_unique_subkeys,
124
                     UseHash use_hash,
125
                     ResolveIntentsDuringRead resolve_intents = ResolveIntentsDuringRead::kTrue,
126
                     int deletion_chance = 100,
127
                     int max_nesting_level = 10,
128
                     uint64 random_seed = kDefaultRandomSeed,
129
                     int verification_frequency = 100);
130
  ~DocDBLoadGenerator();
131
132
  // Performs a random DocDB operation according to the configured options. This also verifies
133
  // the consistency of RocksDB-backed DocDB (which is close to the production codepath) with an
134
  // in-memory non-thread-safe data structure maintained just for sanity checking. Such verification
135
  // is only performed from time to time, not on every call to PerformOperation.
136
  //
137
  // The caller should wrap calls to this function in NO_FATALS.
138
  //
139
  // @param compact_history If this is set, we perform the RocksDB-backed DocDB read before and
140
  //                        after history cleanup, and verify that the state of the document is
141
  //                        the same in both cases.
142
  void PerformOperation(bool compact_history = false);
143
144
  // @return The next "iteration number" to be performed when PerformOperation is called.
145
0
  int next_iteration() const { return iteration_; }
146
147
  // The hybrid_time of the last operation performed is always based on the last iteration number.
148
  // Most times it will be one less than what next_iteration() would return, if we convert the
149
  // hybrid_time to an integer. This can only be called after PerformOperation() has been called at
150
  // least once.
151
  //
152
  // @return The hybrid_time of the last operation performed.
153
  HybridTime last_operation_ht() const;
154
155
  void FlushRocksDB();
156
157
  // Generate a random unsiged 64-bit integer using the random number generator maintained by this
158
  // object.
159
0
  uint64_t NextRandom() { return random_(); }
160
161
  // Generate a random integer from 0 to n - 1 using the random number generator maintained by this
162
  // object.
163
0
  int NextRandomInt(int n) { return NextRandom() % n; }
164
165
  // Capture and remember a "logical DocDB snapshot" (not to be confused with what we call
166
  // a "logical RocksDB snapshot"). This keeps track of all document keys and corresponding
167
  // documents existing at the latest hybrid_time.
168
  void CaptureDocDbSnapshot();
169
170
  void VerifyOldestSnapshot();
171
  void VerifyRandomDocDbSnapshot();
172
173
  // Perform a flashback query at the time of the latest snapshot before the given cleanup
174
  // hybrid_time and compare it to the state recorded with the snapshot. Expect the two to diverge
175
  // using ASSERT_TRUE. This is used for testing that old history is actually being cleaned up
176
  // during compactions.
177
  void CheckIfOldestSnapshotIsStillValid(const HybridTime cleanup_ht);
178
179
  // Removes all snapshots taken before the given hybrid_time. This is done to test history cleanup.
180
  void RemoveSnapshotsBefore(HybridTime ht);
181
182
0
  size_t num_divergent_old_snapshot() { return divergent_snapshot_ht_and_cleanup_ht_.size(); }
183
184
0
  std::vector<std::pair<int, int>> divergent_snapshot_ht_and_cleanup_ht() {
185
0
    return divergent_snapshot_ht_and_cleanup_ht_;
186
0
  }
187
188
 private:
189
0
  rocksdb::DB* rocksdb() { return fixture_->rocksdb(); }
190
0
  DocDB doc_db() { return fixture_->doc_db(); }
191
192
  DocDBRocksDBFixture* fixture_;
193
  RandomNumberGenerator random_;  // Using default seed.
194
  std::vector<DocKey> doc_keys_;
195
196
  // Whether we should pass transaction context during reads, so DocDB tries to resolve write
197
  // intents.
198
  const ResolveIntentsDuringRead resolve_intents_;
199
200
  std::vector<PrimitiveValue> possible_subkeys_;
201
  int iteration_;
202
  InMemDocDbState in_mem_docdb_;
203
204
  // Deletions happen once every this number of iterations.
205
  const int deletion_chance_;
206
207
  // If this is 1, we'll only use primitive-type documents. If this is 2, we'll make some documents
208
  // objects (maps). If this is 3, we'll use maps of maps, etc.
209
  const int max_nesting_level_;
210
211
  HybridTime last_operation_ht_;
212
213
  std::vector<InMemDocDbState> docdb_snapshots_;
214
215
  // HybridTimes and cleanup hybrid_times of examples when
216
  std::vector<std::pair<int, int>> divergent_snapshot_ht_and_cleanup_ht_;
217
218
  // PerformOperation() will verify DocDB state consistency once in this number of iterations.
219
  const int verification_frequency_;
220
221
  const InMemDocDbState& GetOldestSnapshot();
222
223
  // Perform a "flashback query" in the RocksDB-based DocDB at the hybrid_time
224
  // snapshot.captured_at() and verify that the state matches what's in the provided snapshot.
225
  // This is only invoked on snapshots whose capture hybrid_time has not been garbage-collected,
226
  // and therefore we always expect this verification to succeed.
227
  //
228
  // Calls to this function should be wrapped in NO_FATALS.
229
  void VerifySnapshot(const InMemDocDbState& snapshot);
230
231
  // Look at whether the given snapshot is still valid, and if not, track it in
232
  // divergent_snapshot_ht_and_cleanup_ht_, so we can later verify that some snapshots have become
233
  // invalid after history cleanup.
234
  void RecordSnapshotDivergence(const InMemDocDbState &snapshot, HybridTime cleanup_ht);
235
236
  TransactionOperationContext GetReadOperationTransactionContext();
237
};
238
239
// Used for pre-processing multi-line DocDB debug dump strings in tests.  Removes common indentation
240
// and C++-style comments and applies backslash line continuation.
241
string TrimDocDbDebugDumpStr(const string& debug_dump);
242
243
#define ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(expected) \
244
0
  do { \
245
0
    ASSERT_STR_EQ_VERBOSE_TRIMMED( \
246
0
        ::yb::util::ApplyEagerLineContinuation(expected), DocDBDebugDumpToStr()); \
247
0
  } while(false)
248
249
}  // namespace docdb
250
}  // namespace yb
251
252
#endif  // YB_DOCDB_DOCDB_TEST_UTIL_H_