Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sync execution methods and performance optimization. #136

Closed
wants to merge 15 commits into from
Closed
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Tested & supported platforms
* Node 0.10 and above only, see [issue #5](https://github.com/rvagg/node-levelup/issues/5) for more info
* See installation instructions for *node-gyp* dependencies [here](https://github.com/TooTallNate/node-gyp#installation), you'll need these (free) components from Microsoft to compile and run any native Node add-on in Windows.

## Chnages

+ add the sync methods supports for open, put, get, del, batch, approximateSize.

the methods will be executed as sync method if no callback argument passed.
if any error occurs it will throw exception.
* Or call openSync, putSync, getSync, delSync, batchSync, approximateSizeSync directly.

<a name="api"></a>
## API

Expand Down
382 changes: 382 additions & 0 deletions bench/bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,382 @@
var leveldown = require('../');
var assert = require('assert');

leveldown = new leveldown(__dirname+"/foodb");

try {
leveldown.open({
errorIfExists : false
, createIfMissing : true
, cacheSize : 8 << 20
, writeBufferSize : 4 << 20
});
benchIt();
} catch(e) {
leveldown.open({
errorIfExists : false
, createIfMissing : true
, cacheSize : 8 << 20
, writeBufferSize : 4 << 20
}, function(err){
if (err) throw err;
benchIt();
})
}


// bench -----------------------------------
function benchIt() {
var count = 12000;
var val = '1337,1337,1337,1337,1337';

function putSync () {
if (!leveldown.putSync) {
return;
}
var start = Date.now();

for (var i = 0; i < count; i++) {
leveldown.put(i, val);
}

var duration = Date.now()-start;
log(true, count, 'put', duration);
}

function putSyncDirect () {
if (!leveldown.putSync) {
return;
}
var start = Date.now();

for (var i = 0; i < count; i++) {
leveldown.putSync(i, val);
}

var duration = Date.now()-start;
log(true, count, 'put', duration, 'directly');
}

function getSync () {
if (!leveldown.getSync) {
return;
}
start = Date.now();

for (var i = 0; i < count; i++) {
assert(leveldown.get(i) == val);
}

duration = Date.now()-start;
log(true, count, 'get', duration,"asBuffer");
}

function getSyncDirect () {
if (!leveldown.getSync) {
return;
}
start = Date.now();

for (var i = 0; i < count; i++) {
assert(leveldown.getSync(i) == val);
}

duration = Date.now()-start;
log(true, count, 'get', duration, 'directly');
}

function getStrSync () {
if (!leveldown.getSync) {
return;
}
start = Date.now();

for (var i = 0; i < count; i++) {
assert(leveldown.get(i, {asBuffer: false}) == val);
}

duration = Date.now()-start;
log(true, count, 'get', duration);
}

function putAsync(cb) {
start = Date.now();

var written = 0;
for (var i = 0; i < count; i++) {
leveldown.put(i, val, function (err) {
if (err) throw err;
if (++written == count) {
duration = Date.now()-start;
log(false, count, 'put', duration);
if (cb) cb();
}
})
}
}

function getAsync (cb) {
start = Date.now();

var received = 0;
for (var i = 0; i < count; i++) {
leveldown.get(i, function (err, value) {
if (err) throw err;
assert(value == val);
if (++received == count) {
duration = Date.now()-start;
log(false, count, 'get', duration, "asBuffer");
if (cb) cb()
}
})
}
}

function getStrAsync (cb) {
start = Date.now();

var received = 0;
for (var i = 0; i < count; i++) {
leveldown.get(i, {asBuffer:false}, function (err, value) {
if (err) throw err;
assert(value == val);
if (++received == count) {
duration = Date.now()-start;
log(false, count, 'get', duration);
if (cb) cb()
}
})
}
}

function batchSync () {
if (!leveldown.batchSync) {
return;
}
var start = Date.now();

var arr = [];
for (var i = 0; i < count; i++) {
arr.push({type:"put",key:i, value:val});
}

var batch = leveldown.batch(arr);

var duration = Date.now()-start;
log(true, count, 'batch', duration);
}

function batchSyncDirect () {
if (!leveldown.batchSync) {
return;
}
var start = Date.now();

var arr = [];
for (var i = 0; i < count; i++) {
arr.push({type:"put",key:i, value:val});
}

var batch = leveldown.batchSync(arr);

var duration = Date.now()-start;
log(true, count, 'batch', duration, 'directly');
}

function batchAsync(cb) {
var start = Date.now();

var arr = [];
for (var i = 0; i < count; i++) {
arr.push({type:"put",key:i, value:val});
}

leveldown.batch(arr, function (err) {
if (err) throw err;
var duration = Date.now() - start;
log(false, count, 'batch', duration);
if (cb) cb();
});
}

function iteratorAsync (cb) {
start = Date.now();

var received = 0;
var result=[];
var iterator = leveldown.iterator()
, fn = function (err, key, value) {
if (err) {
console.log(err)
}
else if (key && value) {
received++
result.push(key)
result.push(value)
process.nextTick(next)
} else { // end
iterator.end(function () {
var duration = Date.now()-start;
assert(received == count);
log(false, received, 'iterator', duration, "asBuffer");
if (cb) cb()
})
}
}
, next = function () {
iterator.next(fn)
}
next();
}

function iteratorStrAsync (cb) {
start = Date.now();

var received = 0;
var result=[];
var iterator = leveldown.iterator({valueAsBuffer: false, keyAsBuffer: false})
, fn = function (err, key, value) {
if (err) {
console.log(err)
}
else if (key && value) {
received++
result.push(key)
result.push(value)
process.nextTick(next)
} else { // end
iterator.end(function () {
var duration = Date.now()-start;
assert(received == count);
log(false, received, 'iterator', duration);
if (cb) cb()
})
}
}
, next = function () {
iterator.next(fn)
}
next();
}

function iteratorStrAsyncDirect (cb) {
start = Date.now();

var received = 0;
var result=[];
var iterator = leveldown.iterator({keyAsBuffer: false, valueAsBuffer:false, highWaterMark: 16*1024*8}) //22 will get all at once.
, fn = function (err, arr, finished) {
if (err) {
console.log(err)
if (cb) cb()
return
}
received += arr.length / 2
result = result.concat(arr)
if (!finished) {
process.nextTick(next)
} else { // end
iterator.end(function () {
var duration = Date.now()-start;
log(false, received, 'iterator', duration, "directly");
if (cb) cb()
})
}
}
, next = function () {
iterator.binding.next(fn)
}
next();
}

function iteratorStrSyncDirect () {
if (!leveldown.putSync) {
return;
}
start = Date.now();

var received = 0;
var iterator = leveldown.iterator({keyAsBuffer: false, valueAsBuffer:false, highWaterMark: 16*1024*8}); //, highWaterMark: 16*1024*22, 22 will get all at once.
var result = [];
var results = iterator.nextSync(result);
var size = results[1];
while (size > 0) {
result = result.concat(results[0])
received += size;
//result = [];
results = iterator.nextSync(result);
size = results[1];
}
result = result.concat(results[0])
received += Math.abs(size);
var duration = Date.now()-start;
assert(received == count);
log(true, received, 'iterator', duration, "directly");
iterator.endSync()
}


/*
* Get it started
*/

console.log('\n benchmarking with ' + humanize(count) + ' records, ' + val.length + ' chars each\n');

putAsync(function () {
putSync()
putSyncDirect()
batchAsync(function () {
batchSync()
batchSyncDirect()
getAsync(function () {
getStrAsync(function () {
getSync()
getStrSync()
getSyncDirect()
iteratorAsync(function(){
iteratorStrAsync(function(){
iteratorStrAsyncDirect(function(){
iteratorStrSyncDirect()
console.log()
})
})
})
})
})
})
})

/*
* Utility functions
*/

var last;
function log(sync, num, op, dur, desc) {
if (!desc) desc = ""
else desc = "("+desc+")";
if (last && last != op) console.log();
last = op;
console.log([
pad(op + (sync? 'Sync' : ''), 13),
':',
pad(humanize(Math.floor(1000/dur * num)), 9),
{'batch' : 'w', 'put' : 'w', 'get' : 'r', 'iterator' : 'r'}[op] + '/s',
'in ' + pad(humanize(dur), 6) + 'ms' + pad(desc, 18)
].join(' '));
}

function pad(str, len) {
str = str.toString();
return Array(len - str.length + 1).join(' ') + str;
}

function humanize(n, options){
options = options || {};
var d = options.delimiter || ',';
var s = options.separator || '.';
n = n.toString().split('.');
n[0] = n[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + d);
return n.join(s);
}

}
Loading