[Pkg-javascript-commits] [node-leveldown] 05/492: buffers, encoding, persistent handles
Andrew Kelley
andrewrk-guest at moszumanska.debian.org
Sun Jul 6 17:13:38 UTC 2014
This is an automated email from the git hooks/post-receive script.
andrewrk-guest pushed a commit to annotated tag rocksdb-0.10.1
in repository node-leveldown.
commit 9a1271cd0619008a883fbf50215c7e12ac1ca22f
Author: Rod Vagg <rod at vagg.org>
Date: Sat Jul 14 22:06:05 2012 +1000
buffers, encoding, persistent handles
---
lib/levelup.js | 77 ++++++++++++++++++++++++++-----
src/async.cc | 74 +++++++-----------------------
src/async.h | 128 ++++++++++++++++++++++++++++++++++++++++++++--------
src/batch.cc | 12 +++--
src/batch.h | 25 ++++++++--
src/database.cc | 109 ++++++++++++++++++++++++--------------------
src/database.h | 12 ++---
src/levelup.cc | 3 ++
src/levelup.h | 1 +
test/common.js | 51 ++++++++++++++++++++-
test/simple-test.js | 122 +++++++++++++++++++++++++++++++++++++++----------
11 files changed, 439 insertions(+), 175 deletions(-)
diff --git a/lib/levelup.js b/lib/levelup.js
index 9c2bfdf..65b13b7 100644
--- a/lib/levelup.js
+++ b/lib/levelup.js
@@ -4,12 +4,47 @@ var bridge = require('../build/Release/levelup')
, defaultOptions = {
createIfMissing : false
, errorIfExists : false
+ , encoding : 'utf8'
}
, toString = function () {
return "LevelUPDatabase"
}
+ , encodingOpts = (function (enc) {
+ var eo = {}
+ enc.forEach(function (e) { eo[e] = { encoding: e } })
+ return eo
+ }('hex utf8 utf-8 ascii binary base64 ucs2 ucs-2 utf16le utf-16le'.split(' ')))
+
+ , getOptions = function (options_, defaultEncoding) {
+ var options
+ if (typeof options_ == 'string')
+ options = encodingOpts[options_] || encodingOpts[defaultOptions.encoding]
+ else if (typeof options_ == 'object') {
+ options = options_
+ if (!options.encoding
+ || !(options.keyEncoding
+ && options.valueEncoding
+ && encodingOpts[options.keyEncoding]
+ && encodingOpts[options.valueEncoding])
+ || !encodingOpts[options.encoding])
+ options.encoding = defaultOptions.encoding
+ } else
+ options = encodingOpts[defaultEncoding] || encodingOpts[defaultOptions.encoding]
+ return options
+ }
+
+ , getCallback = function (options_, callback_) {
+ if (typeof options_ == 'function')
+ return options_
+ return callback_
+ }
+
+ , toBuffer = function (data, encoding) {
+ return Buffer.isBuffer(data) ? data : new Buffer('' + data, encoding)
+ }
+
, Database = {
open: function (callback) {
var options = {}
@@ -49,61 +84,79 @@ var bridge = require('../build/Release/levelup')
return !!this.db
}
- , get: function (key, callback) {
+ , get: function (key, options_, callback_) {
+ var callback = getCallback(options_, callback_)
+ , options
if (this.isOpen()) {
- this.db.get(key, function (err, value) {
+ options = getOptions(options_, this.encoding)
+ key = toBuffer(key, options.keyEncoding || options.encoding)
+ this.db.get(key, options, function (err, value) {
if (err) {
err = new errors.NotFoundError('Key not found in database [' + key + ']')
if (callback)
return callback(err)
throw err
}
- callback && callback(null, value)
+ callback && callback(null, value.toString(options.valueEncoding || options.encoding), key)
})
} else
callback(new errors.ReadError('Database has not been opened'))
}
- , put: function (key, value, callback) {
+ , put: function (key, value, options_, callback_) {
+ var callback = getCallback(options_, callback_)
+ , options
if (this.isOpen()) {
- this.db.put(key, value, function (err) {
+ options = getOptions(options_, this.encoding)
+ key = toBuffer(key, options.keyEncoding || options.encoding)
+ value = toBuffer(value, options.valueEncoding || options.encoding)
+ this.db.put(key, value, options, function (err) {
if (err) {
err = new errors.WriteError(err)
if (callback)
return callback(err)
throw err
}
- callback && callback()
+ callback && callback(null, key, value)
})
} else
callback(new errors.ReadError('Database has not been opened'))
}
- , del: function (key, callback) {
+ , del: function (key, options_, callback_) {
+ var callback = getCallback(options_, callback_)
+ , options
if (this.isOpen()) {
- this.db.del(key, function (err) {
+ options = getOptions(options_, this.encoding)
+ key = toBuffer(key, options.keyEncoding || options.encoding)
+ this.db.del(key, options, function (err) {
if (err) {
err = new errors.WriteError(err)
if (callback)
return callback(err)
throw err
}
- callback && callback()
+ callback && callback(null, key)
})
} else
callback(new errors.ReadError('Database has not been opened'))
}
- , batch: function (arr, callback) {
+ , batch: function (arr, options_, callback_) {
+ var callback = getCallback(options_, callback_)
+ , options
if (this.isOpen()) {
- this.db.batch(arr, function (err) {
+ options = getOptions(options_, this.encoding)
+ this.db.batch(arr, options, function (err) {
if (err) {
err = new errors.WriteError(err)
if (callback)
return callback(err)
throw err
}
- callback && callback()
+ // reference to 'arr' important to keep from being garbage collected
+ // we don't keep a Persistent<T> reference in the bridge
+ callback && callback(null, arr)
})
} else
callback(new errors.ReadError('Database has not been opened'))
diff --git a/src/async.cc b/src/async.cc
index c50c5e5..6f36f2d 100644
--- a/src/async.cc
+++ b/src/async.cc
@@ -1,5 +1,6 @@
#include <cstdlib>
#include <node.h>
+#include <node_buffer.h>
#include <iostream>
#include <pthread.h>
@@ -40,32 +41,12 @@ void AsyncWorker::HandleErrorCallback () {
/** OPEN WORKER **/
-OpenWorker::OpenWorker (Database* database, Persistent<Function> callback, string location, bool createIfMissing, bool errorIfExists) {
- request.data = this;
- this->database = database;
- this->location = location;
- this->callback = callback;
- options = new Options();
- options->create_if_missing = createIfMissing;
- options->error_if_exists = errorIfExists;
-}
-
-OpenWorker::~OpenWorker () {
- delete options;
-}
-
void OpenWorker::Execute() {
status = database->OpenDatabase(options, location);
}
/** CLOSE WORKER **/
-CloseWorker::CloseWorker (Database* database, Persistent<Function> callback) {
- request.data = this;
- this->database = database;
- this->callback = callback;
-}
-
void CloseWorker::Execute() {
database->CloseDatabase();
}
@@ -76,63 +57,48 @@ void CloseWorker::WorkComplete () {
callback.Dispose();
}
-/** WRITE WORKER **/
+/** IO WORKER (abstract) **/
-WriteWorker::WriteWorker (Database* database, Persistent<Function> callback, string key, string value, bool sync) {
- request.data = this;
- this->database = database;
- this->callback = callback;
- this->key = key;
- this->value = value;
- options = new WriteOptions();
- options->sync = sync;
+void IOWorker::WorkComplete() {
+ AsyncWorker::WorkComplete();
+ keyPtr.Dispose();
}
+/** WRITE WORKER **/
+
WriteWorker::~WriteWorker () {
delete options;
}
void WriteWorker::Execute() {
- status = database->WriteToDatabase(options, key, value);
+ status = database->PutToDatabase(options, key, value);
}
-/** READ WORKER **/
-
-ReadWorker::ReadWorker (Database* database, Persistent<Function> callback, string key) {
- request.data = this;
- this->database = database;
- this->callback = callback;
- this->key = key;
- options = new ReadOptions();
+void WriteWorker::WorkComplete() {
+ IOWorker::WorkComplete();
+ valuePtr.Dispose();
}
+/** READ WORKER **/
+
ReadWorker::~ReadWorker () {
delete options;
}
void ReadWorker::Execute () {
- status = database->ReadFromDatabase(options, key, value);
+ status = database->GetFromDatabase(options, key, value);
}
void ReadWorker::HandleOKCallback () {
Local<Value> argv[] = {
Local<Value>::New(Null())
- , Local<Value>::New(String::New(value.c_str()))
+ , Local<Value>::New(Buffer::New((char*)value.data(), value.size())->handle_)
};
runCallback(callback, argv, 2);
}
/** DELETE WORKER **/
-DeleteWorker::DeleteWorker (Database* database, Persistent<Function> callback, string key, bool sync) {
- request.data = this;
- this->database = database;
- this->callback = callback;
- this->key = key;
- options = new WriteOptions();
- options->sync = sync;
-}
-
DeleteWorker::~DeleteWorker () {
delete options;
}
@@ -143,15 +109,6 @@ void DeleteWorker::Execute() {
/** BATCH WORKER **/
-BatchWorker::BatchWorker (Database* database, Persistent<Function> callback, vector<BatchOp*> operations, bool sync) {
- request.data = this;
- this->database = database;
- this->callback = callback;
- this->operations = operations;
- options = new WriteOptions();
- options->sync = sync;
-}
-
BatchWorker::~BatchWorker () {
for (unsigned int i = 0; i < operations.size(); i++)
delete operations[i];
@@ -170,6 +127,7 @@ void BatchWorker::Execute() {
void runCallback (Persistent<Function> callback, Local<Value> argv[], int length) {
TryCatch try_catch;
+
callback->Call(Context::GetCurrent()->Global(), length, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
diff --git a/src/async.h b/src/async.h
index ac81ca1..1537723 100644
--- a/src/async.h
+++ b/src/async.h
@@ -13,11 +13,19 @@ using namespace leveldb;
class AsyncWorker {
public:
+ AsyncWorker (
+ Database* database
+ , Persistent<Function> callback
+ ) : database(database)
+ , callback(callback) {
+ request.data = this;
+ };
+
uv_work_t request;
Database* database;
Persistent<Function> callback;
Status status;
- void WorkComplete ();
+ virtual void WorkComplete ();
virtual void Execute () {};
protected:
@@ -27,8 +35,23 @@ protected:
class OpenWorker : public AsyncWorker {
public:
- OpenWorker (Database* database, Persistent<Function> callback, string location, bool createIfMissing, bool errorIfExists);
- ~OpenWorker ();
+ OpenWorker (
+ Database* database
+ , Persistent<Function> callback
+ , string location
+ , bool createIfMissing
+ , bool errorIfExists
+ ) : AsyncWorker(database, callback)
+ , location(location)
+ {
+ options = new Options();
+ options->create_if_missing = createIfMissing;
+ options->error_if_exists = errorIfExists;
+ };
+
+ ~OpenWorker () {
+ delete options;
+ }
string location;
Options* options;
@@ -37,7 +60,11 @@ public:
class CloseWorker : public AsyncWorker {
public:
- CloseWorker (Database* database, Persistent<Function> callback);
+ CloseWorker (
+ Database* database
+ , Persistent<Function> callback
+ ) : AsyncWorker(database, callback)
+ {};
virtual void Execute ();
@@ -47,23 +74,35 @@ private:
class IOWorker : public AsyncWorker {
public:
- string key;
- string value;
-};
+ IOWorker (
+ Database* database
+ , Persistent<Function> callback
+ , Slice key
+ , Persistent<Object> keyPtr
+ ) : AsyncWorker(database, callback)
+ , key(key)
+ , keyPtr(keyPtr)
+ {};
-class WriteWorker : public IOWorker {
-public:
- WriteWorker (Database* database, Persistent<Function> callback, string key, string value, bool sync);
- WriteWorker () {};
- ~WriteWorker ();
+ virtual void WorkComplete ();
- WriteOptions* options;
- virtual void Execute ();
+protected:
+ Slice key;
+ Persistent<Object> keyPtr;
};
class ReadWorker : public IOWorker {
public:
- ReadWorker (Database* database, Persistent<Function> callback, string key);
+ ReadWorker(
+ Database* database
+ , Persistent<Function> callback
+ , Slice key
+ , Persistent<Object> keyPtr
+ ) : IOWorker(database, callback, key, keyPtr)
+ {
+ options = new ReadOptions();
+ };
+
~ReadWorker ();
ReadOptions* options;
@@ -71,19 +110,72 @@ public:
protected:
virtual void HandleOKCallback ();
+
+private:
+ string value;
};
-class DeleteWorker : public WriteWorker {
+class DeleteWorker : public IOWorker {
public:
- DeleteWorker (Database* database, Persistent<Function> callback, string key, bool sync);
+ DeleteWorker(
+ Database* database
+ , Persistent<Function> callback
+ , Slice key
+ , bool sync
+ , Persistent<Object> keyPtr
+ ) : IOWorker(database, callback, key, keyPtr)
+ {
+ options = new WriteOptions();
+ options->sync = sync;
+ };
+
~DeleteWorker ();
virtual void Execute ();
+
+protected:
+ WriteOptions* options;
+};
+
+class WriteWorker : public DeleteWorker {
+public:
+ WriteWorker (
+ Database* database
+ , Persistent<Function> callback
+ , Slice key
+ , Slice value
+ , bool sync
+ , Persistent<Object> keyPtr
+ , Persistent<Object> valuePtr
+ ) : DeleteWorker(database, callback, key, sync, keyPtr)
+ , value(value)
+ , valuePtr(valuePtr)
+ {};
+
+ ~WriteWorker ();
+
+ virtual void Execute ();
+ virtual void WorkComplete ();
+
+private:
+ Slice value;
+ Persistent<Object> valuePtr;
};
class BatchWorker : public AsyncWorker {
public:
- BatchWorker (Database* database, Persistent<Function> callback, vector<BatchOp*> operations, bool sync);
+ BatchWorker(
+ Database* database
+ , Persistent<Function> callback
+ , vector<BatchOp*> operations
+ , bool sync
+ ) : AsyncWorker(database, callback)
+ , operations(operations)
+ {
+ options = new WriteOptions();
+ options->sync = sync;
+ };
+
~BatchWorker ();
virtual void Execute ();
diff --git a/src/batch.cc b/src/batch.cc
index 8ed7707..ef2309f 100644
--- a/src/batch.cc
+++ b/src/batch.cc
@@ -7,16 +7,20 @@
using namespace std;
-BatchDelete::BatchDelete (string key) {
- this->key = key;
+BatchDelete::~BatchDelete () {
+ if (keyPtr != NULL)
+ delete keyPtr;
}
void BatchDelete::Execute (WriteBatch* batch) {
batch->Delete(key);
}
-BatchWrite::BatchWrite (string key, string value) : BatchDelete (key) {
- this->value = value;
+BatchWrite::~BatchWrite () {
+ if (keyPtr != NULL)
+ delete keyPtr;
+ if (valuePtr != NULL)
+ delete valuePtr;
}
void BatchWrite::Execute (WriteBatch* batch) {
diff --git a/src/batch.h b/src/batch.h
index 0c0b2c4..eb1cd81 100644
--- a/src/batch.h
+++ b/src/batch.h
@@ -14,20 +14,37 @@ public:
class BatchDelete : public BatchOp {
public:
- BatchDelete (string key);
+ BatchDelete (
+ Slice key
+ , string* keyPtr
+ ) : key(key)
+ , keyPtr(keyPtr)
+ {};
+ ~BatchDelete ();
virtual void Execute (WriteBatch* batch);
protected:
- string key;
+ Slice key;
+ string* keyPtr;
};
class BatchWrite : public BatchDelete {
public:
- BatchWrite (string key, string value);
+ BatchWrite (
+ Slice key
+ , string* keyPtr
+ , Slice value
+ , string* valuePtr
+ ) : BatchDelete(key, keyPtr)
+ , value(value)
+ , valuePtr(valuePtr)
+ {};
+ ~BatchWrite ();
virtual void Execute (WriteBatch* batch);
private:
- string value;
+ Slice value;
+ string* valuePtr;
};
#endif
\ No newline at end of file
diff --git a/src/database.cc b/src/database.cc
index 267924f..8ba9571 100644
--- a/src/database.cc
+++ b/src/database.cc
@@ -1,6 +1,7 @@
#include <cstdlib>
#include <vector>
#include <node.h>
+#include <node_buffer.h>
#include <iostream>
#include <pthread.h>
@@ -40,15 +41,15 @@ Status Database::OpenDatabase (Options* options, string location) {
return DB::Open(*options, location, &db);
}
-Status Database::WriteToDatabase (WriteOptions* options, string key, string value) {
+Status Database::PutToDatabase (WriteOptions* options, Slice key, Slice value) {
return db->Put(*options, key, value);
}
-Status Database::ReadFromDatabase (ReadOptions* options, string key, string& value) {
+Status Database::GetFromDatabase (ReadOptions* options, Slice key, string& value) {
return db->Get(*options, key, &value);
}
-Status Database::DeleteFromDatabase (WriteOptions* options, string key) {
+Status Database::DeleteFromDatabase (WriteOptions* options, Slice key) {
return db->Delete(*options, key);
}
@@ -69,8 +70,8 @@ void Database::Init () {
tpl->InstanceTemplate()->SetInternalFieldCount(5);
tpl->PrototypeTemplate()->Set(String::NewSymbol("open") , FunctionTemplate::New(Open)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("close") , FunctionTemplate::New(Close)->GetFunction());
- tpl->PrototypeTemplate()->Set(String::NewSymbol("put") , FunctionTemplate::New(Write)->GetFunction());
- tpl->PrototypeTemplate()->Set(String::NewSymbol("get") , FunctionTemplate::New(Read)->GetFunction());
+ tpl->PrototypeTemplate()->Set(String::NewSymbol("put") , FunctionTemplate::New(Put)->GetFunction());
+ tpl->PrototypeTemplate()->Set(String::NewSymbol("get") , FunctionTemplate::New(Get)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("del") , FunctionTemplate::New(Delete)->GetFunction());
tpl->PrototypeTemplate()->Set(String::NewSymbol("batch") , FunctionTemplate::New(Batch)->GetFunction());
constructor = Persistent<Function>::New(tpl->GetFunction());
@@ -100,9 +101,7 @@ Handle<Value> Database::Open (const Arguments& args) {
Database* database = ObjectWrap::Unwrap<Database>(args.This());
String::Utf8Value location(args[0]->ToString());
Local<Object> optionsObj = Local<Object>::Cast(args[1]);
- Persistent<Function> callback;
- if (args.Length() > 1)
- callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
+ Persistent<Function> callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
OpenWorker* worker = new OpenWorker(
database
@@ -130,46 +129,48 @@ Handle<Value> Database::Close (const Arguments& args) {
return Undefined();
}
-Handle<Value> Database::Write (const Arguments& args) {
+Handle<Value> Database::Put (const Arguments& args) {
HandleScope scope;
Database* database = ObjectWrap::Unwrap<Database>(args.This());
- String::Utf8Value key(args[0]->ToString());
- String::Utf8Value value(args[1]->ToString());
- Persistent<Function> callback;
- if (args.Length() > 2)
- callback = Persistent<Function>::New(Local<Function>::Cast(args[args.Length() > 3 ? 3 : 2]));
- bool sync = false;
- if (args.Length() > 3) {
- Local<Object> optionsObj = Local<Object>::Cast(args[2]);
- sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
- }
+
+ Local<Object> keyBuffer = args[0]->ToObject();
+ Slice key(Buffer::Data(keyBuffer), Buffer::Length(keyBuffer));
+ Local<Object> valueBuffer = args[1]->ToObject();
+ Slice value(Buffer::Data(valueBuffer), Buffer::Length(valueBuffer));
+
+ Local<Object> optionsObj = Local<Object>::Cast(args[2]);
+ bool sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
+ Persistent<Function> callback = Persistent<Function>::New(Local<Function>::Cast(args[3]));
WriteWorker* worker = new WriteWorker(
database
, callback
- , *key
- , *value
+ , key
+ , value
, sync
+ , Persistent<Object>::New(keyBuffer)
+ , Persistent<Object>::New(valueBuffer)
);
AsyncQueueWorker(worker);
return Undefined();
}
-Handle<Value> Database::Read (const Arguments& args) {
+Handle<Value> Database::Get (const Arguments& args) {
HandleScope scope;
Database* database = ObjectWrap::Unwrap<Database>(args.This());
- String::Utf8Value key(args[0]->ToString());
- Persistent<Function> callback;
- if (args.Length() > 1)
- callback = Persistent<Function>::New(Local<Function>::Cast(args[args.Length() > 2 ? 2 : 1]));
+ Local<Object> keyBuffer = args[0]->ToObject();
+ Slice key(Buffer::Data(keyBuffer), Buffer::Length(keyBuffer));
+ //Local<Object> optionsObj = Local<Object>::Cast(args[1]);
+ Persistent<Function> callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
ReadWorker* worker = new ReadWorker(
database
, callback
- , *key
+ , key
+ , Persistent<Object>::New(keyBuffer)
);
AsyncQueueWorker(worker);
@@ -180,21 +181,18 @@ Handle<Value> Database::Delete (const Arguments& args) {
HandleScope scope;
Database* database = ObjectWrap::Unwrap<Database>(args.This());
- String::Utf8Value key(args[0]->ToString());
- Persistent<Function> callback;
- if (args.Length() > 1)
- callback = Persistent<Function>::New(Local<Function>::Cast(args[args.Length() > 2 ? 2 : 1]));
- bool sync = false;
- if (args.Length() > 2) {
- Local<Object> optionsObj = Local<Object>::Cast(args[1]);
- sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
- }
+ Local<Object> keyBuffer = args[0]->ToObject();
+ Slice key(Buffer::Data(keyBuffer), Buffer::Length(keyBuffer));
+ Local<Object> optionsObj = Local<Object>::Cast(args[1]);
+ bool sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
+ Persistent<Function> callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
DeleteWorker* worker = new DeleteWorker(
database
, callback
- , *key
+ , key
, sync
+ , Persistent<Object>::New(keyBuffer)
);
AsyncQueueWorker(worker);
@@ -206,27 +204,40 @@ Handle<Value> Database::Batch (const Arguments& args) {
Database* database = ObjectWrap::Unwrap<Database>(args.This());
Local<Array> array = Local<Array>::Cast(args[0]);
- Persistent<Function> callback;
- if (args.Length() > 1)
- callback = Persistent<Function>::New(Local<Function>::Cast(args[args.Length() > 2 ? 2 : 1]));
- bool sync = false;
- if (args.Length() > 2) {
- Local<Object> optionsObj = Local<Object>::Cast(args[1]);
- sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
- }
+ Local<Object> optionsObj = Local<Object>::Cast(args[1]);
+ bool sync = optionsObj->Has(option_sync) && optionsObj->Get(option_sync)->BooleanValue();
+ Persistent<Function> callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
vector<BatchOp*> operations;
for (unsigned int i = 0; i < array->Length(); i++) {
Local<Object> obj = Local<Object>::Cast(array->Get(i));
if (!obj->Has(str_type) || !obj->Has(str_key))
continue;
- String::Utf8Value key(obj->Get(str_key)->ToString());
+
+ Local<Object> keyObj = obj->Get(str_key)->ToObject();
+ string* keyStr = NULL;
+ Slice key;
+ if (Buffer::HasInstance(keyObj))
+ key = Slice(Buffer::Data(keyObj), Buffer::Length(keyObj));
+ else {
+ keyStr = new string(ToCString(String::Utf8Value(keyObj->ToString())));
+ key = *keyStr;
+ }
+
if (obj->Get(str_type)->StrictEquals(str_del)) {
- operations.push_back(new BatchDelete(*key));
+ operations.push_back(new BatchDelete(key, keyStr));
} else if (obj->Get(str_type)->StrictEquals(str_put)) {
if (obj->Has(str_value)) {
- String::Utf8Value value(obj->Get(str_value)->ToString());
- operations.push_back(new BatchWrite(*key, *value));
+ Local<Object> valueObj = obj->Get(str_value)->ToObject();
+ string* valueStr = NULL;
+ Slice value;
+ if (Buffer::HasInstance(valueObj))
+ value = Slice(Buffer::Data(valueObj), Buffer::Length(valueObj));
+ else {
+ valueStr = new string(ToCString(String::Utf8Value(valueObj->ToString())));
+ value = *valueStr;
+ }
+ operations.push_back(new BatchWrite(key, keyStr, value, valueStr));
}
}
}
diff --git a/src/database.h b/src/database.h
index 7438b9f..4a3f8a6 100644
--- a/src/database.h
+++ b/src/database.h
@@ -23,11 +23,11 @@ class Database : public node::ObjectWrap {
static v8::Handle<v8::Value> NewInstance (const v8::Arguments& args);
Status OpenDatabase (Options* options, string location);
- Status WriteToDatabase (WriteOptions* options, string key, string value);
- Status ReadFromDatabase (ReadOptions* options, string key, string& value);
- Status DeleteFromDatabase (WriteOptions* options, string key);
+ Status PutToDatabase (WriteOptions* options, Slice key, Slice value);
+ Status GetFromDatabase (ReadOptions* options, Slice key, string& value);
+ Status DeleteFromDatabase (WriteOptions* options, Slice key);
Status WriteBatchToDatabase (WriteOptions* options, WriteBatch* batch);
- void CloseDatabase ();
+ void CloseDatabase ();
private:
Database ();
@@ -40,9 +40,9 @@ class Database : public node::ObjectWrap {
LU_V8_METHOD( New )
LU_V8_METHOD( Open )
LU_V8_METHOD( Close )
- LU_V8_METHOD( Write )
+ LU_V8_METHOD( Put )
LU_V8_METHOD( Delete )
- LU_V8_METHOD( Read )
+ LU_V8_METHOD( Get )
LU_V8_METHOD( Batch )
};
diff --git a/src/levelup.cc b/src/levelup.cc
index f3a73b2..d96be0f 100644
--- a/src/levelup.cc
+++ b/src/levelup.cc
@@ -18,4 +18,7 @@ NODE_MODULE(levelup, Init)
// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
+}
+const char* ToCString(const v8::String::AsciiValue& value) {
+ return *value ? *value : "<string conversion failed>";
}
\ No newline at end of file
diff --git a/src/levelup.h b/src/levelup.h
index 16f460b..948957d 100644
--- a/src/levelup.h
+++ b/src/levelup.h
@@ -8,5 +8,6 @@
static Persistent<String> option_ ## key = Persistent<String>::New(String::New(#key));
const char* ToCString(const v8::String::Utf8Value& value);
+const char* ToCString(const v8::String::AsciiValue& value);
#endif
\ No newline at end of file
diff --git a/test/common.js b/test/common.js
index 0f6e235..f68ec48 100644
--- a/test/common.js
+++ b/test/common.js
@@ -1,4 +1,10 @@
-var ba = require('buster').assertions
+var ba = require('buster').assertions
+ , async = require('async')
+ , rimraf = require('rimraf')
+ , fs = require('fs')
+ , path = require('path')
+ , levelup = require('../lib/levelup.js')
+ , child_process = require('child_process')
ba.add('isInstanceOf', {
assert: function (actual, expected) {
@@ -21,3 +27,46 @@ ba.add('isUndefined', {
, assertMessage: '${0} expected to be undefined'
, refuteMessage: '${0} expected not to be undefined'
})
+
+global.openTestDatabase = function (callback) {
+ var db = levelup.createDatabase(
+ this.cleanupDirs[0] = '/tmp/levelup_test_db'
+ , {
+ createIfMissing: true
+ , errorIfExists: true
+ }
+ )
+ this.closeableDatabases.push(db)
+ db.open(function (err) {
+ refute(err)
+ callback(db)
+ })
+}
+
+global.cleanUp = function (closeableDatabases, cleanupDirs, callback) {
+ async.forEach(
+ closeableDatabases
+ , function (db, callback) {
+ db.close(callback)
+ }
+ , function () {
+ async.forEach(cleanupDirs, rimraf, callback)
+ }.bind(this)
+ )
+}
+
+global.loadBinaryTestData = function (callback) {
+ fs.readFile(path.join(__dirname, 'testdata.bin'), callback)
+}
+
+global.binaryTestDataMD5Sum = '920725ef1a3b32af40ccd0b78f4a62fd'
+
+global.checkBinaryTestData = function (testData, callback) {
+ fs.writeFile('__tst.dat', testData, function (err) {
+ child_process.exec('md5sum __tst.dat', function (error, stdout, stderr) {
+ var md5Sum = stdout.split(' ')[0]
+ assert.equals(md5Sum, global.binaryTestDataMD5Sum)
+ rimraf('__tst.dat', callback)
+ })
+ })
+}
\ No newline at end of file
diff --git a/test/simple-test.js b/test/simple-test.js
index f960e03..6d84994 100644
--- a/test/simple-test.js
+++ b/test/simple-test.js
@@ -1,3 +1,5 @@
+/*global cleanUp:true, openTestDatabase:true*/
+
var buster = require('buster')
, assert = buster.assert
, levelup = require('../lib/levelup.js')
@@ -10,32 +12,11 @@ buster.testCase('Basic API', {
'setUp': function () {
this.cleanupDirs = []
this.closeableDatabases = []
- this.openTestDatabase = function (callback) {
- var db = levelup.createDatabase(
- this.cleanupDirs[0] = '/tmp/levelup_test_db'
- , {
- createIfMissing: true
- , errorIfExists: true
- }
- )
- this.closeableDatabases.push(db)
- db.open(function (err) {
- refute(err)
- callback(db)
- })
- }.bind(this)
+ this.openTestDatabase = openTestDatabase.bind(this)
}
, 'tearDown': function (done) {
- async.forEach(
- this.closeableDatabases
- , function (db, callback) {
- db.close(callback)
- }
- , function () {
- async.forEach(this.cleanupDirs, rimraf, done)
- }.bind(this)
- )
+ cleanUp(this.closeableDatabases, this.cleanupDirs, done)
}
, 'createDatabase()': function () {
@@ -354,5 +335,100 @@ buster.testCase('Basic API', {
)
})
}
+
+ , 'batch() with can manipulate data from put()': function (done) {
+ // checks encoding and whatnot
+ this.openTestDatabase(function (db) {
+ async.series(
+ [
+ db.put.bind(db, '1', 'one')
+ , db.put.bind(db, '2', 'two')
+ , db.put.bind(db, '3', 'three')
+ , function (callback) {
+ db.batch(
+ [
+ { type: 'put', key: 'foo', value: 'afoovalue' }
+ , { type: 'del', key: '1' }
+ , { type: 'put', key: 'bar', value: 'abarvalue' }
+ , { type: 'del', key: 'foo' }
+ , { type: 'put', key: 'baz', value: 'abazvalue' }
+ ]
+ , callback
+ )
+ }
+ , function (callback) {
+ // these should exist
+ async.forEach(
+ ['2', '3', 'bar', 'baz']
+ , function (key, callback) {
+ db.get(key, function (err, value) {
+ refute(err)
+ callback()
+ })
+ }
+ , callback
+ )
+ }
+ , function (callback) {
+ // these shouldn't exist
+ async.forEach(
+ ['1', 'foo']
+ , function (key, callback) {
+ db.get(key, function (err, value) {
+ assert(err)
+ assert.isInstanceOf(err, errors.NotFoundError)
+ callback()
+ })
+ }
+ , callback
+ )
+ }
+ ]
+ , done
+ )
+ })
+ }
+
+ , 'batch() data can be read with get() and del()': function (done) {
+ this.openTestDatabase(function (db) {
+ async.series(
+ [
+ function (callback) {
+ db.batch(
+ [
+ { type: 'put', key: '1', value: 'one' }
+ , { type: 'put', key: '2', value: 'two' }
+ , { type: 'put', key: '3', value: 'three' }
+ ]
+ , callback
+ )
+ }
+ , db.del.bind(db, '1', 'one')
+ , function (callback) {
+ // these should exist
+ async.forEach(
+ ['2', '3']
+ , function (key, callback) {
+ db.get(key, function (err, value) {
+ refute(err)
+ callback()
+ })
+ }
+ , callback
+ )
+ }
+ , function (callback) {
+ // this shouldn't exist
+ db.get('1', function (err, value) {
+ assert(err)
+ assert.isInstanceOf(err, errors.NotFoundError)
+ callback()
+ })
+ }
+ ]
+ , done
+ )
+ })
+ }
}
})
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-leveldown.git
More information about the Pkg-javascript-commits
mailing list