ldb_cmd_test.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. #ifndef ROCKSDB_LITE
  7. #include "rocksdb/utilities/ldb_cmd.h"
  8. #include "db/version_edit.h"
  9. #include "db/version_set.h"
  10. #include "env/composite_env_wrapper.h"
  11. #include "file/filename.h"
  12. #include "port/stack_trace.h"
  13. #include "rocksdb/file_checksum.h"
  14. #include "test_util/sync_point.h"
  15. #include "test_util/testharness.h"
  16. #include "test_util/testutil.h"
  17. #include "util/file_checksum_helper.h"
  18. using std::string;
  19. using std::vector;
  20. using std::map;
  21. namespace ROCKSDB_NAMESPACE {
  22. class LdbCmdTest : public testing::Test {
  23. public:
  24. LdbCmdTest() : testing::Test() {}
  25. Env* TryLoadCustomOrDefaultEnv() {
  26. const char* test_env_uri = getenv("TEST_ENV_URI");
  27. if (!test_env_uri) {
  28. return Env::Default();
  29. }
  30. Env* env = Env::Default();
  31. Env::LoadEnv(test_env_uri, &env, &env_guard_);
  32. return env;
  33. }
  34. private:
  35. std::shared_ptr<Env> env_guard_;
  36. };
  37. TEST_F(LdbCmdTest, HexToString) {
  38. // map input to expected outputs.
  39. // odd number of "hex" half bytes doesn't make sense
  40. map<string, vector<int>> inputMap = {
  41. {"0x07", {7}}, {"0x5050", {80, 80}}, {"0xFF", {-1}},
  42. {"0x1234", {18, 52}}, {"0xaaAbAC", {-86, -85, -84}}, {"0x1203", {18, 3}},
  43. };
  44. for (const auto& inPair : inputMap) {
  45. auto actual = ROCKSDB_NAMESPACE::LDBCommand::HexToString(inPair.first);
  46. auto expected = inPair.second;
  47. for (unsigned int i = 0; i < actual.length(); i++) {
  48. EXPECT_EQ(expected[i], static_cast<int>((signed char) actual[i]));
  49. }
  50. auto reverse = ROCKSDB_NAMESPACE::LDBCommand::StringToHex(actual);
  51. EXPECT_STRCASEEQ(inPair.first.c_str(), reverse.c_str());
  52. }
  53. }
  54. TEST_F(LdbCmdTest, HexToStringBadInputs) {
  55. const vector<string> badInputs = {
  56. "0xZZ", "123", "0xx5", "0x111G", "0x123", "Ox12", "0xT", "0x1Q1",
  57. };
  58. for (const auto badInput : badInputs) {
  59. try {
  60. ROCKSDB_NAMESPACE::LDBCommand::HexToString(badInput);
  61. std::cerr << "Should fail on bad hex value: " << badInput << "\n";
  62. FAIL();
  63. } catch (...) {
  64. }
  65. }
  66. }
  67. TEST_F(LdbCmdTest, MemEnv) {
  68. Env* base_env = TryLoadCustomOrDefaultEnv();
  69. std::unique_ptr<Env> env(NewMemEnv(base_env));
  70. Options opts;
  71. opts.env = env.get();
  72. opts.create_if_missing = true;
  73. opts.file_system.reset(new LegacyFileSystemWrapper(opts.env));
  74. DB* db = nullptr;
  75. std::string dbname = test::TmpDir();
  76. ASSERT_OK(DB::Open(opts, dbname, &db));
  77. WriteOptions wopts;
  78. for (int i = 0; i < 100; i++) {
  79. char buf[16];
  80. snprintf(buf, sizeof(buf), "%08d", i);
  81. ASSERT_OK(db->Put(wopts, buf, buf));
  82. }
  83. FlushOptions fopts;
  84. fopts.wait = true;
  85. ASSERT_OK(db->Flush(fopts));
  86. delete db;
  87. char arg1[] = "./ldb";
  88. char arg2[1024];
  89. snprintf(arg2, sizeof(arg2), "--db=%s", dbname.c_str());
  90. char arg3[] = "dump_live_files";
  91. char* argv[] = {arg1, arg2, arg3};
  92. ASSERT_EQ(0,
  93. LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  94. }
  95. class FileChecksumTestHelper {
  96. private:
  97. Options options_;
  98. DB* db_;
  99. std::string dbname_;
  100. Status VerifyChecksum(LiveFileMetaData& file_meta) {
  101. std::string cur_checksum;
  102. std::string checksum_func_name;
  103. Status s;
  104. EnvOptions soptions;
  105. std::unique_ptr<SequentialFile> file_reader;
  106. std::string file_path = dbname_ + "/" + file_meta.name;
  107. s = options_.env->NewSequentialFile(file_path, &file_reader, soptions);
  108. if (!s.ok()) {
  109. return s;
  110. }
  111. std::unique_ptr<char[]> scratch(new char[2048]);
  112. bool first_read = true;
  113. Slice result;
  114. FileChecksumFunc* file_checksum_func =
  115. options_.sst_file_checksum_func.get();
  116. if (file_checksum_func == nullptr) {
  117. cur_checksum = kUnknownFileChecksum;
  118. checksum_func_name = kUnknownFileChecksumFuncName;
  119. } else {
  120. checksum_func_name = file_checksum_func->Name();
  121. s = file_reader->Read(2048, &result, scratch.get());
  122. if (!s.ok()) {
  123. return s;
  124. }
  125. while (result.size() != 0) {
  126. if (first_read) {
  127. first_read = false;
  128. cur_checksum =
  129. file_checksum_func->Value(scratch.get(), result.size());
  130. } else {
  131. cur_checksum = file_checksum_func->Extend(cur_checksum, scratch.get(),
  132. result.size());
  133. }
  134. s = file_reader->Read(2048, &result, scratch.get());
  135. if (!s.ok()) {
  136. return s;
  137. }
  138. }
  139. }
  140. std::string stored_checksum = file_meta.file_checksum;
  141. std::string stored_checksum_func_name = file_meta.file_checksum_func_name;
  142. if ((cur_checksum != stored_checksum) ||
  143. (checksum_func_name != stored_checksum_func_name)) {
  144. return Status::Corruption(
  145. "Checksum does not match! The file: " + file_meta.name +
  146. ", checksum name: " + stored_checksum_func_name + " and checksum " +
  147. stored_checksum + ". However, expected checksum name: " +
  148. checksum_func_name + " and checksum " + cur_checksum);
  149. }
  150. return Status::OK();
  151. }
  152. public:
  153. FileChecksumTestHelper(Options& options, DB* db, std::string db_name)
  154. : options_(options), db_(db), dbname_(db_name) {}
  155. ~FileChecksumTestHelper() {}
  156. // Verify the checksum information in Manifest.
  157. Status VerifyChecksumInManifest(
  158. const std::vector<LiveFileMetaData>& live_files) {
  159. // Step 1: verify if the dbname_ is correct
  160. if (dbname_[dbname_.length() - 1] != '/') {
  161. dbname_.append("/");
  162. }
  163. // Step 2, get the the checksum information by recovering the VersionSet
  164. // from Manifest.
  165. std::unique_ptr<FileChecksumList> checksum_list(NewFileChecksumList());
  166. EnvOptions sopt;
  167. std::shared_ptr<Cache> tc(NewLRUCache(options_.max_open_files - 10,
  168. options_.table_cache_numshardbits));
  169. options_.db_paths.emplace_back(dbname_, 0);
  170. options_.num_levels = 64;
  171. WriteController wc(options_.delayed_write_rate);
  172. WriteBufferManager wb(options_.db_write_buffer_size);
  173. ImmutableDBOptions immutable_db_options(options_);
  174. VersionSet versions(dbname_, &immutable_db_options, sopt, tc.get(), &wb,
  175. &wc, nullptr);
  176. std::vector<std::string> cf_name_list;
  177. Status s;
  178. s = versions.ListColumnFamilies(&cf_name_list, dbname_,
  179. options_.file_system.get());
  180. if (s.ok()) {
  181. std::vector<ColumnFamilyDescriptor> cf_list;
  182. for (const auto& name : cf_name_list) {
  183. fprintf(stdout, "cf_name: %s", name.c_str());
  184. cf_list.emplace_back(name, ColumnFamilyOptions(options_));
  185. }
  186. s = versions.Recover(cf_list, true);
  187. }
  188. if (s.ok()) {
  189. s = versions.GetLiveFilesChecksumInfo(checksum_list.get());
  190. }
  191. if (!s.ok()) {
  192. return s;
  193. }
  194. // Step 3 verify the checksum
  195. if (live_files.size() != checksum_list->size()) {
  196. return Status::Corruption("The number of files does not match!");
  197. }
  198. for (size_t i = 0; i < live_files.size(); i++) {
  199. std::string stored_checksum = "";
  200. std::string stored_func_name = "";
  201. s = checksum_list->SearchOneFileChecksum(
  202. live_files[i].file_number, &stored_checksum, &stored_func_name);
  203. if (s.IsNotFound()) {
  204. return s;
  205. }
  206. if (live_files[i].file_checksum != stored_checksum ||
  207. live_files[i].file_checksum_func_name != stored_func_name) {
  208. return Status::Corruption(
  209. "Checksum does not match! The file: " +
  210. ToString(live_files[i].file_number) +
  211. ". In Manifest, checksum name: " + stored_func_name +
  212. " and checksum " + stored_checksum +
  213. ". However, expected checksum name: " +
  214. live_files[i].file_checksum_func_name + " and checksum " +
  215. live_files[i].file_checksum);
  216. }
  217. }
  218. return Status::OK();
  219. }
  220. // Verify the checksum of each file by recalculting the checksum and
  221. // comparing it with the one being generated when a SST file is created.
  222. Status VerifyEachFileChecksum() {
  223. assert(db_ != nullptr);
  224. std::vector<LiveFileMetaData> live_files;
  225. db_->GetLiveFilesMetaData(&live_files);
  226. for (auto a_file : live_files) {
  227. Status cs = VerifyChecksum(a_file);
  228. if (!cs.ok()) {
  229. return cs;
  230. }
  231. }
  232. return Status::OK();
  233. }
  234. };
  235. TEST_F(LdbCmdTest, DumpFileChecksumNoChecksum) {
  236. Env* base_env = TryLoadCustomOrDefaultEnv();
  237. std::unique_ptr<Env> env(NewMemEnv(base_env));
  238. Options opts;
  239. opts.env = env.get();
  240. opts.create_if_missing = true;
  241. opts.file_system.reset(new LegacyFileSystemWrapper(opts.env));
  242. DB* db = nullptr;
  243. std::string dbname = test::TmpDir();
  244. ASSERT_OK(DB::Open(opts, dbname, &db));
  245. WriteOptions wopts;
  246. FlushOptions fopts;
  247. fopts.wait = true;
  248. Random rnd(test::RandomSeed());
  249. for (int i = 0; i < 200; i++) {
  250. char buf[16];
  251. snprintf(buf, sizeof(buf), "%08d", i);
  252. std::string v;
  253. test::RandomString(&rnd, 100, &v);
  254. ASSERT_OK(db->Put(wopts, buf, v));
  255. }
  256. ASSERT_OK(db->Flush(fopts));
  257. for (int i = 100; i < 300; i++) {
  258. char buf[16];
  259. snprintf(buf, sizeof(buf), "%08d", i);
  260. std::string v;
  261. test::RandomString(&rnd, 100, &v);
  262. ASSERT_OK(db->Put(wopts, buf, v));
  263. }
  264. ASSERT_OK(db->Flush(fopts));
  265. for (int i = 200; i < 400; i++) {
  266. char buf[16];
  267. snprintf(buf, sizeof(buf), "%08d", i);
  268. std::string v;
  269. test::RandomString(&rnd, 100, &v);
  270. ASSERT_OK(db->Put(wopts, buf, v));
  271. }
  272. ASSERT_OK(db->Flush(fopts));
  273. for (int i = 300; i < 400; i++) {
  274. char buf[16];
  275. snprintf(buf, sizeof(buf), "%08d", i);
  276. std::string v;
  277. test::RandomString(&rnd, 100, &v);
  278. ASSERT_OK(db->Put(wopts, buf, v));
  279. }
  280. ASSERT_OK(db->Flush(fopts));
  281. char arg1[] = "./ldb";
  282. char arg2[1024];
  283. snprintf(arg2, sizeof(arg2), "--db=%s", dbname.c_str());
  284. char arg3[] = "file_checksum_dump";
  285. char* argv[] = {arg1, arg2, arg3};
  286. ASSERT_EQ(0,
  287. LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  288. // Verify each sst file checksum value and checksum name
  289. FileChecksumTestHelper fct_helper(opts, db, dbname);
  290. ASSERT_OK(fct_helper.VerifyEachFileChecksum());
  291. // Manually trigger compaction
  292. char b_buf[16];
  293. snprintf(b_buf, sizeof(b_buf), "%08d", 0);
  294. char e_buf[16];
  295. snprintf(e_buf, sizeof(e_buf), "%08d", 399);
  296. Slice begin(b_buf);
  297. Slice end(e_buf);
  298. CompactRangeOptions options;
  299. ASSERT_OK(db->CompactRange(options, &begin, &end));
  300. // Verify each sst file checksum after compaction
  301. FileChecksumTestHelper fct_helper_ac(opts, db, dbname);
  302. ASSERT_OK(fct_helper_ac.VerifyEachFileChecksum());
  303. ASSERT_EQ(0,
  304. LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  305. // Verify the checksum information in memory is the same as that in Manifest;
  306. std::vector<LiveFileMetaData> live_files;
  307. db->GetLiveFilesMetaData(&live_files);
  308. delete db;
  309. ASSERT_OK(fct_helper_ac.VerifyChecksumInManifest(live_files));
  310. }
  311. TEST_F(LdbCmdTest, DumpFileChecksumCRC32) {
  312. Env* base_env = TryLoadCustomOrDefaultEnv();
  313. std::unique_ptr<Env> env(NewMemEnv(base_env));
  314. Options opts;
  315. opts.env = env.get();
  316. opts.create_if_missing = true;
  317. opts.sst_file_checksum_func =
  318. std::shared_ptr<FileChecksumFunc>(CreateFileChecksumFuncCrc32c());
  319. opts.file_system.reset(new LegacyFileSystemWrapper(opts.env));
  320. DB* db = nullptr;
  321. std::string dbname = test::TmpDir();
  322. ASSERT_OK(DB::Open(opts, dbname, &db));
  323. WriteOptions wopts;
  324. FlushOptions fopts;
  325. fopts.wait = true;
  326. Random rnd(test::RandomSeed());
  327. for (int i = 0; i < 100; i++) {
  328. char buf[16];
  329. snprintf(buf, sizeof(buf), "%08d", i);
  330. std::string v;
  331. test::RandomString(&rnd, 100, &v);
  332. ASSERT_OK(db->Put(wopts, buf, v));
  333. }
  334. ASSERT_OK(db->Flush(fopts));
  335. for (int i = 50; i < 150; i++) {
  336. char buf[16];
  337. snprintf(buf, sizeof(buf), "%08d", i);
  338. std::string v;
  339. test::RandomString(&rnd, 100, &v);
  340. ASSERT_OK(db->Put(wopts, buf, v));
  341. }
  342. ASSERT_OK(db->Flush(fopts));
  343. for (int i = 100; i < 200; i++) {
  344. char buf[16];
  345. snprintf(buf, sizeof(buf), "%08d", i);
  346. std::string v;
  347. test::RandomString(&rnd, 100, &v);
  348. ASSERT_OK(db->Put(wopts, buf, v));
  349. }
  350. ASSERT_OK(db->Flush(fopts));
  351. for (int i = 150; i < 250; i++) {
  352. char buf[16];
  353. snprintf(buf, sizeof(buf), "%08d", i);
  354. std::string v;
  355. test::RandomString(&rnd, 100, &v);
  356. ASSERT_OK(db->Put(wopts, buf, v));
  357. }
  358. ASSERT_OK(db->Flush(fopts));
  359. char arg1[] = "./ldb";
  360. char arg2[1024];
  361. snprintf(arg2, sizeof(arg2), "--db=%s", dbname.c_str());
  362. char arg3[] = "file_checksum_dump";
  363. char* argv[] = {arg1, arg2, arg3};
  364. ASSERT_EQ(0,
  365. LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  366. // Verify each sst file checksum value and checksum name
  367. FileChecksumTestHelper fct_helper(opts, db, dbname);
  368. ASSERT_OK(fct_helper.VerifyEachFileChecksum());
  369. // Manually trigger compaction
  370. char b_buf[16];
  371. snprintf(b_buf, sizeof(b_buf), "%08d", 0);
  372. char e_buf[16];
  373. snprintf(e_buf, sizeof(e_buf), "%08d", 249);
  374. Slice begin(b_buf);
  375. Slice end(e_buf);
  376. CompactRangeOptions options;
  377. ASSERT_OK(db->CompactRange(options, &begin, &end));
  378. // Verify each sst file checksum after compaction
  379. FileChecksumTestHelper fct_helper_ac(opts, db, dbname);
  380. ASSERT_OK(fct_helper_ac.VerifyEachFileChecksum());
  381. ASSERT_EQ(0,
  382. LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  383. // Verify the checksum information in memory is the same as that in Manifest;
  384. std::vector<LiveFileMetaData> live_files;
  385. db->GetLiveFilesMetaData(&live_files);
  386. delete db;
  387. ASSERT_OK(fct_helper_ac.VerifyChecksumInManifest(live_files));
  388. }
  389. TEST_F(LdbCmdTest, OptionParsing) {
  390. // test parsing flags
  391. Options opts;
  392. opts.env = TryLoadCustomOrDefaultEnv();
  393. {
  394. std::vector<std::string> args;
  395. args.push_back("scan");
  396. args.push_back("--ttl");
  397. args.push_back("--timestamp");
  398. LDBCommand* command = ROCKSDB_NAMESPACE::LDBCommand::InitFromCmdLineArgs(
  399. args, opts, LDBOptions(), nullptr);
  400. const std::vector<std::string> flags = command->TEST_GetFlags();
  401. EXPECT_EQ(flags.size(), 2);
  402. EXPECT_EQ(flags[0], "ttl");
  403. EXPECT_EQ(flags[1], "timestamp");
  404. delete command;
  405. }
  406. // test parsing options which contains equal sign in the option value
  407. {
  408. std::vector<std::string> args;
  409. args.push_back("scan");
  410. args.push_back("--db=/dev/shm/ldbtest/");
  411. args.push_back(
  412. "--from='abcd/efg/hijk/lmn/"
  413. "opq:__rst.uvw.xyz?a=3+4+bcd+efghi&jk=lm_no&pq=rst-0&uv=wx-8&yz=a&bcd_"
  414. "ef=gh.ijk'");
  415. LDBCommand* command = ROCKSDB_NAMESPACE::LDBCommand::InitFromCmdLineArgs(
  416. args, opts, LDBOptions(), nullptr);
  417. const std::map<std::string, std::string> option_map =
  418. command->TEST_GetOptionMap();
  419. EXPECT_EQ(option_map.at("db"), "/dev/shm/ldbtest/");
  420. EXPECT_EQ(option_map.at("from"),
  421. "'abcd/efg/hijk/lmn/"
  422. "opq:__rst.uvw.xyz?a=3+4+bcd+efghi&jk=lm_no&pq=rst-0&uv=wx-8&yz="
  423. "a&bcd_ef=gh.ijk'");
  424. delete command;
  425. }
  426. }
  427. TEST_F(LdbCmdTest, ListFileTombstone) {
  428. Env* base_env = TryLoadCustomOrDefaultEnv();
  429. std::unique_ptr<Env> env(NewMemEnv(base_env));
  430. Options opts;
  431. opts.env = env.get();
  432. opts.create_if_missing = true;
  433. DB* db = nullptr;
  434. std::string dbname = test::TmpDir();
  435. ASSERT_OK(DB::Open(opts, dbname, &db));
  436. WriteOptions wopts;
  437. ASSERT_OK(db->Put(wopts, "foo", "1"));
  438. ASSERT_OK(db->Put(wopts, "bar", "2"));
  439. FlushOptions fopts;
  440. fopts.wait = true;
  441. ASSERT_OK(db->Flush(fopts));
  442. ASSERT_OK(db->DeleteRange(wopts, db->DefaultColumnFamily(), "foo", "foo2"));
  443. ASSERT_OK(db->DeleteRange(wopts, db->DefaultColumnFamily(), "bar", "foo2"));
  444. ASSERT_OK(db->Flush(fopts));
  445. delete db;
  446. {
  447. char arg1[] = "./ldb";
  448. char arg2[1024];
  449. snprintf(arg2, sizeof(arg2), "--db=%s", dbname.c_str());
  450. char arg3[] = "list_file_range_deletes";
  451. char* argv[] = {arg1, arg2, arg3};
  452. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  453. "ListFileRangeDeletesCommand::DoCommand:BeforePrint", [&](void* arg) {
  454. std::string* out_str = reinterpret_cast<std::string*>(arg);
  455. // Count number of tombstones printed
  456. int num_tb = 0;
  457. const std::string kFingerprintStr = "start: ";
  458. auto offset = out_str->find(kFingerprintStr);
  459. while (offset != std::string::npos) {
  460. num_tb++;
  461. offset =
  462. out_str->find(kFingerprintStr, offset + kFingerprintStr.size());
  463. }
  464. EXPECT_EQ(2, num_tb);
  465. });
  466. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  467. ASSERT_EQ(
  468. 0, LDBCommandRunner::RunCommand(3, argv, opts, LDBOptions(), nullptr));
  469. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
  470. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  471. }
  472. // Test the case of limiting tombstones
  473. {
  474. char arg1[] = "./ldb";
  475. char arg2[1024];
  476. snprintf(arg2, sizeof(arg2), "--db=%s", dbname.c_str());
  477. char arg3[] = "list_file_range_deletes";
  478. char arg4[] = "--max_keys=1";
  479. char* argv[] = {arg1, arg2, arg3, arg4};
  480. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  481. "ListFileRangeDeletesCommand::DoCommand:BeforePrint", [&](void* arg) {
  482. std::string* out_str = reinterpret_cast<std::string*>(arg);
  483. // Count number of tombstones printed
  484. int num_tb = 0;
  485. const std::string kFingerprintStr = "start: ";
  486. auto offset = out_str->find(kFingerprintStr);
  487. while (offset != std::string::npos) {
  488. num_tb++;
  489. offset =
  490. out_str->find(kFingerprintStr, offset + kFingerprintStr.size());
  491. }
  492. EXPECT_EQ(1, num_tb);
  493. });
  494. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  495. ASSERT_EQ(
  496. 0, LDBCommandRunner::RunCommand(4, argv, opts, LDBOptions(), nullptr));
  497. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
  498. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  499. }
  500. }
  501. } // namespace ROCKSDB_NAMESPACE
  502. #ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
  503. extern "C" {
  504. void RegisterCustomObjects(int argc, char** argv);
  505. }
  506. #else
  507. void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
  508. #endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
  509. int main(int argc, char** argv) {
  510. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  511. ::testing::InitGoogleTest(&argc, argv);
  512. RegisterCustomObjects(argc, argv);
  513. return RUN_ALL_TESTS();
  514. }
  515. #else
  516. #include <stdio.h>
  517. int main(int /*argc*/, char** /*argv*/) {
  518. fprintf(stderr, "SKIPPED as LDBCommand is not supported in ROCKSDB_LITE\n");
  519. return 0;
  520. }
  521. #endif // ROCKSDB_LITE