YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/utilities/checkpoint/checkpoint_test.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
21
// Use of this source code is governed by a BSD-style license that can be
22
// found in the LICENSE file. See the AUTHORS file for names of contributors.
23
24
// Syncpoint prevents us building and running tests in release
25
#ifndef ROCKSDB_LITE
26
27
#ifndef OS_WIN
28
#include <unistd.h>
29
#endif
30
#include <iostream>
31
#include <thread>
32
#include <utility>
33
#include "yb/rocksdb/db/db_impl.h"
34
#include "yb/rocksdb/port/stack_trace.h"
35
#include "yb/rocksdb/db.h"
36
#include "yb/rocksdb/env.h"
37
#include "yb/rocksdb/utilities/checkpoint.h"
38
#include "yb/rocksdb/util/sync_point.h"
39
#include "yb/rocksdb/util/testharness.h"
40
#include "yb/rocksdb/util/testutil.h"
41
#include "yb/rocksdb/util/xfunc.h"
42
43
#include "yb/util/test_util.h"
44
45
namespace rocksdb {
46
class DBTest : public RocksDBTest {
47
 protected:
48
  // Sequence of option configurations to try
49
  enum OptionConfig {
50
    kDefault = 0,
51
  };
52
  int option_config_;
53
54
 public:
55
  std::string dbname_;
56
  std::string alternative_wal_dir_;
57
  Env* env_;
58
  DB* db_;
59
  Options last_options_;
60
  std::vector<ColumnFamilyHandle*> handles_;
61
62
2
  DBTest() : env_(Env::Default()) {
63
2
    env_->SetBackgroundThreads(1, Env::LOW);
64
2
    env_->SetBackgroundThreads(1, Env::HIGH);
65
2
    dbname_ = test::TmpDir(env_) + "/db_test";
66
2
    alternative_wal_dir_ = dbname_ + "/wal";
67
2
    auto options = CurrentOptions();
68
2
    auto delete_options = options;
69
2
    delete_options.wal_dir = alternative_wal_dir_;
70
2
    EXPECT_OK(DestroyDB(dbname_, delete_options));
71
    // Destroy it for not alternative WAL dir is used.
72
2
    EXPECT_OK(DestroyDB(dbname_, options));
73
2
    db_ = nullptr;
74
2
    Reopen(options);
75
2
  }
76
77
2
  ~DBTest() {
78
2
    rocksdb::SyncPoint::GetInstance()->DisableProcessing();
79
2
    rocksdb::SyncPoint::GetInstance()->LoadDependency({});
80
2
    rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
81
2
    Close();
82
2
    Options options;
83
2
    options.db_paths.emplace_back(dbname_, 0);
84
2
    options.db_paths.emplace_back(dbname_ + "_2", 0);
85
2
    options.db_paths.emplace_back(dbname_ + "_3", 0);
86
2
    options.db_paths.emplace_back(dbname_ + "_4", 0);
87
2
    EXPECT_OK(DestroyDB(dbname_, options));
88
2
  }
89
90
  // Return the current option configuration.
91
4
  Options CurrentOptions() {
92
4
    Options options;
93
4
    options.env = env_;
94
4
    options.create_if_missing = true;
95
4
    return options;
96
4
  }
97
98
  void CreateColumnFamilies(const std::vector<std::string>& cfs,
99
1
                            const Options& options) {
100
1
    ColumnFamilyOptions cf_opts(options);
101
1
    size_t cfi = handles_.size();
102
1
    handles_.resize(cfi + cfs.size());
103
5
    for (auto cf : cfs) {
104
5
      ASSERT_OK(db_->CreateColumnFamily(cf_opts, cf, &handles_[cfi++]));
105
5
    }
106
1
  }
107
108
  void CreateAndReopenWithCF(const std::vector<std::string>& cfs,
109
1
                             const Options& options) {
110
1
    CreateColumnFamilies(cfs, options);
111
1
    std::vector<std::string> cfs_plus_default = cfs;
112
1
    cfs_plus_default.insert(cfs_plus_default.begin(), kDefaultColumnFamilyName);
113
1
    ReopenWithColumnFamilies(cfs_plus_default, options);
114
1
  }
115
116
  void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
117
0
                                const std::vector<Options>& options) {
118
0
    ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
119
0
  }
120
121
  void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
122
1
                                const Options& options) {
123
1
    ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
124
1
  }
