Skip to content

Commit

Permalink
refactor: update multithreading handling per PR
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewkeil committed Nov 9, 2023
1 parent 860daf1 commit 70da60a
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 36 deletions.
41 changes: 20 additions & 21 deletions binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct LevelDbHandle
{
leveldb::DB *db;
size_t open_handle_count;
bool multithreading;
};
static std::mutex handles_mutex;
// only access this when protected by the handles_mutex!
Expand Down Expand Up @@ -635,25 +634,27 @@ struct Database {
leveldb::Status threadsafe_open(const leveldb::Options &options,
bool multithreading,
Database &db_instance) {
// Bypass lock and handles if multithreading is disabled
if (!multithreading) {
return leveldb::DB::Open(options, db_instance.location_, &db_instance.db_);
}

std::unique_lock<std::mutex> lock(handles_mutex);

auto it = db_handles.find(db_instance.location_);
if (it == db_handles.end()) {
// Database not opened yet for this location
LevelDbHandle handle = {nullptr, 0, multithreading};
// Database not opened yet for this location, unless it was with
// multithreading disabled, in which case we're expected to fail here.
LevelDbHandle handle = {nullptr, 0};
leveldb::Status status = leveldb::DB::Open(options, db_instance.location_, &handle.db);
if (!status.ok()) {
return status;
}
handle.open_handle_count++;
db_instance.db_ = handle.db;
db_handles[db_instance.location_] = handle;
return leveldb::Status::OK();
}

if (!(it->second.multithreading && multithreading)) {
// Database already opened for this location that disallows multithreading
return leveldb::Status::InvalidArgument("Database already opened. Must set multithreading flag to true for all instances");
if (status.ok()) {
handle.open_handle_count++;
db_instance.db_ = handle.db;
db_handles[db_instance.location_] = handle;
}

return status;
}

++(it->second.open_handle_count);
Expand All @@ -664,20 +665,18 @@ leveldb::Status threadsafe_open(const leveldb::Options &options,

leveldb::Status threadsafe_close(Database &db_instance) {
std::unique_lock<std::mutex> lock(handles_mutex);
db_instance.db_ = NULL; // ensure db_ pointer is nullified in Database instance

auto it = db_handles.find(db_instance.location_);
if (it == db_handles.end()) {
// this should never happen in theory but silently fail and return OK to
// prevent segfault if it does
return leveldb::Status::OK();
}

if (--(it->second.open_handle_count) == 0) {
// Was not opened with multithreading enabled
delete db_instance.db_;
} else if (--(it->second.open_handle_count) == 0) {
delete it->second.db;
db_handles.erase(it);
}

// ensure db_ pointer is nullified in Database instance
db_instance.db_ = NULL;
return leveldb::Status::OK();
}

Expand Down
6 changes: 1 addition & 5 deletions test/lock-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ test('lock held by same process', async function (t) {
await db2.open()
} catch (err) {
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN', 'second instance failed to open')
t.is(
err.cause.message,
'Invalid argument: Database already opened. Must set multithreading flag to true for all instances',
'second instance got lock error'
)
t.is(err.cause.code, 'LEVEL_LOCKED', 'second instance got lock error')
}

return db1.close()
Expand Down
12 changes: 2 additions & 10 deletions test/multithreading-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@ test('check multithreading flag works as expected', async function (t) {
await db2.open({ multithreading: true })
} catch (err) {
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN', 'second instance failed to open')
t.is(
err.cause.message,
'Invalid argument: Database already opened. Must set multithreading flag to true for all instances',
'second instance got lock error'
)
t.is(err.cause.code, 'LEVEL_LOCKED', 'second instance got lock error')
}
await db1.close()

Expand All @@ -55,11 +51,7 @@ test('check multithreading flag works as expected', async function (t) {
await db4.open({ location, multithreading: false })
} catch (err) {
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN', 'fourth instance failed to open')
t.is(
err.cause.message,
'Invalid argument: Database already opened. Must set multithreading flag to true for all instances',
'fourth instance got lock error'
)
t.is(err.cause.code, 'LEVEL_LOCKED', 'second instance got lock error')
}
await db1.close()
await db2.close()
Expand Down

0 comments on commit 70da60a

Please sign in to comment.