]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common, tool: update kvstore-tool to repair our key/value database
authorliuchang0812 <liuchang0812@gmail.com>
Mon, 24 Jul 2017 14:12:43 +0000 (22:12 +0800)
committerKefu Chai <kchai@redhat.com>
Tue, 11 Feb 2020 11:06:32 +0000 (19:06 +0800)
Fixes: http://tracker.ceph.com/issues/17730
Signed-off-by: liuchang0812 <liuchang0812@gmail.com>
(cherry picked from commit 4849ce3cc96eac9fee305927198a6c1b90892687)

Conflicts:
src/kv/LevelDBStore.cc
src/kv/RocksDBStore.cc
src/kv/RocksDBStore.h
src/os/bluestore/BlueStore.cc
src/tools/ceph_kvstore_tool.cc: resolve conflicts.

src/kv/KeyValueDB.h
src/kv/LevelDBStore.cc
src/kv/LevelDBStore.h
src/kv/RocksDBStore.cc
src/kv/RocksDBStore.h
src/os/bluestore/BlueStore.cc
src/os/bluestore/BlueStore.h
src/test/CMakeLists.txt
src/test/cli/ceph-kvstore-tool/help.t [new file with mode: 0644]
src/tools/CMakeLists.txt
src/tools/ceph_kvstore_tool.cc

index 2c31944edc73fd67b77c69c8fa71aa55e58be912..b5247280075f5086769a10d401fce2e2663148ef 100644 (file)
@@ -148,6 +148,9 @@ public:
   virtual int create_and_open(std::ostream &out) = 0;
   virtual void close() { }
 
+  /// Try to repair K/V database. leveldb and rocksdb require that database must be not opened.
+  virtual int repair(std::ostream &out) { return 0; }
+
   virtual Transaction get_transaction() = 0;
   virtual int submit_transaction(Transaction) = 0;
   virtual int submit_transaction_sync(Transaction t) {
index 25ff7a698d2e32bc56d6682d347373d687c5f731..37b08612a5cfd04ef7de6738d4f74c056ed91539 100644 (file)
@@ -61,10 +61,8 @@ int LevelDBStore::init(string option_str)
   return 0;
 }
 
-int LevelDBStore::do_open(ostream &out, bool create_if_missing)
+int LevelDBStore::load_leveldb_options(bool create_if_missing, leveldb::Options &ldoptions)
 {
-  leveldb::Options ldoptions;
-
   if (options.write_buffer_size)
     ldoptions.write_buffer_size = options.write_buffer_size;
   if (options.max_open_files)
@@ -106,6 +104,17 @@ int LevelDBStore::do_open(ostream &out, bool create_if_missing)
     leveldb::Env *env = leveldb::Env::Default();
     env->NewLogger(options.log_file, &ldoptions.info_log);
   }
+  return 0;
+}
+
+int LevelDBStore::do_open(ostream &out, bool create_if_missing)
+{
+  leveldb::Options ldoptions;
+  int r = load_leveldb_options(create_if_missing, ldoptions);
+  if (r) {
+    dout(1) << "load leveldb options failed" << dendl;
+    return r;
+  }
 
   leveldb::DB *_db;
   leveldb::Status status = leveldb::DB::Open(ldoptions, path, &_db);
@@ -173,6 +182,24 @@ void LevelDBStore::close()
     cct->get_perfcounters_collection()->remove(logger);
 }
 