125
126
  Status TryReopenWithColumnFamilies(
127
      const std::vector<std::string>& cfs,
128
1
      const std::vector<Options>& options) {
129
1
    Close();
130
1
    EXPECT_EQ(cfs.size(), options.size());
131
1
    std::vector<ColumnFamilyDescriptor> column_families;
132
7
    for (size_t i = 0; i < cfs.size(); ++i) {
133
6
      column_families.push_back(ColumnFamilyDescriptor(cfs[i], options[i]));
134
6
    }
135
1
    DBOptions db_opts = DBOptions(options[0]);
136
1
    return DB::Open(db_opts, dbname_, column_families, &handles_, &db_);
137
1
  }
138
139
  Status TryReopenWithColumnFamilies(const std::vector<std::string>& cfs,
140
1
                                     const Options& options) {
141
1
    Close();
142
1
    std::vector<Options> v_opts(cfs.size(), options);
143
1
    return TryReopenWithColumnFamilies(cfs, v_opts);
144
1
  }
145
146
2
  void Reopen(const Options& options) {
147
2
    ASSERT_OK(TryReopen(options));
148
2
  }
149
150
6
  void Close() {
151
11
    for (auto h : handles_) {
152
11
      delete h;
153
11
    }
154
6
    handles_.clear();
155
6
    delete db_;
156
6
    db_ = nullptr;
157
6
  }
158
159
0
  void DestroyAndReopen(const Options& options) {
160
0
    // Destroy using last options
161
0
    Destroy(last_options_);
162
0
    ASSERT_OK(TryReopen(options));
163
0
  }
164
165
0
  void Destroy(const Options& options) {
166
0
    Close();
167
0
    ASSERT_OK(DestroyDB(dbname_, options));
168
0
  }
169
170
0
  Status ReadOnlyReopen(const Options& options) {
171
0
    return DB::OpenForReadOnly(options, dbname_, &db_);
172
0
  }
173
174
2
  Status TryReopen(const Options& options) {
175
2
    Close();
176
2
    last_options_ = options;
177
2
    return DB::Open(options, dbname_, &db_);
178
2
  }
179
180
2
  Status Flush(int cf = 0) {
181
2
    if (cf == 0) {
182
2
      return db_->Flush(FlushOptions());
183
0
    } else {
184
0
      return db_->Flush(FlushOptions(), handles_[cf]);
185
0
    }
186
2
  }
187
188
2
  Status Put(const Slice& k, const Slice& v, WriteOptions wo = WriteOptions()) {
189
2
    return db_->Put(wo, k, v);
190
2
  }
191
192
  Status Put(int cf, const Slice& k, const Slice& v,
193
17
             WriteOptions wo = WriteOptions()) {
194
17
    return db_->Put(wo, handles_[cf], k, v);
195
17
  }
196
197
0
  Status Delete(const std::string& k) {
198
0
    return db_->Delete(WriteOptions(), k);
199
0
  }
200
201
0
  Status Delete(int cf, const std::string& k) {
202
0
    return db_->Delete(WriteOptions(), handles_[cf], k);
203
0
  }
204
205
3
  std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
206
3
    ReadOptions options;
207
3
    options.verify_checksums = true;
208
3
    options.snapshot = snapshot;
209
3
    std::string result;
210
3
    Status s = db_->Get(options, k, &result);
211
3
    if (s.IsNotFound()) {
212
0
      result = "NOT_FOUND";
213
3
    } else if (!s.ok()) {
214
0
      result = s.ToString();
215
0
    }
216
3
    return result;
217
3
  }
