From: liuchang0812 Date: Mon, 24 Jul 2017 14:12:43 +0000 (+0800) Subject: common, tool: update kvstore-tool to repair our key/value database X-Git-Tag: v12.2.14~18^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=60be81f3c780d9c0dc9af98bf6a6d1644c5a7f88;p=ceph.git common, tool: update kvstore-tool to repair our key/value database Fixes: http://tracker.ceph.com/issues/17730 Signed-off-by: liuchang0812 (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. --- diff --git a/src/kv/KeyValueDB.h b/src/kv/KeyValueDB.h index 2c31944edc7..b5247280075 100644 --- a/src/kv/KeyValueDB.h +++ b/src/kv/KeyValueDB.h @@ -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) { diff --git a/src/kv/LevelDBStore.cc b/src/kv/LevelDBStore.cc index 25ff7a698d2..37b08612a5c 100644 --- a/src/kv/LevelDBStore.cc +++ b/src/kv/LevelDBStore.cc @@ -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(); diff --git a/src/kv/LevelDBStore.h b/src/kv/LevelDBStore.h index 5a3ced9e4c9..39d3ecee65b 100644 --- a/src/kv/LevelDBStore.h +++ b/src/kv/LevelDBStore.h @@ -66,6 +66,7 @@ class LevelDBStore : public KeyValueDB { #endif boost::scoped_ptr 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: diff --git a/src/kv/RocksDBStore.cc b/src/kv/RocksDBStore.cc index 1cfa7548b40..025c521bfb1 100644 --- a/src/kv/RocksDBStore.cc +++ b/src/kv/RocksDBStore.cc @@ -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 &elems) { std::stringstream ss; ss.str(s); diff --git a/src/kv/RocksDBStore.h b/src/kv/RocksDBStore.h index 0b0d31d12de..1039d5e411d 100644 --- a/src/kv/RocksDBStore.h +++ b/src/kv/RocksDBStore.h @@ -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 &elems); void get_statistics(Formatter *f) override; diff --git a/src/os/bluestore/BlueStore.cc b/src/os/bluestore/BlueStore.cc index 414ad62eecd..64a6022441d 100644 --- a/src/os/bluestore/BlueStore.cc +++ b/src/os/bluestore/BlueStore.cc @@ -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; diff --git a/src/os/bluestore/BlueStore.h b/src/os/bluestore/BlueStore.h index 69362ac69cc..6bcbed7b91e 100644 --- a/src/os/bluestore/BlueStore.h +++ b/src/os/bluestore/BlueStore.h @@ -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; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index f53a016db46..767590c02a6 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -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 index 00000000000..3556d3483c0 --- /dev/null +++ b/src/test/cli/ceph-kvstore-tool/help.t @@ -0,0 +1,21 @@ + $ ceph-kvstore-tool --help + Usage: ceph-kvstore-tool command [args...] + + Commands: + list [prefix] + list-crc [prefix] + exists [key] + get [out ] + crc + get-size [ ] + set [ver |in ] + rm + rm-prefix + store-copy [num-keys-per-tx] + store-crc + compact + compact-prefix + compact-range + repair + + [1] diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 9f72fa3b48d..761c3a814e6 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -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}) diff --git a/src/tools/ceph_kvstore_tool.cc b/src/tools/ceph_kvstore_tool.cc index 3ba4a4a8766..af1126f22c1 100644 --- a/src/tools/ceph_kvstore_tool.cc +++ b/src/tools/ceph_kvstore_tool.cc @@ -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 \n" << " compact-range \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]);