+int LevelDBStore::repair(std::ostream &out)
+{
+  leveldb::Options ldoptions;
+  int r = load_leveldb_options(false, ldoptions);
+  if (r) {
+    dout(1) << "load leveldb options failed" << dendl;
+    out << "load leveldb options failed" << std::endl;
+    return r;
+  }
+  leveldb::Status status = leveldb::RepairDB(path, ldoptions);
+  if (status.ok()) {
+    return 0;
+  } else {
+    out << "repair leveldb failed : " << status.ToString() << std::endl;
+    return 1;
+  }
+}
+
 int LevelDBStore::submit_transaction(KeyValueDB::Transaction t)
 {
   utime_t start = ceph_clock_now();
index 5a3ced9e4c9b9d565f435274c668b70d2d11e118..39d3ecee65b391f36ddee7681cf04098bff396fe 100644 (file)
@@ -66,6 +66,7 @@ class LevelDBStore : public KeyValueDB {
 #endif
   boost::scoped_ptr<leveldb::DB> db;
 
+  int load_leveldb_options(bool create_if_missing, leveldb::Options &opts);
   int do_open(ostream &out, bool create_if_missing);
 
   // manage async compactions
@@ -188,6 +189,7 @@ public:
   {
     return logger;
   }
+  int repair(std::ostream &out) override;
 
   class LevelDBTransactionImpl : public KeyValueDB::TransactionImpl {
   public:
index 1cfa7548b40b1f381ae4b8adfaac465e13e23db6..025c521bfb1e851b87d728e0c5e2ead27b936e61 100644 (file)
@@ -247,9 +247,8 @@ int RocksDBStore::create_and_open(ostream &out)
   return do_open(out, true);
 }
 
-int RocksDBStore::do_open(ostream &out, bool create_if_missing)
+int RocksDBStore::load_rocksdb_options(bool create_if_missing, rocksdb::Options& opt)
 {
-  rocksdb::Options opt;
   rocksdb::Status status;
 
   if (options_str.length()) {
@@ -367,6 +366,19 @@ int RocksDBStore::do_open(ostream &out, bool create_if_missing)
           << dendl;
 
   opt.merge_operator.reset(new MergeOperatorRouter(*this));
+
+  return 0;
+}
+
+int RocksDBStore::do_open(ostream &out, bool create_if_missing)
+{
+  rocksdb::Options opt;
+  int r = load_rocksdb_options(create_if_missing, opt);
+  if (r) {
+    dout(1) << __func__ << " load rocksdb options failed" << dendl;
+    return r;
+  }
+  rocksdb::Status status;
   status = rocksdb::DB::Open(opt, path, &db);
   if (!status.ok()) {
     derr << status.ToString() << dendl;
@@ -442,6 +454,24 @@ void RocksDBStore::close()
     cct->get_perfcounters_collection()->remove(logger);
 }
 
+int RocksDBStore::repair(std::ostream &out)
+{
+  rocksdb::Options opt;
+  int r = load_rocksdb_options(false, opt);
+  if (r) {
+    dout(1) << __func__ << " load rocksdb options failed" << dendl;
+    out << "load rocksdb options failed" << std::endl;
+    return r;
+  }
+  rocksdb::Status status = rocksdb::RepairDB(path, opt);
+  if (status.ok()) {
+    return 0;
+  } else {
+    out << "repair rocksdb failed : " << status.ToString() << std::endl;
+    return 1;
+  }
+}
+
 void RocksDBStore::split_stats(const std::string &s, char delim, std::vector<std::string> &elems) {
     std::stringstream ss;
     ss.str(s);
index 0b0d31d12ded00b709246e2dcc5ab8df197a1d02..1039d5e411df67205621061135f238c5a7276161 100644 (file)
@@ -80,6 +80,7 @@ class RocksDBStore : public KeyValueDB {
   bool set_cache_flag = false;
 
   int do_open(ostream &out, bool create_if_missing);
+  int load_rocksdb_options(bool create_if_missing, rocksdb::Options& opt);
 
   // manage async compactions
   Mutex compact_queue_lock;
@@ -158,6 +159,7 @@ public:
 
   void close() override;
 
+  int repair(std::ostream &out) override;
   void split_stats(const std::string &s, char delim, std::vector<std::string> &elems);
   void get_statistics(Formatter *f) override;
 
index 414ad62eecd57dba13a9ffa94edf9f426a56c669..64a6022441de39ec97c792e106127b15da3ee761 100644 (file)
@@ -4896,7 +4896,7 @@ void BlueStore::_close_db_and_around()
 }
 
 
-int BlueStore::_open_db(bool create)
+int BlueStore::_open_db(bool create, bool to_repair_db)
 {
   int r;
   assert(!db);
@@ -5163,6 +5163,8 @@ int BlueStore::_open_db(bool create)
   if (kv_backend == "rocksdb")
     options = cct->_conf->bluestore_rocksdb_options;
   db->init(options);
+  if (to_repair_db)
+    return 0;
   if (create)
     r = db->create_and_open(err);
   else
@@ -5791,7 +5793,7 @@ void BlueStore::set_cache_shards(unsigned num)
   }
 }
 
-int BlueStore::_mount(bool kv_only)
+int BlueStore::_mount(bool kv_only, bool open_db)
 {
   dout(1) << __func__ << " path " << path << dendl;
 
@@ -5848,7 +5850,7 @@ int BlueStore::_mount(bool kv_only)
   if (r < 0)
     goto out_fsid;
 
-  r = _open_db(false);
+  r = _open_db(false, !open_db);
   if (r < 0)
     goto out_bdev;
 
index 69362ac69ccbd770fa0cc37c1778d3b5a768f00e..6bcbed7b91e3ac120a5dd7dcd1929dd0467ca8ba 100644 (file)
@@ -2123,7 +2123,11 @@ private:
 
   int _open_bdev(bool create);
   void _close_bdev();
-  int _open_db(bool create);
+  /*
+   * @warning to_repair_db means that we open this db to repair it, will not
+   * hold the rocksdb's file lock.
+   */
+  int _open_db(bool create, bool to_repair_db=false);
   void _close_db();
   int _open_fm(bool create);
   void _close_fm();
@@ -2294,15 +2298,15 @@ public:
   bool test_mount_in_use() override;
 
 private:
-  int _mount(bool kv_only);
+  int _mount(bool kv_only, bool open_db=true);
 public:
   int mount() override {
     return _mount(false);
   }
   int umount() override;
 
-  int start_kv_only(KeyValueDB **pdb) {
-    int r = _mount(true);
+  int start_kv_only(KeyValueDB **pdb, bool open_db=true) {
+    int r = _mount(true, open_db);
     if (r < 0)
       return r;
     *pdb = db;
index f53a016db46f108d1c901e640774432622acf9fd..767590c02a6f8af5de6c90f9f2473df58bbe71e8 100644 (file)
@@ -549,6 +549,7 @@ add_dependencies(tests
   ceph-osd
   ceph-dencoder
   ceph-objectstore-tool
+  ceph-kvstore-tool
   ceph-monstore-tool
   osdmaptool
   ceph_example
diff --git a/src/test/cli/ceph-kvstore-tool/help.t b/src/test/cli/ceph-kvstore-tool/help.t
new file mode 100644 (file)
index 0000000..3556d34
--- /dev/null
@@ -0,0 +1,21 @@
+  $ ceph-kvstore-tool --help
+  Usage: ceph-kvstore-tool <leveldb|rocksdb|bluestore-kv> <store path> command [args...]
+  
+  Commands:
+    list [prefix]
+    list-crc [prefix]
+    exists <prefix> [key]
+    get <prefix> <key> [out <file>]
+    crc <prefix> <key>
+    get-size [<prefix> <key>]
+    set <prefix> <key> [ver <N>|in <file>]
+    rm <prefix> <key>
+    rm-prefix <prefix>
+    store-copy <path> [num-keys-per-tx]
+    store-crc <path>
+    compact
+    compact-prefix <prefix>
+    compact-range <prefix> <start> <end>
+    repair
+  
+  [1]
index 9f72fa3b48d7dd6f8cd9da47a4b5616018a6a58f..761c3a814e6963030d0cf13503416820c5249233 100644 (file)
@@ -55,11 +55,9 @@ if(WITH_TESTS)
 endif(WITH_TESTS)
 endif(WITH_LIBCEPHFS)
 
-if(WITH_TESTS)
 add_executable(ceph-kvstore-tool ceph_kvstore_tool.cc)
 target_link_libraries(ceph-kvstore-tool os global)
 install(TARGETS ceph-kvstore-tool DESTINATION bin)
-endif(WITH_TESTS)
 
 set(ceph_conf_srcs ceph_conf.cc)
 add_executable(ceph-conf ${ceph_conf_srcs})
index 3ba4a4a87669addfad6744ccd8482cf7d46f04c4..af1126f22c1aea37c9c215322599899226ad8355 100644 (file)
@@ -46,13 +46,13 @@ class StoreTool
   string store_path;
 
   public:
-  StoreTool(string type, const string &path) : store_path(path) {
+  StoreTool(string type, const string &path, bool need_open_db=true) : store_path(path) {
     KeyValueDB *db_ptr;
     if (type == "bluestore-kv") {
 #ifdef HAVE_LIBAIO
       // note: we'll leak this!  the only user is ceph-kvstore-tool and
       // we don't care.
-      bluestore.reset(new BlueStore(g_ceph_context, path));
+      bluestore.reset(new BlueStore(g_ceph_context, path, need_open_db));
       int r = bluestore->start_kv_only(&db_ptr);
       if (r < 0) {
        exit(1);
@@ -63,14 +63,16 @@ class StoreTool
 #endif
     } else {
       db_ptr = KeyValueDB::create(g_ceph_context, type, path);
-      int r = db_ptr->open(std::cerr);
-      if (r < 0) {
-       cerr << "failed to open type " << type << " path " << path << ": "
-            << cpp_strerror(r) << std::endl;
-       exit(1);
+      if (need_open_db) {
+        int r = db_ptr->open(std::cerr);
+        if (r < 0) {
+         cerr << "failed to open type " << type << " path " << path << ": "
+              << cpp_strerror(r) << std::endl;
+         exit(1);
+       }
+       db = db_ptr;
       }
     }
-    db = db_ptr;
   }
 
   ~StoreTool() {
@@ -279,6 +281,10 @@ class StoreTool
   void compact_range(string prefix, string start, string end) {
     db->compact_range(prefix, start, end);
   }
+
+  int repair() {
+    return db->repair(std::cout);
+  }
 };
 
 void usage(const char *pname)
@@ -300,6 +306,7 @@ void usage(const char *pname)
     << "  compact\n"
     << "  compact-prefix <prefix>\n"
     << "  compact-range <prefix> <start> <end>\n"
+    << "  repair\n"
     << std::endl;
 }
 
@@ -324,9 +331,18 @@ int main(int argc, const char *argv[])
   string path(args[1]);
   string cmd(args[2]);
 
-  StoreTool st(type, path);
+  bool need_open_db = (cmd != "repair");
+  StoreTool st(type, path, need_open_db);
 
-  if (cmd == "list" || cmd == "list-crc") {
+  if (cmd == "repair") {
+    int ret = st.repair();
+    if (!ret) {
+      std::cout << "repair kvstore successfully" << std::endl;
+    } else {
+      std::cout << "repair kvstore failed" << std::endl;
+    }
+    return ret;
+  } else if (cmd == "list" || cmd == "list-crc") {
     string prefix;
     if (argc > 4)
       prefix = url_unescape(argv[4]);