Skip to content
This repository has been archived by the owner on Dec 1, 2024. It is now read-only.

Disable info log by default and add infoLogLevel option #114

Merged
merged 1 commit into from
May 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ prebuilds/
yarn.lock
package-lock.json
.nyc_output/
.benchmarks/
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ libleveldb.a
# Benchmarks and tests
bench/
test/
.benchmarks/
*.csv

# Misc
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ If you don't want to use the prebuilt binary for the platform you are installing
Please refer to [`leveldown`](https://github.com/Level/leveldown#api) for API documentation. The `db.open(options, callback)` method of `rocksdb` has a few additional options:

- `readOnly` (boolean, default `false`): open database in read-only mode.
- `infoLogLevel` (string, default `null`): verbosity of info log. One of `'debug'`, `'info'`, `'warn'`, `'error'`, `'fatal'`, `'header'` or `null` (disable).

## Contributing

Expand Down
44 changes: 41 additions & 3 deletions binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <rocksdb/write_batch.h>
#include <rocksdb/cache.h>
#include <rocksdb/filter_policy.h>
#include <rocksdb/utilities/leveldb_options.h>
#include <rocksdb/cache.h>
#include <rocksdb/comparator.h>
#include <rocksdb/env.h>
Expand All @@ -20,6 +19,13 @@ namespace leveldb = rocksdb;
#include <map>
#include <vector>

class NullLogger : public rocksdb::Logger {
public:
using rocksdb::Logger::Logv;
virtual void Logv(const char* format, va_list ap) override {}
virtual size_t GetLogFileSize() const override { return 0; }
};

/**
* Forward declarations.
*/
Expand Down Expand Up @@ -777,6 +783,7 @@ struct OpenWorker final : public BaseWorker {
uint32_t blockRestartInterval,
uint32_t maxFileSize,
uint32_t cacheSize,
const std::string& infoLogLevel,
bool readOnly)
: BaseWorker(env, database, callback, "leveldown.db.open"),
readOnly_(readOnly),
Expand All @@ -790,7 +797,25 @@ struct OpenWorker final : public BaseWorker {
options_.max_open_files = maxOpenFiles;
options_.max_log_file_size = maxFileSize;
options_.paranoid_checks = false;
options_.info_log_level = rocksdb::InfoLogLevel::WARN_LEVEL;

if (infoLogLevel.size() > 0) {
rocksdb::InfoLogLevel lvl;

if (infoLogLevel == "debug") lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
else if (infoLogLevel == "info") lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
else if (infoLogLevel == "warn") lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
else if (infoLogLevel == "error") lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
else if (infoLogLevel == "fatal") lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
else if (infoLogLevel == "header") lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
else napi_throw_error(env_, NULL, "invalid log level");

options_.info_log_level = lvl;
} else {
// In some places RocksDB checks this option to see if it should prepare
// debug information (ahead of logging), so set it to the highest level.
options_.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
options_.info_log.reset(new NullLogger());
}

rocksdb::BlockBasedTableOptions tableOptions;

Expand Down Expand Up @@ -834,6 +859,8 @@ NAPI_METHOD(db_open) {
bool compression = BooleanProperty(env, options, "compression", true);
bool readOnly = BooleanProperty(env, options, "readOnly", false);

std::string infoLogLevel = StringProperty(env, options, "infoLogLevel");

uint32_t cacheSize = Uint32Property(env, options, "cacheSize", 8 << 20);
uint32_t writeBufferSize = Uint32Property(env, options , "writeBufferSize" , 4 << 20);
uint32_t blockSize = Uint32Property(env, options, "blockSize", 4096);
Expand All @@ -847,7 +874,8 @@ NAPI_METHOD(db_open) {
createIfMissing, errorIfExists,
compression, writeBufferSize, blockSize,
maxOpenFiles, blockRestartInterval,
maxFileSize, cacheSize, readOnly);
maxFileSize, cacheSize,
infoLogLevel, readOnly);
worker->Queue();
delete [] location;

Expand Down Expand Up @@ -1192,6 +1220,11 @@ struct DestroyWorker final : public BaseWorker {

void DoExecute () override {
leveldb::Options options;

// TODO: support overriding infoLogLevel the same as db.open(options)
options.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
options.info_log.reset(new NullLogger());

SetStatus(leveldb::DestroyDB(location_, options));
}

Expand Down Expand Up @@ -1228,6 +1261,11 @@ struct RepairWorker final : public BaseWorker {

void DoExecute () override {
leveldb::Options options;

// TODO: support overriding infoLogLevel the same as db.open(options)
options.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
options.info_log.reset(new NullLogger());

SetStatus(leveldb::RepairDB(location_, options));
}

Expand Down
24 changes: 1 addition & 23 deletions leveldown.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const AbstractLevelDOWN = require('abstract-leveldown').AbstractLevelDOWN
const binding = require('./binding')
const ChainedBatch = require('./chained-batch')
const Iterator = require('./iterator')
const fs = require('fs')

function LevelDOWN (location) {
if (!(this instanceof LevelDOWN)) {
Expand Down Expand Up @@ -122,28 +121,7 @@ LevelDOWN.destroy = function (location, callback) {
throw new Error('destroy() requires a callback function argument')
}

binding.destroy_db(location, function (err) {
if (err) return callback(err)

// On Windows, RocksDB silently fails to remove the directory because its
// Logger, which is instantiated on destroy(), has an open file handle on a
// LOG file. Destroy() removes this file but Windows won't actually delete
// it until the handle is released. This happens when destroy() goes out of
// scope, which disposes the Logger. So back in JS-land, we can again
// attempt to remove the directory. This is merely a workaround because
// arguably RocksDB should not instantiate a Logger or open a file at all.
fs.rmdir(location, function (err) {
if (err) {
// Ignore this error in case there are non-RocksDB files left.
if (err.code === 'ENOTEMPTY') return callback()
if (err.code === 'ENOENT') return callback()

return callback(err)
}

callback()
})
})
binding.destroy_db(location, callback)
}

LevelDOWN.repair = function (location, callback) {
Expand Down
3 changes: 2 additions & 1 deletion test/destroy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ test('test destroy non-existent directory', function (t) {
t.ifError(err, 'no error from rimraf()')

leveldown.destroy(location, function (err) {
t.error(err, 'no error')
// This behavior differs from LevelDB, which is silent.
t.ok(/.*IO error.*/.test(err), 'got IO error')

// Assert that destroy() didn't inadvertently create the directory.
// Or if it did, that it was at least cleaned up afterwards.
Expand Down