move some logic from RocksHandles to RocksDbLocalStore

Summary:
This moves some logic from the RocksHandles class up to RocksDbLocalStore.
The main thing moved here is the logic to automatically try and repair the DB
if opening fails.  This will make it easier in a subsequent diff to make the
repair logic a bit smarter and more aware of our column family semantics.

This keeps RocksHandles a pretty dumb wrapper around the RocksDB object and
column family handles, whose only purpose is to manage destroying these two
things in the correct order.

Reviewed By: chadaustin

Differential Revision: D15043208

fbshipit-source-id: ee2d5619ac7781a892e1ba151712eee9e3ebfb14
This commit is contained in:
Adam Simpkins 2019-04-24 19:59:48 -07:00 committed by Facebook Github Bot
parent 256422737d
commit 2faa637da5
3 changed files with 63 additions and 55 deletions

View File

@ -11,6 +11,8 @@
#include <folly/logging/xlog.h>
#include "eden/fs/rocksdb/RocksException.h"
using folly::StringPiece;
using rocksdb::ColumnFamilyDescriptor;
using rocksdb::ColumnFamilyHandle;
@ -26,6 +28,10 @@ namespace facebook {
namespace eden {
RocksHandles::~RocksHandles() {
close();
}
void RocksHandles::close() {
// MUST destroy the column handles first
columns.clear();
db.reset();
@ -33,33 +39,12 @@ RocksHandles::~RocksHandles() {
RocksHandles::RocksHandles(
StringPiece dbPath,
const Options& options,
const std::vector<ColumnFamilyDescriptor>& columnDescriptors) {
auto dbPathStr = dbPath.str();
Options options;
// Optimize RocksDB. This is the easiest way to get RocksDB to perform well.
options.IncreaseParallelism();
// Create the DB if it's not already present.
options.create_if_missing = true;
// Automatically create column families as we define new ones.
options.create_missing_column_families = true;
// If we wanted we could set options.info_log to control where RocksDB
// log messages get sent. By default they are written to a file named "LOG"
// in the DB directory.
// options.info_log = make_shared<CustomLogger>(InfoLogLevel::INFO_LEVEL);
DB* dbRaw;
columns.reserve(columnDescriptors.size());
std::vector<ColumnFamilyHandle*> columnHandles;
auto openDB = [&] {
return DB::Open(
options, dbPathStr, columnDescriptors, &columnHandles, &dbRaw);
};
// This will create any newly defined column families automatically,
// so we needn't make any special migration steps here; just define
// a new family and start to use it.
@ -67,36 +52,17 @@ RocksHandles::RocksHandles(
// and shout at us for not opening up the database with them defined.
// We will need to do "something smarter" if we ever decide to perform
// that kind of a migration.
auto status = openDB();
auto status =
DB::Open(options, dbPathStr, columnDescriptors, &columnHandles, &dbRaw);
if (!status.ok()) {
XLOG(ERR) << "Error opening RocksDB storage at " << dbPathStr << ": "
<< status.ToString();
XLOG(ERR) << "Attempting to repair RocksDB " << dbPathStr;
rocksdb::ColumnFamilyOptions unknownColumFamilyOptions;
unknownColumFamilyOptions.OptimizeForPointLookup(8);
unknownColumFamilyOptions.OptimizeLevelStyleCompaction();
DBOptions dbOptions(options);
status = RepairDB(
dbPathStr, dbOptions, columnDescriptors, unknownColumFamilyOptions);
if (!status.ok()) {
throw std::runtime_error(folly::to<string>(
"Unable to repair RocksDB at ", dbPathStr, ": ", status.ToString()));
}
columnHandles.clear();
status = openDB();
if (!status.ok()) {
throw std::runtime_error(folly::to<string>(
"Failed to open RocksDB at ",
dbPathStr,
" after repair attempt: ",
status.ToString()));
}
throw RocksException::build(
status, "error opening RocksDB storage at", dbPathStr);
}
db.reset(dbRaw);
columns.reserve(columnHandles.size());
for (auto h : columnHandles) {
columns.emplace_back(h);
}

View File

@ -48,12 +48,10 @@ struct RocksHandles {
*/
RocksHandles(
folly::StringPiece dbPath,
const rocksdb::Options& options,
const std::vector<rocksdb::ColumnFamilyDescriptor>& columnDescriptors);
RocksHandles(const RocksHandles&) = delete;
RocksHandles& operator=(const RocksHandles&) = delete;
RocksHandles(RocksHandles&&) = default;
RocksHandles& operator=(RocksHandles&&) = default;
void close();
};
} // namespace eden
} // namespace facebook

View File

@ -178,6 +178,52 @@ void RocksDbWriteBatch::put(
flushIfNeeded();
}
rocksdb::Options getRocksdbOptions() {
rocksdb::Options options;
// Optimize RocksDB. This is the easiest way to get RocksDB to perform well.
options.IncreaseParallelism();
// Create the DB if it's not already present.
options.create_if_missing = true;
// Automatically create column families as we define new ones.
options.create_missing_column_families = true;
return options;
}
void repairDB(AbsolutePathPiece path) {
XLOG(ERR) << "Attempting to repair RocksDB " << path;
rocksdb::ColumnFamilyOptions unknownColumFamilyOptions;
unknownColumFamilyOptions.OptimizeForPointLookup(8);
unknownColumFamilyOptions.OptimizeLevelStyleCompaction();
const auto& columnDescriptors = columnFamilies();
auto dbPathStr = path.stringPiece().str();
rocksdb::DBOptions dbOptions(getRocksdbOptions());
auto status = RepairDB(
dbPathStr, dbOptions, columnDescriptors, unknownColumFamilyOptions);
if (!status.ok()) {
throw RocksException::build(status, "unable to repair RocksDB at ", path);
}
}
RocksHandles openDB(AbsolutePathPiece path) {
auto options = getRocksdbOptions();
try {
return RocksHandles(path.stringPiece(), options, columnFamilies());
} catch (const RocksException& ex) {
XLOG(ERR) << "Error opening RocksDB storage at " << path << ": "
<< ex.what();
// Fall through and attempt to repair the DB
}
repairDB(path);
// Now try opening the DB again.
return RocksHandles(path.stringPiece(), options, columnFamilies());
}
} // namespace
namespace facebook {
@ -189,9 +235,8 @@ RocksDbLocalStore::RocksDbLocalStore(
std::shared_ptr<ReloadableConfig> config)
: LocalStore(std::move(config)),
faultInjector_(*faultInjector),
dbHandles_(pathToRocksDb.stringPiece(), columnFamilies()),
ioPool_(12, "RocksLocalStore") {
}
dbHandles_(openDB(pathToRocksDb)),
ioPool_(12, "RocksLocalStore") {}
RocksDbLocalStore::~RocksDbLocalStore() {
#ifdef FOLLY_SANITIZE_ADDRESS
@ -209,8 +254,7 @@ RocksDbLocalStore::~RocksDbLocalStore() {
}
void RocksDbLocalStore::close() {
dbHandles_.columns.clear();
dbHandles_.db.reset();
dbHandles_.close();
}
void RocksDbLocalStore::clearKeySpace(KeySpace keySpace) {