]> 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)
committerChang Liu <liuchang0812@gmail.com>
Mon, 16 Oct 2017 14:52:10 +0000 (22:52 +0800)
Fixes: http://tracker.ceph.com/issues/17730
Signed-off-by: liuchang0812 <liuchang0812@gmail.com>
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 54b55a50307961023fe4b01d5be792f215884fbd..60e32254e09db491a03aa5c8d076cbf5cc2a4fa6 100644 (file)
@@ -162,6 +162,9 @@ public:
                              const vector<ColumnFamily>& cfs = {}) = 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 e124c1a537b94d07ba31d4bc0f45e9228b70b259..7c8b44dc20d4c8838c8b74c3548c4bc1978d7d3f 100644 (file)
@@ -75,10 +75,8 @@ int LevelDBStore::create_and_open(ostream &out, const vector<ColumnFamily>& cfs)
   return do_open(out, true);
 }
 
-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)
@@ -120,6 +118,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);
@@ -187,6 +196,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 ca08430e67a8681e31208c0c8efd9fddad81620e..decd07977a69ad1817d224282f97fb61a07e9f3a 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
@@ -184,6 +185,7 @@ public:
   {
     return logger;
   }
+  int repair(std::ostream &out) override;
 
   class LevelDBTransactionImpl : public KeyValueDB::TransactionImpl {
   public:
index 0fd20cde61133438c9c651cb9944b0d76e0bf7b3..b8b259208a1846578f5a499e69d315993b0064b9 100644 (file)
@@ -322,10 +322,8 @@ int RocksDBStore::create_and_open(ostream &out,
   }
 }
 
-int RocksDBStore::do_open(ostream &out, bool create_if_missing,
-                         const vector<ColumnFamily>* cfs)
+int RocksDBStore::load_rocksdb_options(bool create_if_missing, rocksdb::Options& opt)
 {
-  rocksdb::Options opt;
   rocksdb::Status status;
 
   if (options_str.length()) {
@@ -440,6 +438,20 @@ 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,
+                         const vector<ColumnFamily>* cfs)
+{
+  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;
   if (create_if_missing) {
     status = rocksdb::DB::Open(opt, path, &db);
     if (!status.ok()) {
@@ -618,6 +630,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 0cd93f7c641e42e512bd9dcaf08c77f1f6642edc..e6649548cd88961e7a6fe6e7214cc07d070b58a0 100644 (file)
@@ -89,6 +89,7 @@ class RocksDBStore : public KeyValueDB {
   int create_db_dir();
   int do_open(ostream &out, bool create_if_missing,
              const vector<ColumnFamily>* cfs = nullptr);
+  int load_rocksdb_options(bool create_if_missing, rocksdb::Options& opt);
 
   // manage async compactions
   Mutex compact_queue_lock;
@@ -173,7 +174,7 @@ public:
     else
       return static_cast<rocksdb::ColumnFamilyHandle*>(iter->second);
   }
-
+  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 97179348b5b6e02e8a4565f18b61622b54ed4f05..839c4976b81f3e21a858149b5eb7fd43cdd32d95 100644 (file)
@@ -4477,7 +4477,7 @@ bool BlueStore::test_mount_in_use()
   return ret;
 }
 
-int BlueStore::_open_db(bool create)
+int BlueStore::_open_db(bool create, bool to_repair_db)
 {
   int r;
   assert(!db);
@@ -4749,6 +4749,8 @@ int BlueStore::_open_db(bool create)
   }
 
   db->init(options);
+  if (to_repair_db)
+    return 0;
   if (create) {
     if (cct->_conf->get_val<bool>("bluestore_rocksdb_cf")) {
       r = db->create_and_open(err, cfs);
@@ -5340,7 +5342,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;
 
@@ -5390,7 +5392,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 03bf8115c490024f8e4cceb69ff6db1a081e0a91..134866532a169cdb3131780fc208dc7cf1de8e7b 100644 (file)
@@ -1972,7 +1972,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();
@@ -2137,15 +2141,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 6c5414627a3f5b2ff962b66171bf996016fa6552..d0003c69a7651cfa541aae3c53ed6af99507d553 100644 (file)
@@ -537,6 +537,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..9fb3e1d
--- /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] [leveldb|rocksdb|...] 
+    store-crc <path>
+    compact
+    compact-prefix <prefix>
+    compact-range <prefix> <start> <end>
+    repair
+  
+  [1]
index ed19c63bc3c7da87dfb9ee6fa043d95683f1dc0b..490caca3f6814a4094649b82e792329de86c070a 100644 (file)
@@ -52,11 +52,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 c3c9c52e4b6d02d0d437a2e62bd3d70b05d7e462..8cd3afd56e367f5fda5d5ebb614b90c7bf0e5b89 100644 (file)
@@ -59,10 +59,10 @@ 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) {
     if (type == "bluestore-kv") {
 #ifdef HAVE_LIBAIO
-      auto bluestore = new BlueStore(g_ceph_context, path);
+      auto bluestore = new BlueStore(g_ceph_context, path, need_open_db);
       KeyValueDB *db_ptr;
       int r = bluestore->start_kv_only(&db_ptr);
       if (r < 0) {
@@ -75,13 +75,15 @@ class StoreTool
 #endif
     } else {
       auto 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.reset(db_ptr);
       }
-      db.reset(db_ptr);
     }
   }
 
@@ -282,6 +284,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)
@@ -303,6 +309,7 @@ void usage(const char *pname)
     << "  compact\n"
     << "  compact-prefix <prefix>\n"
     << "  compact-range <prefix> <start> <end>\n"
+    << "  repair\n"
     << std::endl;
 }
 
@@ -327,9 +334,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]);