#include "SharedRocksDB.hpp" #include #include #include #include #include #include #include #include "Assert.hpp" #include "RocksDBUtils.hpp" static void closeDB(rocksdb::DB* db) { ROCKS_DB_CHECKED(db->Close()); delete db; } SharedRocksDB::SharedRocksDB(Logger& logger, std::shared_ptr& xmon, const std::string& path, const std::string& statisticsFilePath) : _env(logger, xmon, "shared_rocksdb"), _transactionDB(false), _path(path), _statisticsFilePath(statisticsFilePath), _db(nullptr, closeDB) {} SharedRocksDB::~SharedRocksDB() { close(); } void SharedRocksDB::open(rocksdb::Options options) { std::unique_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() == nullptr); ALWAYS_ASSERT(options.statistics.get() == nullptr); _dbStatistics = rocksdb::CreateDBStatistics(); options.statistics = _dbStatistics; std::vector cfHandles; cfHandles.reserve(_cfDescriptors.size()); rocksdb::DB* db; LOG_INFO(_env, "Opening RocksDB in %s", _path); ROCKS_DB_CHECKED_MSG( rocksdb::DB::Open(options, _path, _cfDescriptors, &cfHandles, &db), "could not open RocksDB %s", _path ); _db = std::unique_ptr(db,closeDB); ALWAYS_ASSERT(_cfDescriptors.size() == cfHandles.size()); for (auto i = 0; i < _cfDescriptors.size(); ++i) { _cfs.insert(std::make_pair(_cfDescriptors[i].name, cfHandles[i])); } _cfDescriptors.clear(); } void SharedRocksDB::openTransactionDB(rocksdb::Options options) { std::unique_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() == nullptr); ALWAYS_ASSERT(options.statistics.get() == nullptr); _dbStatistics = rocksdb::CreateDBStatistics(); options.statistics = _dbStatistics; std::vector cfHandles; cfHandles.reserve(_cfDescriptors.size()); rocksdb::OptimisticTransactionDB* db; LOG_INFO(_env, "Opening RocksDB in %s", _path); ROCKS_DB_CHECKED_MSG( rocksdb::OptimisticTransactionDB::Open(options, _path, _cfDescriptors, &cfHandles, &db), "could not open RocksDB %s", _path ); _db = std::unique_ptr(db,closeDB); _transactionDB = true; ALWAYS_ASSERT(_cfDescriptors.size() == cfHandles.size()); for (auto i = 0; i < _cfDescriptors.size(); ++i) { _cfs.insert(std::make_pair(_cfDescriptors[i].name, cfHandles[i])); } _cfDescriptors.clear(); } void SharedRocksDB::openForReadOnly(rocksdb::Options options) { std::unique_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() == nullptr); options.create_if_missing = false; options.create_missing_column_families = false; std::vector cfHandles; cfHandles.reserve(_cfDescriptors.size()); rocksdb::DB* db; LOG_INFO(_env, "Opening RocksDB as readonly in %s", _path); ROCKS_DB_CHECKED_MSG( rocksdb::DB::OpenForReadOnly(options, _path, _cfDescriptors, &cfHandles, &db), "could not open RocksDB %s", _path ); _db = std::unique_ptr(db,closeDB); ALWAYS_ASSERT(_cfDescriptors.size() == cfHandles.size()); for (auto i = 0; i < _cfDescriptors.size(); ++i) { _cfs.insert(std::make_pair(_cfDescriptors[i].name, cfHandles[i])); } _cfDescriptors.clear(); } void SharedRocksDB::close() { std::unique_lock _(_stateMutex); if (_db.get() == nullptr) { return; } LOG_INFO(_env, "Destroying column families and closing database"); for( auto& cf : _cfs ) { ROCKS_DB_CHECKED(_db->DestroyColumnFamilyHandle(cf.second)); } _cfs.clear(); _db.reset(nullptr); LOG_INFO(_env, "database closed"); } void SharedRocksDB::registerCFDescriptors(const std::vector& cfDescriptors) { std::unique_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() == nullptr); _cfDescriptors.insert(_cfDescriptors.end(), cfDescriptors.begin(), cfDescriptors.end()); } rocksdb::ColumnFamilyHandle* SharedRocksDB::getCF(const std::string& name) const { std::shared_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); auto it = _cfs.find(name); if (it == _cfs.end()) { return nullptr; } return it->second; } void SharedRocksDB::deleteCF(const std::string& name) { std::unique_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); auto it = _cfs.find(name); if (it == _cfs.end()) { return; } ROCKS_DB_CHECKED(_db->DropColumnFamily(it->second)); ROCKS_DB_CHECKED(_db->DestroyColumnFamilyHandle(it->second)); _cfs.erase(it); } rocksdb::ColumnFamilyHandle* SharedRocksDB::createCF(const rocksdb::ColumnFamilyDescriptor& descriptor) { std::unique_lock _(_stateMutex); ASSERT(_db.get() != nullptr); auto it = _cfs.find(descriptor.name); if (it != _cfs.end()) { return it->second; } rocksdb::ColumnFamilyHandle* handle; ROCKS_DB_CHECKED(_db->CreateColumnFamily(descriptor.options, descriptor.name, &handle)); _cfs.emplace(descriptor.name, handle); return handle; } rocksdb::DB* SharedRocksDB::db() const { std::shared_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); return _db.get(); } rocksdb::OptimisticTransactionDB* SharedRocksDB::transactionDB() const { std::shared_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); ALWAYS_ASSERT(_transactionDB); return (rocksdb::OptimisticTransactionDB*)_db.get(); } void SharedRocksDB::rocksDBMetrics(std::unordered_map& stats) { std::shared_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); ::rocksDBMetrics(_env, _db.get(), *_dbStatistics, stats); } void SharedRocksDB::dumpRocksDBStatistics() { std::shared_lock _(_stateMutex); ALWAYS_ASSERT(_db.get() != nullptr); LOG_INFO(_env, "Dumping statistics to %s", _statisticsFilePath); std::ofstream file(_statisticsFilePath); file << _dbStatistics->ToString(); }