218
219
  std::string Get(int cf, const std::string& k,
220
0
                  const Snapshot* snapshot = nullptr) {
221
0
    ReadOptions options;
222
0
    options.verify_checksums = true;
223
0
    options.snapshot = snapshot;
224
0
    std::string result;
225
0
    Status s = db_->Get(options, handles_[cf], k, &result);
226
0
    if (s.IsNotFound()) {
227
0
      result = "NOT_FOUND";
228
0
    } else if (!s.ok()) {
229
0
      result = s.ToString();
230
0
    }
231
0
    return result;
232
0
  }
233
};
234
235
1
TEST_F(DBTest, GetSnapshotLink) {
236
1
    Options options;
237
1
    const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
238
1
    DB* snapshotDB;
239
1
    ReadOptions roptions;
240
1
    std::string result;
241
242
1
    options = CurrentOptions();
243
1
    delete db_;
244
1
    db_ = nullptr;
245
1
    ASSERT_OK(DestroyDB(dbname_, options));
246
1
    if (env_->DirExists(snapshot_name)) {
247
0
      ASSERT_OK(DestroyDB(snapshot_name, options));
248
0
      ASSERT_OK(env_->DeleteDir(snapshot_name));
249
0
    }
250
251
    // Create a database
252
1
    Status s;
253
1
    options.create_if_missing = true;
254
1
    ASSERT_OK(DB::Open(options, dbname_, &db_));
255
1
    std::string key = std::string("foo");
256
1
    ASSERT_OK(Put(key, "v1"));
257
    // Take a snapshot
258
1
    ASSERT_OK(checkpoint::CreateCheckpoint(db_, snapshot_name));
259
    // Overwrite the snapshot.
260
1
    ASSERT_OK(checkpoint::CreateCheckpoint(db_, snapshot_name));
261
1
    ASSERT_OK(Put(key, "v2"));
262
1
    ASSERT_EQ("v2", Get(key));
263
1
    ASSERT_OK(Flush());
264
1
    ASSERT_EQ("v2", Get(key));
265
    // Open snapshot and verify contents while DB is running
266
1
    options.create_if_missing = false;
267
1
    ASSERT_OK(DB::Open(options, snapshot_name, &snapshotDB));
268
1
    ASSERT_OK(snapshotDB->Get(roptions, key, &result));
269
1
    ASSERT_EQ("v1", result);
270
1
    delete snapshotDB;
271
1
    snapshotDB = nullptr;
272
1
    delete db_;
273
1
    db_ = nullptr;
274
275
    // Destroy original DB
276
1
    ASSERT_OK(DestroyDB(dbname_, options));
277
278
    // Open snapshot and verify contents
279
1
    options.create_if_missing = false;
280
1
    dbname_ = snapshot_name;
281
1
    ASSERT_OK(DB::Open(options, dbname_, &db_));
282
1
    ASSERT_EQ("v1", Get(key));
283
1
    delete db_;
284
1
    db_ = nullptr;
285
1
    ASSERT_OK(DestroyDB(dbname_, options));
286
287
    // Restore DB name
288
1
    dbname_ = test::TmpDir(env_) + "/db_test";
289
1
}
290
291
1
TEST_F(DBTest, CheckpointCF) {
292
1
  Options options = CurrentOptions();
293
1
  CreateAndReopenWithCF({"one", "two", "three", "four", "five"}, options);
294
1
  rocksdb::SyncPoint::GetInstance()->LoadDependency(
295
1
      {{"DBTest::CheckpointCF:2",
296
1
        "DBImpl::GetLiveFiles:2"},
297
1
       {"DBImpl::GetLiveFiles:1",
298
1
        "DBTest::CheckpointCF:1"}});
299
300
1
  rocksdb::SyncPoint::GetInstance()->EnableProcessing();
301
302
1
  ASSERT_OK(Put(0, "Default", "Default"));
303
1
  ASSERT_OK(Put(1, "one", "one"));
304
1
  ASSERT_OK(Put(2, "two", "two"));
305
1
  ASSERT_OK(Put(3, "three", "three"));
306
1
  ASSERT_OK(Put(4, "four", "four"));
307
1
  ASSERT_OK(Put(5, "five", "five"));
308
309
1
  const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
310
1
  DB* snapshotDB;
311
1
  ReadOptions roptions;
312
1
  std::string result;
313
1
  std::vector<ColumnFamilyHandle*> cphandles;
314
315
1
  ASSERT_OK(DestroyDB(snapshot_name, options));
316
1
  if (env_->DirExists(snapshot_name)) {
317
0
    ASSERT_OK(env_->DeleteDir(snapshot_name));
318
0
  }
319
320
1
  Status s;
321
  // Take a snapshot
322
1
  std::thread t([&]() {
323
1
    ASSERT_OK(checkpoint::CreateCheckpoint(db_, snapshot_name));
324
1
  });
325
1
  TEST_SYNC_POINT("DBTest::CheckpointCF:1");
326
1
  ASSERT_OK(Put(0, "Default", "Default1"));
327
1
  ASSERT_OK(Put(1, "one", "eleven"));
328
1
  ASSERT_OK(Put(2, "two", "twelve"));
329
1
  ASSERT_OK(Put(3, "three", "thirteen"));
330
1
  ASSERT_OK(Put(4, "four", "fourteen"));
331
1
  ASSERT_OK(Put(5, "five", "fifteen"));
332
1
  TEST_SYNC_POINT("DBTest::CheckpointCF:2");
333
1
  t.join();
334
1
  rocksdb::SyncPoint::GetInstance()->DisableProcessing();
335
1
  ASSERT_OK(Put(1, "one", "twentyone"));
336
1
  ASSERT_OK(Put(2, "two", "twentytwo"));
337
1
  ASSERT_OK(Put(3, "three", "twentythree"));
338
1
  ASSERT_OK(Put(4, "four", "twentyfour"));
339
1
  ASSERT_OK(Put(5, "five", "twentyfive"));
340
1
  ASSERT_OK(Flush());
341
342
  // Open snapshot and verify contents while DB is running
343
1
  options.create_if_missing = false;
344
1
  std::vector<std::string> cfs;
345
1
  cfs = {kDefaultColumnFamilyName, "one", "two", "three", "four", "five"};
346
1
  std::vector<ColumnFamilyDescriptor> column_families;
347
7
    for (size_t i = 0; i < cfs.size(); ++i) {
348
6
      column_families.push_back(ColumnFamilyDescriptor(cfs[i], options));
349
6
    }
350
1
  ASSERT_OK(DB::Open(options, snapshot_name,
351
1
        column_families, &cphandles, &snapshotDB));
352
1
  ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
353
1
  ASSERT_EQ("Default1", result);
354
1
  ASSERT_OK(snapshotDB->Get(roptions, cphandles[1], "one", &result));
355
1
  ASSERT_EQ("eleven", result);
356
1
  ASSERT_OK(snapshotDB->Get(roptions, cphandles[2], "two", &result));
357
6
  for (auto h : cphandles) {
358
6
      delete h;
359
6
  }
360
1
  cphandles.clear();
361
1
  delete snapshotDB;
362
1
  snapshotDB = nullptr;
363
1
  ASSERT_OK(DestroyDB(snapshot_name, options));
364
1
}
365
366
}  // namespace rocksdb
367
368
13.2k
int main(int argc, char** argv) {
369
13.2k
  rocksdb::port::InstallStackTraceHandler();
370
13.2k
  ::testing::InitGoogleTest(&argc, argv);
371
13.2k
  return RUN_ALL_TESTS();
372
13.2k
}
373
374
#else
375
#include <stdio.h>
376
377
int main(int argc, char** argv) {
378
  fprintf(stderr, "SKIPPED as Checkpoint is not supported in ROCKSDB_LITE\n");
379
  return 0;
380
}
381
382
#endif  // !ROCKSDB_LITE