Skip to content

Commit

Permalink
optimize iterators by avoiding handles.
Browse files Browse the repository at this point in the history
  • Loading branch information
chjj committed Apr 8, 2016
1 parent 259a5b7 commit ce3eb77
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 60 deletions.
110 changes: 53 additions & 57 deletions src/iterator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Iterator::Iterator (
, bool fillCache
, bool keyAsBuffer
, bool valueAsBuffer
, v8::Local<v8::Object> &startHandle
, size_t highWaterMark
) : database(database)
, id(id)
Expand All @@ -51,11 +50,6 @@ Iterator::Iterator (
{
Nan::HandleScope scope;

v8::Local<v8::Object> obj = Nan::New<v8::Object>();
if (!startHandle.IsEmpty())
obj->Set(Nan::New("obj").ToLocalChecked(), startHandle);
persistentHandle.Reset(obj);

options = new leveldb::ReadOptions();
options->fill_cache = fillCache;
// get a snapshot of the current state
Expand All @@ -71,11 +65,16 @@ Iterator::Iterator (
Iterator::~Iterator () {
delete options;
if (start != NULL) {
DisposeStringOrBufferFromSlice(persistentHandle, *start);
// Special case for `start` option: it won't be
// freed up by any of the delete calls below.
if (!((lt != NULL && reverse)
|| (lte != NULL && reverse)
|| (gt != NULL && !reverse)
|| (gte != NULL && !reverse))) {
delete[] start->data();
}
delete start;
}
if (!persistentHandle.IsEmpty())
persistentHandle.Reset();
if (end != NULL)
delete end;
if (lt != NULL)
Expand Down Expand Up @@ -341,10 +340,6 @@ v8::Local<v8::Object> Iterator::NewInstance (
NAN_METHOD(Iterator::New) {
Database* database = Nan::ObjectWrap::Unwrap<Database>(info[0]->ToObject());

//TODO: remove this, it's only here to make LD_STRING_OR_BUFFER_TO_SLICE happy
v8::Local<v8::Function> callback;

v8::Local<v8::Object> startHandle;
leveldb::Slice* start = NULL;
std::string* end = NULL;
int limit = -1;
Expand All @@ -360,6 +355,7 @@ NAN_METHOD(Iterator::New) {
v8::Local<v8::Object> gtHandle;
v8::Local<v8::Object> gteHandle;

char *startStr = NULL;
std::string* lt = NULL;
std::string* lte = NULL;
std::string* gt = NULL;
Expand All @@ -377,12 +373,13 @@ NAN_METHOD(Iterator::New) {
&& (node::Buffer::HasInstance(optionsObj->Get(Nan::New("start").ToLocalChecked()))
|| optionsObj->Get(Nan::New("start").ToLocalChecked())->IsString())) {

startHandle = optionsObj->Get(Nan::New("start").ToLocalChecked()).As<v8::Object>();
v8::Local<v8::Value> startBuffer = optionsObj->Get(Nan::New("start").ToLocalChecked());

// ignore start if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(startHandle) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_start, startHandle, start)
start = new leveldb::Slice(_start.data(), _start.size());
if (StringOrBufferLength(startBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_COPY(_start, startBuffer, start)
start = new leveldb::Slice(_startCh_, _startSz_);
startStr = _startCh_;
}
}

Expand All @@ -394,9 +391,9 @@ NAN_METHOD(Iterator::New) {

// ignore end if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(endBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_end, endBuffer, end)
end = new std::string(_end.data(), _end.size());
DisposeStringOrBufferFromSlice(endBuffer, _end);
LD_STRING_OR_BUFFER_TO_COPY(_end, endBuffer, end)
end = new std::string(_endCh_, _endSz_);
delete _endCh_;
}
}

Expand All @@ -418,17 +415,17 @@ NAN_METHOD(Iterator::New) {

// ignore end if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(ltBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_lt, ltBuffer, lt)
lt = new std::string(_lt.data(), _lt.size());
LD_STRING_OR_BUFFER_TO_COPY(_lt, ltBuffer, lt)
lt = new std::string(_ltCh_, _ltSz_);
delete[] _ltCh_;
if (reverse) {
if (start != NULL) {
DisposeStringOrBufferFromSlice(startHandle, *start);
delete start;
if (startStr != NULL) {
delete[] startStr;
startStr = NULL;
}
start = new leveldb::Slice(_lt.data(), _lt.size());
startHandle = optionsObj->Get(Nan::New("lt").ToLocalChecked()).As<v8::Object>();
} else {
DisposeStringOrBufferFromSlice(ltBuffer, _lt);
if (start != NULL)
delete start;
start = new leveldb::Slice(lt->data(), lt->size());
}
}
}
Expand All @@ -441,17 +438,17 @@ NAN_METHOD(Iterator::New) {

// ignore end if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(lteBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_lte, lteBuffer, lte)
lte = new std::string(_lte.data(), _lte.size());
LD_STRING_OR_BUFFER_TO_COPY(_lte, lteBuffer, lte)
lte = new std::string(_lteCh_, _lteSz_);
delete[] _lteCh_;
if (reverse) {
if (start != NULL) {
DisposeStringOrBufferFromSlice(startHandle, *start);
delete start;
if (startStr != NULL) {
delete[] startStr;
startStr = NULL;
}
start = new leveldb::Slice(_lte.data(), _lte.size());
startHandle = optionsObj->Get(Nan::New("lte").ToLocalChecked()).As<v8::Object>();
} else {
DisposeStringOrBufferFromSlice(lteBuffer, _lte);
if (start != NULL)
delete start;
start = new leveldb::Slice(lte->data(), lte->size());
}
}
}
Expand All @@ -464,17 +461,17 @@ NAN_METHOD(Iterator::New) {

// ignore end if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(gtBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_gt, gtBuffer, gt)
gt = new std::string(_gt.data(), _gt.size());
LD_STRING_OR_BUFFER_TO_COPY(_gt, gtBuffer, gt)
gt = new std::string(_gtCh_, _gtSz_);
delete _gtCh_;
if (!reverse) {
if (start != NULL) {
DisposeStringOrBufferFromSlice(startHandle, *start);
delete start;
if (startStr != NULL) {
delete[] startStr;
startStr = NULL;
}
start = new leveldb::Slice(_gt.data(), _gt.size());
startHandle = optionsObj->Get(Nan::New("gt").ToLocalChecked()).As<v8::Object>();
} else {
DisposeStringOrBufferFromSlice(gtBuffer, _gt);
if (start != NULL)
delete start;
start = new leveldb::Slice(gt->data(), gt->size());
}
}
}
Expand All @@ -487,17 +484,17 @@ NAN_METHOD(Iterator::New) {

// ignore end if it has size 0 since a Slice can't have length 0
if (StringOrBufferLength(gteBuffer) > 0) {
LD_STRING_OR_BUFFER_TO_SLICE(_gte, gteBuffer, gte)
gte = new std::string(_gte.data(), _gte.size());
LD_STRING_OR_BUFFER_TO_COPY(_gte, gteBuffer, gte)
gte = new std::string(_gteCh_, _gteSz_);
delete _gteCh_;
if (!reverse) {
if (start != NULL) {
DisposeStringOrBufferFromSlice(startHandle, *start);
delete start;
if (startStr != NULL) {
delete[] startStr;
startStr = NULL;
}
start = new leveldb::Slice(_gte.data(), _gte.size());
startHandle = optionsObj->Get(Nan::New("gte").ToLocalChecked()).As<v8::Object>();
} else {
DisposeStringOrBufferFromSlice(gteBuffer, _gte);
if (start != NULL)
delete start;
start = new leveldb::Slice(gte->data(), gte->size());
}
}
}
Expand Down Expand Up @@ -526,7 +523,6 @@ NAN_METHOD(Iterator::New) {
, fillCache
, keyAsBuffer
, valueAsBuffer
, startHandle
, highWaterMark
);
iterator->Wrap(info.This());
Expand Down
3 changes: 0 additions & 3 deletions src/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class Iterator : public Nan::ObjectWrap {
, bool fillCache
, bool keyAsBuffer
, bool valueAsBuffer
, v8::Local<v8::Object> &startHandle
, size_t highWaterMark
);

Expand Down Expand Up @@ -82,8 +81,6 @@ class Iterator : public Nan::ObjectWrap {
AsyncWorker* endWorker;

private:
Nan::Persistent<v8::Object> persistentHandle;

bool Read (std::string& key, std::string& value);
bool GetIterator ();

Expand Down
19 changes: 19 additions & 0 deletions src/leveldown.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,25 @@ static inline void DisposeStringOrBufferFromSlice(
} \
leveldb::Slice to(to ## Ch_, to ## Sz_);

#define LD_STRING_OR_BUFFER_TO_COPY(to, from, name) \
size_t to ## Sz_; \
char* to ## Ch_; \
if (!from->ToObject().IsEmpty() \
&& node::Buffer::HasInstance(from->ToObject())) { \
to ## Sz_ = node::Buffer::Length(from->ToObject()); \
to ## Ch_ = new char[to ## Sz_]; \
memcpy(to ## Ch_, node::Buffer::Data(from->ToObject()), to ## Sz_); \
} else { \
v8::Local<v8::String> to ## Str = from->ToString(); \
to ## Sz_ = to ## Str->Utf8Length(); \
to ## Ch_ = new char[to ## Sz_]; \
to ## Str->WriteUtf8( \
to ## Ch_ \
, -1 \
, NULL, v8::String::NO_NULL_TERMINATION \
); \
}

#define LD_RETURN_CALLBACK_OR_ERROR(callback, msg) \
if (!callback.IsEmpty() && callback->IsFunction()) { \
v8::Local<v8::Value> argv[] = { \
Expand Down

0 comments on commit ce3eb77

Please sign in to comment.