Remove tools/rdb from main repo (#9399)
Summary: This PR is one proposal to resolve https://github.com/facebook/rocksdb/issues/9382. Looking at the code, I can't think of a reason why rdb is an internal component of RocksDB: it does not require any header files NOT in `include/rocksdb`. It's a better idea to host it somewhere else. Plus, rdb requires python2 which is not supported any more. No fixes or improvements will be made, even for potential security bugs (https://www.python.org/doc/sunset-python-2/). Pull Request resolved: https://github.com/facebook/rocksdb/pull/9399 Test Plan: make check Reviewed By: ajkr Differential Revision: D33641965 Pulled By: riversand963 fbshipit-source-id: 2a6a74693e5de36834f355e41d6865db206af48b
This commit is contained in:
parent
50135c1bf3
commit
5d30668cab
2
Makefile
2
Makefile
@ -561,7 +561,7 @@ ifneq ($(filter check-headers, $(MAKECMDGOALS)),)
|
|||||||
# TODO: add/support JNI headers
|
# TODO: add/support JNI headers
|
||||||
DEV_HEADER_DIRS := $(sort include/ $(dir $(ALL_SOURCES)))
|
DEV_HEADER_DIRS := $(sort include/ $(dir $(ALL_SOURCES)))
|
||||||
# Some headers like in port/ are platform-specific
|
# Some headers like in port/ are platform-specific
|
||||||
DEV_HEADERS := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | egrep -v 'port/|plugin/|lua/|range_tree/|tools/rdb/db_wrapper.h|include/rocksdb/utilities/env_librados.h')
|
DEV_HEADERS := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | egrep -v 'port/|plugin/|lua/|range_tree/|include/rocksdb/utilities/env_librados.h')
|
||||||
else
|
else
|
||||||
DEV_HEADERS :=
|
DEV_HEADERS :=
|
||||||
endif
|
endif
|
||||||
|
1
tools/rdb/.gitignore
vendored
1
tools/rdb/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
build
|
|
178
tools/rdb/API.md
178
tools/rdb/API.md
@ -1,178 +0,0 @@
|
|||||||
# JavaScript API
|
|
||||||
|
|
||||||
## DBWrapper
|
|
||||||
|
|
||||||
### Constructor
|
|
||||||
|
|
||||||
# Creates a new database wrapper object
|
|
||||||
RDB()
|
|
||||||
|
|
||||||
### Open
|
|
||||||
|
|
||||||
# Open a new or existing RocksDB database.
|
|
||||||
#
|
|
||||||
# db_name (string) - Location of the database (inside the
|
|
||||||
# `/tmp` directory).
|
|
||||||
# column_families (string[]) - Names of additional column families
|
|
||||||
# beyond the default. If there are no other
|
|
||||||
# column families, this argument can be
|
|
||||||
# left off.
|
|
||||||
#
|
|
||||||
# Returns true if the database was opened successfully, or false otherwise
|
|
||||||
db_obj.(db_name, column_families = [])
|
|
||||||
|
|
||||||
### Get
|
|
||||||
|
|
||||||
# Get the value of a given key.
|
|
||||||
#
|
|
||||||
# key (string) - Which key to get the value of.
|
|
||||||
# column_family (string) - Which column family to check for the key.
|
|
||||||
# This argument can be left off for the default
|
|
||||||
# column family
|
|
||||||
#
|
|
||||||
# Returns the value (string) that is associated with the given key if
|
|
||||||
# one exists, or null otherwise.
|
|
||||||
db_obj.get(key, column_family = { default })
|
|
||||||
|
|
||||||
### Put
|
|
||||||
|
|
||||||
# Associate a value with a key.
|
|
||||||
#
|
|
||||||
# key (string) - Which key to associate the value with.
|
|
||||||
# value (string) - The value to associate with the key.
|
|
||||||
# column_family (string) - Which column family to put the key-value pair
|
|
||||||
# in. This argument can be left off for the
|
|
||||||
# default column family.
|
|
||||||
#
|
|
||||||
# Returns true if the key-value pair was successfully stored in the
|
|
||||||
# database, or false otherwise.
|
|
||||||
db_obj.put(key, value, column_family = { default })
|
|
||||||
|
|
||||||
### Delete
|
|
||||||
|
|
||||||
# Delete a value associated with a given key.
|
|
||||||
#
|
|
||||||
# key (string) - Which key to delete the value of..
|
|
||||||
# column_family (string) - Which column family to check for the key.
|
|
||||||
# This argument can be left off for the default
|
|
||||||
# column family
|
|
||||||
#
|
|
||||||
# Returns true if an error occurred while trying to delete the key in
|
|
||||||
# the database, or false otherwise. Note that this is NOT the same as
|
|
||||||
# whether a value was deleted; in the case of a specified key not having
|
|
||||||
# a value, this will still return true. Use the `get` method prior to
|
|
||||||
# this method to check if a value existed before the call to `delete`.
|
|
||||||
db_obj.delete(key, column_family = { default })
|
|
||||||
|
|
||||||
### Dump
|
|
||||||
|
|
||||||
# Print out all the key-value pairs in a given column family of the
|
|
||||||
# database.
|
|
||||||
#
|
|
||||||
# column_family (string) - Which column family to dump the pairs from.
|
|
||||||
# This argument can be left off for the default
|
|
||||||
# column family.
|
|
||||||
#
|
|
||||||
# Returns true if the keys were successfully read from the database, or
|
|
||||||
# false otherwise.
|
|
||||||
db_obj.dump(column_family = { default })
|
|
||||||
|
|
||||||
### WriteBatch
|
|
||||||
|
|
||||||
# Execute an atomic batch of writes (i.e. puts and deletes) to the
|
|
||||||
# database.
|
|
||||||
#
|
|
||||||
# cf_batches (BatchObject[]; see below) - Put and Delete writes grouped
|
|
||||||
# by column family to execute
|
|
||||||
# atomically.
|
|
||||||
#
|
|
||||||
# Returns true if the argument array was well-formed and was
|
|
||||||
# successfully written to the database, or false otherwise.
|
|
||||||
db_obj.writeBatch(cf_batches)
|
|
||||||
|
|
||||||
### CreateColumnFamily
|
|
||||||
|
|
||||||
# Create a new column family for the database.
|
|
||||||
#
|
|
||||||
# column_family_name (string) - Name of the new column family.
|
|
||||||
#
|
|
||||||
# Returns true if the new column family was successfully created, or
|
|
||||||
# false otherwise.
|
|
||||||
db_obj.createColumnFamily(column_family_name)
|
|
||||||
|
|
||||||
### CompactRange
|
|
||||||
|
|
||||||
# Compact the underlying storage for a given range.
|
|
||||||
#
|
|
||||||
# In addition to the endpoints of the range, the method is overloaded to
|
|
||||||
# accept a non-default column family, a set of options, or both.
|
|
||||||
#
|
|
||||||
# begin (string) - First key in the range to compact.
|
|
||||||
# end (string) - Last key in the range to compact.
|
|
||||||
# options (object) - Contains a subset of the following key-value
|
|
||||||
# pairs:
|
|
||||||
# * 'target_level' => int
|
|
||||||
# * 'target_path_id' => int
|
|
||||||
# column_family (string) - Which column family to compact the range in.
|
|
||||||
db_obj.compactRange(begin, end)
|
|
||||||
db_obj.compactRange(begin, end, options)
|
|
||||||
db_obj.compactRange(begin, end, column_family)
|
|
||||||
db_obj.compactRange(begin, end, options, column_family)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Close
|
|
||||||
|
|
||||||
# Close an a database and free the memory associated with it.
|
|
||||||
#
|
|
||||||
# Return null.
|
|
||||||
# db_obj.close()
|
|
||||||
|
|
||||||
|
|
||||||
## BatchObject
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
|
|
||||||
A BatchObject must have at least one of the following key-value pairs:
|
|
||||||
|
|
||||||
* 'put' => Array of ['string1', 'string1'] pairs, each of which signifies that
|
|
||||||
the key 'string1' should be associated with the value 'string2'
|
|
||||||
* 'delete' => Array of strings, each of which is a key whose value should be
|
|
||||||
deleted.
|
|
||||||
|
|
||||||
The following key-value pair is optional:
|
|
||||||
|
|
||||||
* 'column_family' => The name (string) of the column family to apply the
|
|
||||||
changes to.
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
# Writes the key-value pairs 'firstname' => 'Saghm' and
|
|
||||||
# 'lastname' => 'Rossi' atomically to the database.
|
|
||||||
db_obj.writeBatch([
|
|
||||||
{
|
|
||||||
put: [ ['firstname', 'Saghm'], ['lastname', 'Rossi'] ]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
# Deletes the values associated with 'firstname' and 'lastname' in
|
|
||||||
# the default column family and adds the key 'number_of_people' with
|
|
||||||
# with the value '2'. Additionally, adds the key-value pair
|
|
||||||
# 'name' => 'Saghm Rossi' to the column family 'user1' and the pair
|
|
||||||
# 'name' => 'Matt Blaze' to the column family 'user2'. All writes
|
|
||||||
# are done atomically.
|
|
||||||
db_obj.writeBatch([
|
|
||||||
{
|
|
||||||
put: [ ['number_of_people', '2'] ],
|
|
||||||
delete: ['firstname', 'lastname']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
put: [ ['name', 'Saghm Rossi'] ],
|
|
||||||
column_family: 'user1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
put: [ ['name', Matt Blaze'] ],
|
|
||||||
column_family: 'user2'
|
|
||||||
}
|
|
||||||
]);
|
|
@ -1,40 +0,0 @@
|
|||||||
# RDB - RocksDB Shell
|
|
||||||
|
|
||||||
RDB is a NodeJS-based shell interface to RocksDB. It can also be used as a
|
|
||||||
JavaScript binding for RocksDB within a Node application.
|
|
||||||
|
|
||||||
## Setup/Compilation
|
|
||||||
|
|
||||||
### Requirements
|
|
||||||
|
|
||||||
* static RocksDB library (i.e. librocksdb.a)
|
|
||||||
* libsnappy
|
|
||||||
* node (tested onv0.10.33, no guarantees on anything else!)
|
|
||||||
* node-gyp
|
|
||||||
* python2 (for node-gyp; tested with 2.7.8)
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
NOTE: If your default `python` binary is not a version of python2, add
|
|
||||||
the arguments `--python /path/to/python2` to the `node-gyp` commands.
|
|
||||||
|
|
||||||
1. Make sure you have the static library (i.e. "librocksdb.a") in the root
|
|
||||||
directory of your rocksdb installation. If not, `cd` there and run
|
|
||||||
`make static_lib`.
|
|
||||||
|
|
||||||
2. Run `node-gyp configure` to generate the build.
|
|
||||||
|
|
||||||
3. Run `node-gyp build` to compile RDB.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Running the shell
|
|
||||||
|
|
||||||
Assuming everything compiled correctly, you can run the `rdb` executable
|
|
||||||
located in the root of the `tools/rdb` directory to start the shell. The file is
|
|
||||||
just a shell script that runs the node shell and loads the constructor for the
|
|
||||||
RDB object into the top-level function `RDB`.
|
|
||||||
|
|
||||||
### JavaScript API
|
|
||||||
|
|
||||||
See `API.md` for how to use RocksDB from the shell.
|
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"target_name": "rdb",
|
|
||||||
"sources": [
|
|
||||||
"rdb.cc",
|
|
||||||
"db_wrapper.cc",
|
|
||||||
"db_wrapper.h"
|
|
||||||
],
|
|
||||||
"cflags_cc!": [
|
|
||||||
"-fno-exceptions"
|
|
||||||
],
|
|
||||||
"cflags_cc+": [
|
|
||||||
"-std=c++11",
|
|
||||||
],
|
|
||||||
"include_dirs+": [
|
|
||||||
"../../include"
|
|
||||||
],
|
|
||||||
"libraries": [
|
|
||||||
"../../../librocksdb.a",
|
|
||||||
"-lsnappy"
|
|
||||||
],
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,523 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <v8.h>
|
|
||||||
#include <node.h>
|
|
||||||
|
|
||||||
#include "db/_wrapper.h"
|
|
||||||
#include "rocksdb/db.h"
|
|
||||||
#include "rocksdb/options.h"
|
|
||||||
#include "rocksdb/slice.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void printWithBackSlashes(std::string str) {
|
|
||||||
for (std::string::size_type i = 0; i < str.size(); i++) {
|
|
||||||
if (str[i] == '\\' || str[i] == '"') {
|
|
||||||
std::cout << "\\";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << str[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_key_for_array(Local<Object> obj, std::string key) {
|
|
||||||
return obj->Has(String::NewSymbol(key.c_str())) &&
|
|
||||||
obj->Get(String::NewSymbol(key.c_str()))->IsArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Persistent<Function> DBWrapper::constructor;
|
|
||||||
|
|
||||||
DBWrapper::DBWrapper() {
|
|
||||||
options_.IncreaseParallelism();
|
|
||||||
options_.OptimizeLevelStyleCompaction();
|
|
||||||
options_.disable_auto_compactions = true;
|
|
||||||
options_.create_if_missing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper::~DBWrapper() {
|
|
||||||
delete db_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBWrapper::HasFamilyNamed(std::string& name, DBWrapper* db) {
|
|
||||||
return db->columnFamilies_.find(name) != db->columnFamilies_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DBWrapper::Init(Handle<Object> exports) {
|
|
||||||
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
|
|
||||||
tpl->SetClassName(String::NewSymbol("DBWrapper"));
|
|
||||||
tpl->InstanceTemplate()->SetInternalFieldCount(8);
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("open"),
|
|
||||||
FunctionTemplate::New(Open)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("get"),
|
|
||||||
FunctionTemplate::New(Get)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("put"),
|
|
||||||
FunctionTemplate::New(Put)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("delete"),
|
|
||||||
FunctionTemplate::New(Delete)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("dump"),
|
|
||||||
FunctionTemplate::New(Dump)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("createColumnFamily"),
|
|
||||||
FunctionTemplate::New(CreateColumnFamily)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("writeBatch"),
|
|
||||||
FunctionTemplate::New(WriteBatch)->GetFunction());
|
|
||||||
tpl->PrototypeTemplate()->Set(String::NewSymbol("compactRange"),
|
|
||||||
FunctionTemplate::New(CompactRange)->GetFunction());
|
|
||||||
|
|
||||||
constructor = Persistent<Function>::New(tpl->GetFunction());
|
|
||||||
exports->Set(String::NewSymbol("DBWrapper"), constructor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Open(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
|
|
||||||
if (!(args[0]->IsString() &&
|
|
||||||
(args[1]->IsUndefined() || args[1]->IsArray()))) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string db_file = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
|
|
||||||
std::vector<std::string> cfs = {ROCKSDB_NAMESPACE::kDefaultColumnFamilyName};
|
|
||||||
|
|
||||||
if (!args[1]->IsUndefined()) {
|
|
||||||
Handle<Array> array = Handle<Array>::Cast(args[1]);
|
|
||||||
for (uint i = 0; i < array->Length(); i++) {
|
|
||||||
if (!array->Get(i)->IsString()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
cfs.push_back(*v8::String::Utf8Value(array->Get(i)->ToString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfs.size() == 1) {
|
|
||||||
db_wrapper->status_ = ROCKSDB_NAMESPACE::DB::Open(
|
|
||||||
db_wrapper->options_, db_file, &db_wrapper->db_);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> families;
|
|
||||||
|
|
||||||
for (std::vector<int>::size_type i = 0; i < cfs.size(); i++) {
|
|
||||||
families.push_back(ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(
|
|
||||||
cfs[i], ROCKSDB_NAMESPACE::ColumnFamilyOptions()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> handles;
|
|
||||||
db_wrapper->status_ = ROCKSDB_NAMESPACE::DB::Open(
|
|
||||||
db_wrapper->options_, db_file, families, &handles, &db_wrapper->db_);
|
|
||||||
|
|
||||||
if (!db_wrapper->status_.ok()) {
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<int>::size_type i = 0; i < handles.size(); i++) {
|
|
||||||
db_wrapper->columnFamilies_[cfs[i]] = handles[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::New(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
Handle<Value> to_return;
|
|
||||||
|
|
||||||
if (args.IsConstructCall()) {
|
|
||||||
DBWrapper* db_wrapper = new DBWrapper();
|
|
||||||
db_wrapper->Wrap(args.This());
|
|
||||||
|
|
||||||
return args.This();
|
|
||||||
}
|
|
||||||
|
|
||||||
const int argc = 0;
|
|
||||||
Local<Value> argv[0] = {};
|
|
||||||
|
|
||||||
return scope.Close(constructor->NewInstance(argc, argv));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Get(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!(args[0]->IsString() &&
|
|
||||||
(args[1]->IsUndefined() || args[1]->IsString()))) {
|
|
||||||
return scope.Close(Null());
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
std::string key = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
std::string cf = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
std::string value;
|
|
||||||
|
|
||||||
if (args[1]->IsUndefined()) {
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Get(ROCKSDB_NAMESPACE::ReadOptions(), key, &value);
|
|
||||||
} else if (db_wrapper->HasFamilyNamed(cf, db_wrapper)) {
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Get(ROCKSDB_NAMESPACE::ReadOptions(),
|
|
||||||
db_wrapper->columnFamilies_[cf], key, &value);
|
|
||||||
} else {
|
|
||||||
return scope.Close(Null());
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> v = db_wrapper->status_.ok() ?
|
|
||||||
String::NewSymbol(value.c_str()) : Null();
|
|
||||||
|
|
||||||
return scope.Close(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Put(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!(args[0]->IsString() && args[1]->IsString() &&
|
|
||||||
(args[2]->IsUndefined() || args[2]->IsString()))) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
std::string key = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
std::string value = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
std::string cf = *v8::String::Utf8Value(args[2]->ToString());
|
|
||||||
|
|
||||||
if (args[2]->IsUndefined()) {
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Put(ROCKSDB_NAMESPACE::WriteOptions(), key, value);
|
|
||||||
} else if (db_wrapper->HasFamilyNamed(cf, db_wrapper)) {
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Put(ROCKSDB_NAMESPACE::WriteOptions(),
|
|
||||||
db_wrapper->columnFamilies_[cf], key, value);
|
|
||||||
} else {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Delete(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[0]->IsString()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
std::string arg0 = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
std::string arg1 = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
|
|
||||||
if (args[1]->IsUndefined()) {
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Delete(ROCKSDB_NAMESPACE::WriteOptions(), arg0);
|
|
||||||
} else {
|
|
||||||
if (!db_wrapper->HasFamilyNamed(arg1, db_wrapper)) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Delete(ROCKSDB_NAMESPACE::WriteOptions(),
|
|
||||||
db_wrapper->columnFamilies_[arg1], arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Dump(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
std::unique_ptr<ROCKSDB_NAMESPACE::Iterator> iterator;
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
std::string arg0 = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
|
|
||||||
if (args[0]->IsUndefined()) {
|
|
||||||
iterator.reset(
|
|
||||||
db_wrapper->db_->NewIterator(ROCKSDB_NAMESPACE::ReadOptions()));
|
|
||||||
} else {
|
|
||||||
if (!db_wrapper->HasFamilyNamed(arg0, db_wrapper)) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator.reset(db_wrapper->db_->NewIterator(
|
|
||||||
ROCKSDB_NAMESPACE::ReadOptions(), db_wrapper->columnFamilies_[arg0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator->SeekToFirst();
|
|
||||||
|
|
||||||
while (iterator->Valid()) {
|
|
||||||
std::cout << "\"";
|
|
||||||
printWithBackSlashes(iterator->key().ToString());
|
|
||||||
std::cout << "\" => \"";
|
|
||||||
printWithBackSlashes(iterator->value().ToString());
|
|
||||||
std::cout << "\"\n";
|
|
||||||
iterator->Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CreateColumnFamily(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[0]->IsString()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
std::string cf_name = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
|
|
||||||
if (db_wrapper->HasFamilyNamed(cf_name, db_wrapper)) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf;
|
|
||||||
db_wrapper->status_ = db_wrapper->db_->CreateColumnFamily(
|
|
||||||
ROCKSDB_NAMESPACE::ColumnFamilyOptions(), cf_name, &cf);
|
|
||||||
|
|
||||||
if (!db_wrapper->status_.ok()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
db_wrapper->columnFamilies_[cf_name] = cf;
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBWrapper::AddToBatch(ROCKSDB_NAMESPACE::WriteBatch& batch, bool del,
|
|
||||||
Handle<Array> array) {
|
|
||||||
Handle<Array> put_pair;
|
|
||||||
for (uint i = 0; i < array->Length(); i++) {
|
|
||||||
if (del) {
|
|
||||||
if (!array->Get(i)->IsString()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.Delete(*v8::String::Utf8Value(array->Get(i)->ToString()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array->Get(i)->IsArray()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
put_pair = Handle<Array>::Cast(array->Get(i));
|
|
||||||
|
|
||||||
if (!put_pair->Get(0)->IsString() || !put_pair->Get(1)->IsString()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.Put(
|
|
||||||
*v8::String::Utf8Value(put_pair->Get(0)->ToString()),
|
|
||||||
*v8::String::Utf8Value(put_pair->Get(1)->ToString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBWrapper::AddToBatch(ROCKSDB_NAMESPACE::WriteBatch& batch, bool del,
|
|
||||||
Handle<Array> array, DBWrapper* db_wrapper,
|
|
||||||
std::string cf) {
|
|
||||||
Handle<Array> put_pair;
|
|
||||||
for (uint i = 0; i < array->Length(); i++) {
|
|
||||||
if (del) {
|
|
||||||
if (!array->Get(i)->IsString()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.Delete(
|
|
||||||
db_wrapper->columnFamilies_[cf],
|
|
||||||
*v8::String::Utf8Value(array->Get(i)->ToString()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array->Get(i)->IsArray()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
put_pair = Handle<Array>::Cast(array->Get(i));
|
|
||||||
|
|
||||||
if (!put_pair->Get(0)->IsString() || !put_pair->Get(1)->IsString()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.Put(
|
|
||||||
db_wrapper->columnFamilies_[cf],
|
|
||||||
*v8::String::Utf8Value(put_pair->Get(0)->ToString()),
|
|
||||||
*v8::String::Utf8Value(put_pair->Get(1)->ToString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::WriteBatch(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[0]->IsArray()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
Handle<Array> sub_batches = Handle<Array>::Cast(args[0]);
|
|
||||||
Local<Object> sub_batch;
|
|
||||||
ROCKSDB_NAMESPACE::WriteBatch batch;
|
|
||||||
bool well_formed;
|
|
||||||
|
|
||||||
for (uint i = 0; i < sub_batches->Length(); i++) {
|
|
||||||
if (!sub_batches->Get(i)->IsObject()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
sub_batch = sub_batches->Get(i)->ToObject();
|
|
||||||
|
|
||||||
if (sub_batch->Has(String::NewSymbol("column_family"))) {
|
|
||||||
if (!has_key_for_array(sub_batch, "put") &&
|
|
||||||
!has_key_for_array(sub_batch, "delete")) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
well_formed = db_wrapper->AddToBatch(
|
|
||||||
batch, false,
|
|
||||||
Handle<Array>::Cast(sub_batch->Get(String::NewSymbol("put"))),
|
|
||||||
db_wrapper, *v8::String::Utf8Value(sub_batch->Get(
|
|
||||||
String::NewSymbol("column_family"))));
|
|
||||||
|
|
||||||
well_formed = db_wrapper->AddToBatch(
|
|
||||||
batch, true,
|
|
||||||
Handle<Array>::Cast(sub_batch->Get(String::NewSymbol("delete"))),
|
|
||||||
db_wrapper, *v8::String::Utf8Value(sub_batch->Get(
|
|
||||||
String::NewSymbol("column_family"))));
|
|
||||||
} else {
|
|
||||||
well_formed = db_wrapper->AddToBatch(
|
|
||||||
batch, false,
|
|
||||||
Handle<Array>::Cast(sub_batch->Get(String::NewSymbol("put"))));
|
|
||||||
well_formed = db_wrapper->AddToBatch(
|
|
||||||
batch, true,
|
|
||||||
Handle<Array>::Cast(sub_batch->Get(String::NewSymbol("delete"))));
|
|
||||||
|
|
||||||
if (!well_formed) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_wrapper->status_ =
|
|
||||||
db_wrapper->db_->Write(ROCKSDB_NAMESPACE::WriteOptions(), &batch);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CompactRangeDefault(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
ROCKSDB_NAMESPACE::Slice begin = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
ROCKSDB_NAMESPACE::Slice end = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
db_wrapper->status_ = db_wrapper->db_->CompactRange(&end, &begin);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CompactColumnFamily(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
ROCKSDB_NAMESPACE::Slice begin = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
ROCKSDB_NAMESPACE::Slice end = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
std::string cf = *v8::String::Utf8Value(args[2]->ToString());
|
|
||||||
db_wrapper->status_ = db_wrapper->db_->CompactRange(
|
|
||||||
db_wrapper->columnFamilies_[cf], &begin, &end);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CompactOptions(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[2]->IsObject()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
ROCKSDB_NAMESPACE::Slice begin = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
ROCKSDB_NAMESPACE::Slice end = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
Local<Object> options = args[2]->ToObject();
|
|
||||||
int target_level = -1, target_path_id = 0;
|
|
||||||
|
|
||||||
if (options->Has(String::NewSymbol("target_level")) &&
|
|
||||||
options->Get(String::NewSymbol("target_level"))->IsInt32()) {
|
|
||||||
target_level = (int)(options->Get(
|
|
||||||
String::NewSymbol("target_level"))->ToInt32()->Value());
|
|
||||||
|
|
||||||
if (options->Has(String::NewSymbol("target_path_id")) ||
|
|
||||||
options->Get(String::NewSymbol("target_path_id"))->IsInt32()) {
|
|
||||||
target_path_id = (int)(options->Get(
|
|
||||||
String::NewSymbol("target_path_id"))->ToInt32()->Value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_wrapper->status_ = db_wrapper->db_->CompactRange(
|
|
||||||
&begin, &end, true, target_level, target_path_id
|
|
||||||
);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CompactAll(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[2]->IsObject() || !args[3]->IsString()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
DBWrapper* db_wrapper = ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
ROCKSDB_NAMESPACE::Slice begin = *v8::String::Utf8Value(args[0]->ToString());
|
|
||||||
ROCKSDB_NAMESPACE::Slice end = *v8::String::Utf8Value(args[1]->ToString());
|
|
||||||
Local<Object> options = args[2]->ToObject();
|
|
||||||
std::string cf = *v8::String::Utf8Value(args[3]->ToString());
|
|
||||||
|
|
||||||
int target_level = -1, target_path_id = 0;
|
|
||||||
|
|
||||||
if (options->Has(String::NewSymbol("target_level")) &&
|
|
||||||
options->Get(String::NewSymbol("target_level"))->IsInt32()) {
|
|
||||||
target_level = (int)(options->Get(
|
|
||||||
String::NewSymbol("target_level"))->ToInt32()->Value());
|
|
||||||
|
|
||||||
if (options->Has(String::NewSymbol("target_path_id")) ||
|
|
||||||
options->Get(String::NewSymbol("target_path_id"))->IsInt32()) {
|
|
||||||
target_path_id = (int)(options->Get(
|
|
||||||
String::NewSymbol("target_path_id"))->ToInt32()->Value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_wrapper->status_ = db_wrapper->db_->CompactRange(
|
|
||||||
db_wrapper->columnFamilies_[cf], &begin, &end, true, target_level,
|
|
||||||
target_path_id);
|
|
||||||
|
|
||||||
return scope.Close(Boolean::New(db_wrapper->status_.ok()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::CompactRange(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
if (!args[0]->IsString() || !args[1]->IsString()) {
|
|
||||||
return scope.Close(Boolean::New(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(args.Length()) {
|
|
||||||
case 2:
|
|
||||||
return CompactRangeDefault(args);
|
|
||||||
case 3:
|
|
||||||
return args[2]->IsString() ? CompactColumnFamily(args) :
|
|
||||||
CompactOptions(args);
|
|
||||||
default:
|
|
||||||
return CompactAll(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Value> DBWrapper::Close(const Arguments& args) {
|
|
||||||
HandleScope scope;
|
|
||||||
|
|
||||||
delete ObjectWrap::Unwrap<DBWrapper>(args.This());
|
|
||||||
|
|
||||||
return scope.Close(Null());
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
||||||
#ifndef DBWRAPPER_H
|
|
||||||
#define DBWRAPPER_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <node.h>
|
|
||||||
|
|
||||||
#include "rocksdb/db.h"
|
|
||||||
#include "rocksdb/slice.h"
|
|
||||||
#include "rocksdb/options.h"
|
|
||||||
|
|
||||||
// Used to encapsulate a particular instance of an opened database.
|
|
||||||
//
|
|
||||||
// This object should not be used directly in C++; it exists solely to provide
|
|
||||||
// a mapping from a JavaScript object to a C++ code that can use the RocksDB
|
|
||||||
// API.
|
|
||||||
class DBWrapper : public node::ObjectWrap {
|
|
||||||
public:
|
|
||||||
static void Init(Handle<Object> exports);
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit DBWrapper();
|
|
||||||
~DBWrapper();
|
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
static bool HasFamilyNamed(std::string& name, DBWrapper* db);
|
|
||||||
static bool AddToBatch(ROCKSDB_NAMESPACE::WriteBatch& batch, bool del,
|
|
||||||
Handle<Array> array);
|
|
||||||
static bool AddToBatch(ROCKSDB_NAMESPACE::WriteBatch& batch, bool del,
|
|
||||||
Handle<Array> array, DBWrapper* db_wrapper,
|
|
||||||
std::string cf);
|
|
||||||
static Handle<Value> CompactRangeDefault(const v8::Arguments& args);
|
|
||||||
static Handle<Value> CompactColumnFamily(const Arguments& args);
|
|
||||||
static Handle<Value> CompactOptions(const Arguments& args);
|
|
||||||
static Handle<Value> CompactAll(const Arguments& args);
|
|
||||||
|
|
||||||
// C++ mappings of API methods
|
|
||||||
static Persistent<v8::Function> constructor;
|
|
||||||
static Handle<Value> Open(const Arguments& args);
|
|
||||||
static Handle<Value> New(const Arguments& args);
|
|
||||||
static Handle<Value> Get(const Arguments& args);
|
|
||||||
static Handle<Value> Put(const Arguments& args);
|
|
||||||
static Handle<Value> Delete(const Arguments& args);
|
|
||||||
static Handle<Value> Dump(const Arguments& args);
|
|
||||||
static Handle<Value> WriteBatch(const Arguments& args);
|
|
||||||
static Handle<Value> CreateColumnFamily(const Arguments& args);
|
|
||||||
static Handle<Value> CompactRange(const Arguments& args);
|
|
||||||
static Handle<Value> Close(const Arguments& args);
|
|
||||||
|
|
||||||
// Internal fields
|
|
||||||
ROCKSDB_NAMESPACE::Options options_;
|
|
||||||
ROCKSDB_NAMESPACE::Status status_;
|
|
||||||
ROCKSDB_NAMESPACE::DB* db_;
|
|
||||||
std::unordered_map<std::string, ROCKSDB_NAMESPACE::ColumnFamilyHandle*>
|
|
||||||
columnFamilies_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
node -e "RDB = require('./build/Release/rdb').DBWrapper; console.log('Loaded rocksdb in variable RDB'); repl = require('repl').start('> ');"
|
|
@ -1,14 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
||||||
#ifndef BUILDING_NODE_EXTENSION
|
|
||||||
#define BUILDING_NODE_EXTENSION
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <node.h>
|
|
||||||
#include <v8.h>
|
|
||||||
#include "db/_wrapper.h"
|
|
||||||
|
|
||||||
void InitAll(Handle<Object> exports) {
|
|
||||||
DBWrapper::Init(exports);
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_MODULE(rdb, InitAll)
|
|
@ -1,125 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
|
||||||
assert = require('assert')
|
|
||||||
RDB = require('./build/Release/rdb').DBWrapper
|
|
||||||
exec = require('child_process').exec
|
|
||||||
util = require('util')
|
|
||||||
|
|
||||||
DB_NAME = '/tmp/rocksdbtest-' + process.getuid()
|
|
||||||
|
|
||||||
a = RDB()
|
|
||||||
assert.equal(a.open(DB_NAME, ['b']), false)
|
|
||||||
|
|
||||||
exec(
|
|
||||||
util.format(
|
|
||||||
"node -e \"RDB = require('./build/Release/rdb').DBWrapper; \
|
|
||||||
a = RDB('%s'); a.createColumnFamily('b')\"",
|
|
||||||
DB_NAME
|
|
||||||
).exitCode, null
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
exec(
|
|
||||||
util.format(
|
|
||||||
"node -e \"RDB = require('./build/Release/rdb').DBWrapper; \
|
|
||||||
a = RDB('%s', ['b'])\"",
|
|
||||||
DB_NAME
|
|
||||||
).exitCode, null
|
|
||||||
)
|
|
||||||
|
|
||||||
exec('rm -rf ' + DB_NAME)
|
|
||||||
|
|
||||||
a = RDB()
|
|
||||||
assert.equal(a.open(DB_NAME, ['a']), false)
|
|
||||||
assert(a.open(DB_NAME), true)
|
|
||||||
assert(a.createColumnFamily('temp'))
|
|
||||||
|
|
||||||
b = RDB()
|
|
||||||
assert.equal(b.open(DB_NAME), false)
|
|
||||||
|
|
||||||
exec('rm -rf ' + DB_NAME)
|
|
||||||
|
|
||||||
DB_NAME += 'b'
|
|
||||||
|
|
||||||
a = RDB()
|
|
||||||
assert(a.open(DB_NAME))
|
|
||||||
assert.equal(a.constructor.name, 'DBWrapper')
|
|
||||||
assert.equal(a.createColumnFamily(), false)
|
|
||||||
assert.equal(a.createColumnFamily(1), false)
|
|
||||||
assert.equal(a.createColumnFamily(['']), false)
|
|
||||||
assert(a.createColumnFamily('b'))
|
|
||||||
assert.equal(a.createColumnFamily('b'), false)
|
|
||||||
|
|
||||||
// Get and Put
|
|
||||||
assert.equal(a.get(1), null)
|
|
||||||
assert.equal(a.get(['a']), null)
|
|
||||||
assert.equal(a.get('a', 1), null)
|
|
||||||
assert.equal(a.get(1, 'a'), null)
|
|
||||||
assert.equal(a.get(1, 1), null)
|
|
||||||
|
|
||||||
assert.equal(a.put(1), false)
|
|
||||||
assert.equal(a.put(['a']), false)
|
|
||||||
assert.equal(a.put('a', 1), false)
|
|
||||||
assert.equal(a.put(1, 'a'), false)
|
|
||||||
assert.equal(a.put(1, 1), false)
|
|
||||||
assert.equal(a.put('a', 'a', 1), false)
|
|
||||||
assert.equal(a.put('a', 1, 'a'), false)
|
|
||||||
assert.equal(a.put(1, 'a', 'a'), false)
|
|
||||||
assert.equal(a.put('a', 1, 1), false)
|
|
||||||
assert.equal(a.put(1, 'a', 1), false)
|
|
||||||
assert.equal(a.put(1, 1, 'a'), false)
|
|
||||||
assert.equal(a.put(1, 1, 1), false)
|
|
||||||
|
|
||||||
|
|
||||||
assert.equal(a.get(), null)
|
|
||||||
assert.equal(a.get('a'), null)
|
|
||||||
assert.equal(a.get('a', 'c'), null)
|
|
||||||
assert.equal(a.put(), false)
|
|
||||||
assert.equal(a.put('a'), false)
|
|
||||||
assert.equal(a.get('a', 'b', 'c'), null)
|
|
||||||
|
|
||||||
assert(a.put('a', 'axe'))
|
|
||||||
assert(a.put('a', 'first'))
|
|
||||||
assert.equal(a.get('a'), 'first')
|
|
||||||
assert.equal(a.get('a', 'b'), null)
|
|
||||||
assert.equal(a.get('a', 'c'), null)
|
|
||||||
|
|
||||||
assert(a.put('a', 'apple', 'b'))
|
|
||||||
assert.equal(a.get('a', 'b'), 'apple')
|
|
||||||
assert.equal(a.get('a'), 'first')
|
|
||||||
assert(a.put('b', 'butter', 'b'), 'butter')
|
|
||||||
assert(a.put('b', 'banana', 'b'))
|
|
||||||
assert.equal(a.get('b', 'b'), 'banana')
|
|
||||||
assert.equal(a.get('b'), null)
|
|
||||||
assert.equal(a.get('b', 'c'), null)
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
assert.equal(a.delete(1), false)
|
|
||||||
assert.equal(a.delete('a', 1), false)
|
|
||||||
assert.equal(a.delete(1, 'a'), false)
|
|
||||||
assert.equal(a.delete(1, 1), false)
|
|
||||||
|
|
||||||
assert.equal(a.delete('b'), true)
|
|
||||||
assert(a.delete('a'))
|
|
||||||
assert.equal(a.get('a'), null)
|
|
||||||
assert.equal(a.get('a', 'b'), 'apple')
|
|
||||||
assert.equal(a.delete('c', 'c'), false)
|
|
||||||
assert.equal(a.delete('c', 'b'), true)
|
|
||||||
assert(a.delete('b', 'b'))
|
|
||||||
assert.equal(a.get('b', 'b'), null)
|
|
||||||
|
|
||||||
// Dump
|
|
||||||
console.log("MARKER 1")
|
|
||||||
assert(a.dump())
|
|
||||||
console.log("Should be no output between 'MARKER 1' and here\n")
|
|
||||||
console.log('Next line should be "a" => "apple"')
|
|
||||||
assert(a.dump('b'))
|
|
||||||
|
|
||||||
console.log("\nMARKER 2")
|
|
||||||
assert.equal(a.dump('c'), false)
|
|
||||||
console.log("Should be no output between 'MARKER 2' and here\n")
|
|
||||||
|
|
||||||
// WriteBatch
|
|
||||||
|
|
||||||
|
|
||||||
// Clean up test database
|
|
||||||
exec('rm -rf ' + DB_NAME)
|
|
Loading…
Reference in New Issue
Block a user