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

Commit 002d836

Browse files
authored
Disable info log by default and add infoLogLevel option (#114)
1 parent 5678c16 commit 002d836

File tree

6 files changed

+47
-27
lines changed

6 files changed

+47
-27
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ prebuilds/
2020
yarn.lock
2121
package-lock.json
2222
.nyc_output/
23+
.benchmarks/

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ libleveldb.a
4242
# Benchmarks and tests
4343
bench/
4444
test/
45+
.benchmarks/
4546
*.csv
4647

4748
# Misc

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ If you don't want to use the prebuilt binary for the platform you are installing
5555
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:
5656

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

5960
## Contributing
6061

binding.cc

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <rocksdb/write_batch.h>
99
#include <rocksdb/cache.h>
1010
#include <rocksdb/filter_policy.h>
11-
#include <rocksdb/utilities/leveldb_options.h>
1211
#include <rocksdb/cache.h>
1312
#include <rocksdb/comparator.h>
1413
#include <rocksdb/env.h>
@@ -20,6 +19,13 @@ namespace leveldb = rocksdb;
2019
#include <map>
2120
#include <vector>
2221

22+
class NullLogger : public rocksdb::Logger {
23+
public:
24+
using rocksdb::Logger::Logv;
25+
virtual void Logv(const char* format, va_list ap) override {}
26+
virtual size_t GetLogFileSize() const override { return 0; }
27+
};
28+
2329
/**
2430
* Forward declarations.
2531
*/
@@ -777,6 +783,7 @@ struct OpenWorker final : public BaseWorker {
777783
uint32_t blockRestartInterval,
778784
uint32_t maxFileSize,
779785
uint32_t cacheSize,
786+
const std::string& infoLogLevel,
780787
bool readOnly)
781788
: BaseWorker(env, database, callback, "leveldown.db.open"),
782789
readOnly_(readOnly),
@@ -790,7 +797,25 @@ struct OpenWorker final : public BaseWorker {
790797
options_.max_open_files = maxOpenFiles;
791798
options_.max_log_file_size = maxFileSize;
792799
options_.paranoid_checks = false;
793-
options_.info_log_level = rocksdb::InfoLogLevel::WARN_LEVEL;
800+
801+
if (infoLogLevel.size() > 0) {
802+
rocksdb::InfoLogLevel lvl;
803+
804+
if (infoLogLevel == "debug") lvl = rocksdb::InfoLogLevel::DEBUG_LEVEL;
805+
else if (infoLogLevel == "info") lvl = rocksdb::InfoLogLevel::INFO_LEVEL;
806+
else if (infoLogLevel == "warn") lvl = rocksdb::InfoLogLevel::WARN_LEVEL;
807+
else if (infoLogLevel == "error") lvl = rocksdb::InfoLogLevel::ERROR_LEVEL;
808+
else if (infoLogLevel == "fatal") lvl = rocksdb::InfoLogLevel::FATAL_LEVEL;
809+
else if (infoLogLevel == "header") lvl = rocksdb::InfoLogLevel::HEADER_LEVEL;
810+
else napi_throw_error(env_, NULL, "invalid log level");
811+
812+
options_.info_log_level = lvl;
813+
} else {
814+
// In some places RocksDB checks this option to see if it should prepare
815+
// debug information (ahead of logging), so set it to the highest level.
816+
options_.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
817+
options_.info_log.reset(new NullLogger());
818+
}
794819

795820
rocksdb::BlockBasedTableOptions tableOptions;
796821

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

862+
std::string infoLogLevel = StringProperty(env, options, "infoLogLevel");
863+
837864
uint32_t cacheSize = Uint32Property(env, options, "cacheSize", 8 << 20);
838865
uint32_t writeBufferSize = Uint32Property(env, options , "writeBufferSize" , 4 << 20);
839866
uint32_t blockSize = Uint32Property(env, options, "blockSize", 4096);
@@ -847,7 +874,8 @@ NAPI_METHOD(db_open) {
847874
createIfMissing, errorIfExists,
848875
compression, writeBufferSize, blockSize,
849876
maxOpenFiles, blockRestartInterval,
850-
maxFileSize, cacheSize, readOnly);
877+
maxFileSize, cacheSize,
878+
infoLogLevel, readOnly);
851879
worker->Queue();
852880
delete [] location;
853881

@@ -1192,6 +1220,11 @@ struct DestroyWorker final : public BaseWorker {
11921220

11931221
void DoExecute () override {
11941222
leveldb::Options options;
1223+
1224+
// TODO: support overriding infoLogLevel the same as db.open(options)
1225+
options.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
1226+
options.info_log.reset(new NullLogger());
1227+
11951228
SetStatus(leveldb::DestroyDB(location_, options));
11961229
}
11971230

@@ -1228,6 +1261,11 @@ struct RepairWorker final : public BaseWorker {
12281261

12291262
void DoExecute () override {
12301263
leveldb::Options options;
1264+
1265+
// TODO: support overriding infoLogLevel the same as db.open(options)
1266+
options.info_log_level = rocksdb::InfoLogLevel::HEADER_LEVEL;
1267+
options.info_log.reset(new NullLogger());
1268+
12311269
SetStatus(leveldb::RepairDB(location_, options));
12321270
}
12331271

leveldown.js

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ const AbstractLevelDOWN = require('abstract-leveldown').AbstractLevelDOWN
33
const binding = require('./binding')
44
const ChainedBatch = require('./chained-batch')
55
const Iterator = require('./iterator')
6-
const fs = require('fs')
76

87
function LevelDOWN (location) {
98
if (!(this instanceof LevelDOWN)) {
@@ -122,28 +121,7 @@ LevelDOWN.destroy = function (location, callback) {
122121
throw new Error('destroy() requires a callback function argument')
123122
}
124123

125-
binding.destroy_db(location, function (err) {
126-
if (err) return callback(err)
127-
128-
// On Windows, RocksDB silently fails to remove the directory because its
129-
// Logger, which is instantiated on destroy(), has an open file handle on a
130-
// LOG file. Destroy() removes this file but Windows won't actually delete
131-
// it until the handle is released. This happens when destroy() goes out of
132-
// scope, which disposes the Logger. So back in JS-land, we can again
133-
// attempt to remove the directory. This is merely a workaround because
134-
// arguably RocksDB should not instantiate a Logger or open a file at all.
135-
fs.rmdir(location, function (err) {
136-
if (err) {
137-
// Ignore this error in case there are non-RocksDB files left.
138-
if (err.code === 'ENOTEMPTY') return callback()
139-
if (err.code === 'ENOENT') return callback()
140-
141-
return callback(err)
142-
}
143-
144-
callback()
145-
})
146-
})
124+
binding.destroy_db(location, callback)
147125
}
148126

149127
LevelDOWN.repair = function (location, callback) {

test/destroy-test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ test('test destroy non-existent directory', function (t) {
3838
t.ifError(err, 'no error from rimraf()')
3939

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

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

0 commit comments

Comments
 (0)