pax_global_header00006660000000000000000000000064126064737300014522gustar00rootroot0000000000000052 comment=dec801f29059e505fe217e09a802acc2617ca3e9 node-leveldown-1.4.1+dfsg/000077500000000000000000000000001260647373000153665ustar00rootroot00000000000000node-leveldown-1.4.1+dfsg/.dntrc000066400000000000000000000011431260647373000165000ustar00rootroot00000000000000## DNT config file ## see https://github.com/rvagg/dnt NODE_VERSIONS="\ v0.10.40 \ v0.12.7 \ " IOJS_VERSIONS="\ v1.8.4 \ v2.0.1 \ v2.3.4 \ v3.0.0-rc.3 \ " OUTPUT_PREFIX="leveldown-" TEST_CMD="\ cd /dnt/ && \ npm install && \ npm run-script prebuild \ --nodedir=/usr/src/node/ && \ node_modules/.bin/tape test/*-test.js \ " # for tape LOG_OK_CMD="tail -2 | head -1 | sed 's/^# //'" node-leveldown-1.4.1+dfsg/.gitignore000066400000000000000000000002621260647373000173560ustar00rootroot00000000000000node_modules/ build/ build-pre-gyp/ libleveldb.so libleveldb.a leakydb bench/ *.sln *.vcxproj *.vcxproj.filters *.tlog *.obj *.1sdk.pdb *.lastbuildstate npm-debug.log prebuilds/ node-leveldown-1.4.1+dfsg/.jshintrc000066400000000000000000000021721260647373000172150ustar00rootroot00000000000000{ "predef": [ ] , "bitwise": false , "camelcase": false , "curly": false , "eqeqeq": false , "forin": false , "immed": false , "latedef": false , "noarg": true , "noempty": true , "nonew": true , "plusplus": false , "quotmark": true , "regexp": false , "undef": true , "unused": true , "strict": false , "trailing": true , "maxlen": 120 , "asi": true , "boss": true , "debug": true , "eqnull": true , "esnext": true , "evil": true , "expr": true , "funcscope": false , "globalstrict": false , "iterator": false , "lastsemic": true , "laxbreak": true , "laxcomma": true , "loopfunc": true , "multistr": false , "onecase": false , "proto": false , "regexdash": false , "scripturl": true , "smarttabs": false , "shadow": false , "sub": true , "supernew": false , "validthis": true , "browser": true , "couch": false , "devel": false , "dojo": false , "mootools": false , "node": true , "nonstandard": true , "prototypejs": false , "rhino": false , "worker": true , "wsh": false , "nomen": false , "onevar": true , "passfail": false }node-leveldown-1.4.1+dfsg/.npmignore000066400000000000000000000004111260647373000173610ustar00rootroot00000000000000*.tar.gz build/ build-pre-gyp/ test-data.tar test-data.db.tar deps/leveldb/leveldb-basho/ deps/leveldb/leveldb-hyper/ deps/leveldb/leveldb-rocksdb/ deps/snappy/snappy-1.1.1/testdata/ leakydb bench/ test/ deps/leveldb/leveldb-1.17.0/doc/ README INSTALL NEWS AUTHORS node-leveldown-1.4.1+dfsg/.prebuildrc000066400000000000000000000002441260647373000175220ustar00rootroot00000000000000# abi 11 target[] = 0.10.40 # abi 14 target[] = 0.12.7 # abi 42 target[] = 1.0.4 # abi 43 target[] = 1.8.4 # abi 44 target[] = 2.4.0 # abi 45 target[] = 3.0.0 node-leveldown-1.4.1+dfsg/.travis.yml000066400000000000000000000003071260647373000174770ustar00rootroot00000000000000language: node_js before_install: - export JOBS=max - export prebuild_compile=true node_js: - "2.4" - "1.8" - "1.0" - "0.12" - "0.10" install: - npm install script: - npm test node-leveldown-1.4.1+dfsg/CHANGELOG.md000066400000000000000000000244111260647373000172010ustar00rootroot00000000000000Note that we have filtered out commits related to new tags, updating changelog and we're also not listing any merge commits, i.e. we are only listing things that changed between versions. ### 1.0.7 May 27 2015 * [[`61398a0056`](https://github.com/level/leveldown/commit/61398a0056)] - link to level/community (Lars-Magnus Skog) * [[`382a1a7fa3`](https://github.com/level/leveldown/commit/382a1a7fa3)] - add compression test suite (Julian Gruber) * [[`139db7bc7f`](https://github.com/level/leveldown/commit/139db7bc7f)] - use const reference instead of by value in Database constructor (Lars-Magnus Skog) * [[`b56a86323e`](https://github.com/level/leveldown/commit/b56a86323e)] - refactor NanNew() on strings into option value functions (Lars-Magnus Skog) * [[`ca1f4746c4`](https://github.com/level/leveldown/commit/ca1f4746c4)] - refactor BooleanOptionValue (Lars-Magnus Skog) * [[`56def2d7c8`](https://github.com/level/leveldown/commit/56def2d7c8)] - NanUInt32OptionValue -> UInt32OptionValue (Lars-Magnus Skog) * [[`39c614a24f`](https://github.com/level/leveldown/commit/39c614a24f)] - NanBooleanOptionValue -> BooleanOptionValue (Lars-Magnus Skog) * [[`fcdc46183e`](https://github.com/level/leveldown/commit/fcdc46183e)] - simplify location logic, let Database take care of allocation (Lars-Magnus Skog) * [[`8cb90e6b6d`](https://github.com/level/leveldown/commit/8cb90e6b6d)] - update abstract-leveldown (Lars-Magnus Skog) * [[`f70b6576e7`](https://github.com/level/leveldown/commit/f70b6576e7)] - update .travis.yml (nvm works on travis now) (Lars-Magnus Skog) * [[`007550e7f7`](https://github.com/level/leveldown/commit/007550e7f7)] - 1.0.6 (Lars-Magnus Skog) ### 1.0.5/1.0.6 May 5 2015 * [[`9064099fe7`](https://github.com/level/leveldown/commit/9064099fe7)] - pass db to abstractIterator so gc keeps it (Julian Gruber) ### 1.0.4 May 5 2015 * [[`b550c98291`](https://github.com/level/leveldown/commit/b550c98291)] - update nan for iojs 2.0.0 (Lars-Magnus Skog) ### 1.0.3 May 2 2015 * [[`82479b689f`](https://github.com/level/leveldown/commit/82479b689f)] - tap -> tape + faucet (Lars-Magnus Skog) * [[`ca9101542a`](https://github.com/level/leveldown/commit/ca9101542a)] - fix write-random.js, use leveldown instead of lmdb (Lars-Magnus Skog) * [[`03fbbfb99f`](https://github.com/level/leveldown/commit/03fbbfb99f)] - fix bench/db-bench.js (Lars-Magnus Skog) ### 1.0.2 Apr 26 2015 * [[`8470a63678`](https://github.com/level/leveldown/commit/8470a63678)] - s/rvagg\/node-/level\// (Lars-Magnus Skog) * [[`9cbf592bea`](https://github.com/level/leveldown/commit/9cbf592bea)] - add documentation about snapshots (Max Ogden) * [[`b57827cd29`](https://github.com/level/leveldown/commit/b57827cd29)] - use n instead of nvm for working iojs support (Lars-Magnus Skog) * [[`a19927667a`](https://github.com/level/leveldown/commit/a19927667a)] - abstract-leveldown ~2.1.0 (ralphtheninja) * [[`95ccdf0850`](https://github.com/level/leveldown/commit/95ccdf0850)] - update logo and copyright (Lars-Magnus Skog) * [[`09e89d7abb`](https://github.com/level/leveldown/commit/09e89d7abb)] - updated my email (ralphtheninja) ### 1.0.1 Jan 16 2015 * [[`6df3ecd6f5`](https://github.com/level/leveldown/commit/6df3ecd6f5)] - nan 1.5 for io.js support (Rod Vagg) * [[`5198231a88`](https://github.com/level/leveldown/commit/5198231a88)] - Fix LevelDB builds for modern gcc versions (Sharvil Nanavati) ### 1.0.0 Aug 26 2014 * NAN@1.3 for Node 0.11.13+ support (@rvagg) * Allow writing empty values: null, undefined, '', [] and Buffer(0). Entries come out as '' or Buffer(0) (@ggreer, @juliangruber, @rvagg) * Fix clang build (@thlorenz) * Massive speed up of iterators by chunking reads (@kesla) * Wrap in abstract-leveldown for consistent type-checking across *DOWNs (@kesla) * Upgrade to LevelDB 1.17.0 (@kesla) * Minor memory leaks * Remove compile option that borked EL5 compiles * Switch to plain MIT license ### 0.10.2 @ Nov 30 2013 * Apply fix by @rescrv for long-standing OSX corruption bug, https://groups.google.com/forum/#!topic/leveldb/GXhx8YvFiig (@rvagg / @rescrv) ### 0.10.1 @ Nov 21 2013 * NAN@0.6 for Node@0.11.6 support, v8::Local::New(val) rewritten to NanNewLocal(val) (@rvagg) ### 0.10.0 @ Nov 18 2013 * Fix array-batch memory leak, levelup/#171 (@rvagg) * Fix chained-batch write() segfaults, details in #73, (@rvagg and @mcollina) * Remove `Persistent` references for all `batch()` operations as `WriteBatch` takes an explicit copy of the data (@mcollina and @rvagg) * Upgrade to Snappy 1.1.1 (@rvagg and @no9) * Upgrade to NAN@0.5.x (@rvagg) * Switch all `callback->Call()`s to `node::MakeCallback()` to properly support Node.js domains (@rvagg) * Properly enable compression by default (@Kyotoweb) * Enable LevelDB's BloomFilter (@Kyotoweb) * Upgrade to AbstractLevelDOWN@0.11.x for testing (@rvagg) * Add new simple batch() leak tester (@rvagg) ### 0.9.2 @ Nov 02 2013 * Minor fixes to support Node 0.11.8 and new Linux gcc (warnings) (@rvagg) ### 0.9.1 @ Oct 03 2013 * Include port_uv.h for Windows compile, added test to suite to make sure this happens every time LevelDB is upgraded (@rvagg) ### 0.9.0 @ Oct 01 2013 * Upgrade from LevelDB@0.11.0 to LevelDB@0.14.0, includes change from .sst to .ldb file extension for SST files (@rvagg) ### 0.8.3 @ Sept 18 2013 * Upgrade to nan@0.4.0, better support for latest Node master & support for installing within directory structures containing spaces in directory names (@rvagg) ### 0.8.2 @ Sept 2 2013 * FreeBSD support (@rvagg, @kelexel) ### 0.8.1 @ Sept 1 2013 * Fixed some minor V8-level leaks (@rvagg) ### 0.8.0 @ Aug 19 2013 * Added `gt`, `lt`, `gte`, `lte` for iterators (@dominictarr) * Switch to NAN as an npm dependency (@rvagg) ### 0.7.0 @ Aug 11 2013 * Added @pgte to contributors list * (very) Minor perf improvements in C++ (@mscdex) * Use NAN for Node 0.8->0.11 compatibility ### 0.6.2 @ Jul 07 2013 * Compatibility for Node 0.11.3, breaks compatibility with 0.11.2 ### 0.6.1 @ Jun 15 2013 * Fix broken Windows compile, apply port-uv patch to LevelDB's port.h (@rvagg) ### 0.6.0 @ Jun 14 2013 * Upgrade to LevelDB 1.11.0, some important bugfixes: https://groups.google.com/forum/#!topic/leveldb/vS1JvmGlp4E ### 0.5.0 @ May 18 2013 * Bumped major version for db.getProperty() addition (should have been done in 0.4.4) (@rvagg) * Disallow batch() operations after a write() (@rvagg) ### 0.4.4 @ May 18 2013 * db.getProperty() implemented, see README for details (@rvagg) * More work on memory management, including late-creation of Persistent handles (@rvagg) ### 0.4.3 @ May 18 2013 * Better memory leak fix (@rvagg) ### 0.2.2 @ May 17 2013 * BACKPORT memory leak fixes (@rvagg) ### 0.4.2 @ May 17 2013 * Same memory leak fixes as 0.4.1, properly applied to batch() operations too (@rvagg) ### 0.4.1 @ May 17 2013 * Fix memory leak caused when passing String objects in as keys and values, conversion to Slice created new char[] but wasn't being disposed. Buffers are automatically disposed. (@rvagg, reported by @kylegetson levelup/#140) ### 0.4.0 @ May 15 2013 * Upgrade to LevelDB 1.10.0, fairly minor changes, mostly bugfixes see https://groups.google.com/forum/#!topic/leveldb/O2Zdbi9Lrao for more info (@rvagg) ### 0.3.1 @ May 14 2013 * Don't allow empty batch() operations through to LevelDB, on chained of array forms (@rvagg) ### 0.3.0 (& 0.2.2) @ May 14 2013 * Pull API tests up into AbstractLevelDOWN, require it to run the tests. AbstractLevelDOWN can now be used to test LevelDOWN-compliant APIs. (@maxogden) * Change Iterator methods to return errors on the callbacks rather than throw (@mcollina & @rvagg) 0.2.1 @ Apr 8 2013 ================== * Start on correct value when reverse=true, also handle end-of-store case #27 (@kesla) * Ignore empty string/buffer start/end options on iterators (@kesla) * Macro cleanup, replace some with static inline functions (@rvagg) ### 0.2.0 @ Mar 30 2013 * Windows support--using a combination of libuv and Windows-specific code. See README for details about what's required (@rvagg) * leveldown.destroy(location, callback) to delete an existing LevelDB store, exposes LevelDB.DestroyDB() (@rvagg) * leveldown.repair(location, callback) to repair an existing LevelDB store, exposes LevelDB.RepairDB() (@rvagg) * advanced options: writeBufferSize, blockSize, maxOpenFiles, blockRestartInterval, exposes LevelDB options (@rvagg) * chained-batch operations. Argument-less db.batch() will return a new Batch object that can .put() and .del() and then .write(). API in flux so not documented yet. (@juliangruber / @rvagg) * auto-cleanup iterators that are left open when you close a database; any iterators left open when you close a database instance will kill your process so we now keep track of iterators and auto-close them before a db.close completes. * Node 0.11 support (no compile warnings) ### 0.1.4 @ Mar 11 2013 * return error when batch ops contain null or undefined (@rvagg / @ralphtheninja / @dominictarr) (additional tests in LevelUP for this) 0.1.3 @ Mar 9 2013 ================== * add 'standalone_static_library':1 in dependency gyp files to fix SmartOS build problems (@wolfeidau) ### 0.1.2 @ Jan 25 2013 * upgrade to LevelDB 1.9.0, fairly minor changes since 1.7.0 (@rvagg) * upgrade to Snappy 1.1.0, changes block size to improve compression ~3%, slight decrease in speed (@rvagg) ### 0.1.1 @ Jan 25 2013 * compile error on Mac OS (@kesla / @rvagg) ### 0.1.0 @ Jan 24 2013 * change API to export single function `levelup()` (@rvagg) * move `createIterator()` to `levelup#iterator()` (@rvagg) * make all `options` arguments optional (@rvagg) * argument number & type checking on all methods (@rvagg) * stricter checking on key & value types, String/Object.toString()/Buffer, non-zero-length (@rvagg) * remove `use namespace` and add `namespace leveldown` everywhere (@rvagg) * race condition in Iterator end()/next() fix, merged from LevelUP (@ralphtheninja / @rvagg) * add complete, independent test suite (@rvagg) ### 0.0.1 & 0.0.2 @ Jan 2013 * finalise rename of internal components to LevelDOWN, removing LevelUP references (@rvagg) * complete documentation of current API (@rvagg) ### 0.0.0 @ Jan 06 2013 * extracted from LevelUP as stand-alone package (@rvagg) node-leveldown-1.4.1+dfsg/LICENSE.md000066400000000000000000000021451260647373000167740ustar00rootroot00000000000000The MIT License (MIT) ===================== Copyright (c) 2014 Rod Vagg --------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. node-leveldown-1.4.1+dfsg/README.md000066400000000000000000000552521260647373000166560ustar00rootroot00000000000000LevelDOWN ========= LevelDB Logo A Low-level Node.js LevelDB binding ------------------------- [![Build Status](https://secure.travis-ci.org/Level/leveldown.png)](http://travis-ci.org/Level/leveldown) [![NPM](https://nodei.co/npm/leveldown.png?stars&downloads&downloadRank)](https://nodei.co/npm/leveldown/) [![NPM](https://nodei.co/npm-dl/leveldown.png?months=6&height=3)](https://nodei.co/npm/leveldown/) LevelDOWN was extracted from [LevelUP](https://github.com/level/levelup) and now serves as a stand-alone binding for LevelDB. It is **strongly recommended** that you use LevelUP in preference to LevelDOWN unless you have measurable performance reasons to do so. LevelUP is optimised for usability and safety. Although we are working to improve the safety of the LevelDOWN interface it is still easy to crash your Node process if you don't do things in just the right way. See the section on safety below for details of known unsafe operations with LevelDOWN. Tested & supported platforms ---------------------------- * **Linux** (including ARM platforms such as Raspberry Pi *and Kindle!*) * **Mac OS** * **Solaris** (SmartOS & Nodejitsu) * **FreeBSD** * **Windows** * Node 0.10 and above only, see [issue #5](https://github.com/level/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. ## API * leveldown() * leveldown#open() * leveldown#close() * leveldown#put() * leveldown#get() * leveldown#del() * leveldown#batch() * leveldown#approximateSize() * leveldown#getProperty() * leveldown#iterator() * iterator#next() * iterator#seek() * iterator#end() * leveldown.destroy() * leveldown.repair() -------------------------------------------------------- ### leveldown(location) leveldown() returns a new **LevelDOWN** instance. `location` is a String pointing to the LevelDB location to be opened. -------------------------------------------------------- ### leveldown#open([options, ]callback) open() is an instance method on an existing database object. The `callback` function will be called with no arguments when the database has been successfully opened, or with a single `error` argument if the open operation failed for any reason. #### `options` The optional `options` argument may contain: * `'createIfMissing'` *(boolean, default: `true`)*: If `true`, will initialise an empty database at the specified location if one doesn't already exist. If `false` and a database doesn't exist you will receive an error in your `open()` callback and your database won't open. * `'errorIfExists'` *(boolean, default: `false`)*: If `true`, you will receive an error in your `open()` callback if the database exists at the specified location. * `'compression'` *(boolean, default: `true`)*: If `true`, all *compressible* data will be run through the Snappy compression algorithm before being stored. Snappy is very fast and shouldn't gain much speed by disabling so leave this on unless you have good reason to turn it off. * `'cacheSize'` *(number, default: `8 * 1024 * 1024` = 8MB)*: The size (in bytes) of the in-memory [LRU](http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used) cache with frequently used uncompressed block contents. **Advanced options** The following options are for advanced performance tuning. Modify them only if you can prove actual benefit for your particular application. * `'writeBufferSize'` *(number, default: `4 * 1024 * 1024` = 4MB)*: The maximum size (in bytes) of the log (in memory and stored in the .log file on disk). Beyond this size, LevelDB will convert the log data to the first level of sorted table files. From the LevelDB documentation: > Larger values increase performance, especially during bulk loads. Up to two write buffers may be held in memory at the same time, so you may wish to adjust this parameter to control memory usage. Also, a larger write buffer will result in a longer recovery time the next time the database is opened. * `'blockSize'` *(number, default `4096` = 4K)*: The *approximate* size of the blocks that make up the table files. The size related to uncompressed data (hence "approximate"). Blocks are indexed in the table file and entry-lookups involve reading an entire block and parsing to discover the required entry. * `'maxOpenFiles'` *(number, default: `1000`)*: The maximum number of files that LevelDB is allowed to have open at a time. If your data store is likely to have a large working set, you may increase this value to prevent file descriptor churn. To calculate the number of files required for your working set, divide your total data by 2MB, as each table file is a maximum of 2MB. * `'blockRestartInterval'` *(number, default: `16`)*: The number of entries before restarting the "delta encoding" of keys within blocks. Each "restart" point stores the full key for the entry, between restarts, the common prefix of the keys for those entries is omitted. Restarts are similar to the concept of keyframs in video encoding and are used to minimise the amount of space required to store keys. This is particularly helpful when using deep namespacing / prefixing in your keys. -------------------------------------------------------- ### leveldown#close(callback) close() is an instance method on an existing database object. The underlying LevelDB database will be closed and the `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown#put(key, value[, options], callback) put() is an instance method on an existing database object, used to store new entries, or overwrite existing entries in the LevelDB store. The `key` and `value` objects may either be `String`s or Node.js `Buffer` objects. Other object types are converted to JavaScript `String`s with the `toString()` method. Keys may not be `null` or `undefined` and objects converted with `toString()` should not result in an empty-string. Values of `null`, `undefined`, `''`, `[]` and `new Buffer(0)` (and any object resulting in a `toString()` of one of these) will be stored as a zero-length character array and will therefore be retrieved as either `''` or `new Buffer(0)` depending on the type requested. A richer set of data-types are catered for in LevelUP. #### `options` The only property currently available on the `options` object is `'sync'` *(boolean, default: `false`)*. If you provide a `'sync'` value of `true` in your `options` object, LevelDB will perform a synchronous write of the data; although the operation will be asynchronous as far as Node is concerned. Normally, LevelDB passes the data to the operating system for writing and returns immediately, however a synchronous write will use `fsync()` or equivalent so your callback won't be triggered until the data is actually on disk. Synchronous filesystem writes are **significantly** slower than asynchronous writes but if you want to be absolutely sure that the data is flushed then you can use `'sync': true`. The `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown#get(key[, options], callback) get() is an instance method on an existing database object, used to fetch individual entries from the LevelDB store. The `key` object may either be a `String` or a Node.js `Buffer` object and cannot be `undefined` or `null`. Other object types are converted to JavaScript `String`s with the `toString()` method and the resulting `String` *may not* be a zero-length. A richer set of data-types are catered for in LevelUP. Values fetched via `get()` that are stored as zero-length character arrays (`null`, `undefined`, `''`, `[]`, `new Buffer(0)`) will return as empty-`String` (`''`) or `new Buffer(0)` when fetched with `asBuffer: true` (see below). #### `options` The optional `options` object may contain: * `'fillCache'` *(boolean, default: `true`)*: LevelDB will by default fill the in-memory LRU Cache with data from a call to get. Disabling this is done by setting `fillCache` to `false`. * `'asBuffer'` *(boolean, default: `true`)*: Used to determine whether to return the `value` of the entry as a `String` or a Node.js `Buffer` object. Note that converting from a `Buffer` to a `String` incurs a cost so if you need a `String` (and the `value` can legitimately become a UFT8 string) then you should fetch it as one with `asBuffer: true` and you'll avoid this conversion cost. The `callback` function will be called with a single `error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be the `value` as a `String` or `Buffer` depending on the `asBuffer` option. -------------------------------------------------------- ### leveldown#del(key[, options], callback) del() is an instance method on an existing database object, used to delete entries from the LevelDB store. The `key` object may either be a `String` or a Node.js `Buffer` object and cannot be `undefined` or `null`. Other object types are converted to JavaScript `String`s with the `toString()` method and the resulting `String` *may not* be a zero-length. A richer set of data-types are catered for in LevelUP. #### `options` The only property currently available on the `options` object is `'sync'` *(boolean, default: `false`)*. See leveldown#put() for details about this option. The `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown#batch(operations[, options], callback) batch() is an instance method on an existing database object. Used for very fast bulk-write operations (both *put* and *delete*). The `operations` argument should be an `Array` containing a list of operations to be executed sequentially, although as a whole they are performed as an atomic operation inside LevelDB. Each operation is contained in an object having the following properties: `type`, `key`, `value`, where the *type* is either `'put'` or `'del'`. In the case of `'del'` the `'value'` property is ignored. Any entries with a `'key'` of `null` or `undefined` will cause an error to be returned on the `callback`. Any entries where the *type* is `'put'` that have a `'value'` of `undefined`, `null`, `[]`, `''` or `new Buffer(0)` will be stored as a zero-length character array and therefore be fetched during reads as either `''` or `new Buffer(0)` depending on how they are requested. See [LevelUP](https://github.com/level/levelup#batch) for full documentation on how this works in practice. #### `options` The only property currently available on the `options` object is `'sync'` *(boolean, default: `false`)*. See leveldown#put() for details about this option. The `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown#approximateSize(start, end, callback) approximateSize() is an instance method on an existing database object. Used to get the approximate number of bytes of file system space used by the range `[start..end)`. The result may not include recently written data. The `start` and `end` parameters may be either `String` or Node.js `Buffer` objects representing keys in the LevelDB store. The `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown#getProperty(property) getProperty can be used to get internal details from LevelDB. When issued with a valid property string, a readable string will be returned (this method is synchronous). Currently, the only valid properties are: * 'leveldb.num-files-at-levelN': return the number of files at level *N*, where N is an integer representing a valid level (e.g. "0"). * 'leveldb.stats': returns a multi-line string describing statistics about LevelDB's internal operation. * 'leveldb.sstables': returns a multi-line string describing all of the *sstables* that make up contents of the current database. -------------------------------------------------------- ### leveldown#iterator([options]) iterator() is an instance method on an existing database object. It returns a new **Iterator** instance. #### `options` The optional `options` object may contain: * `'gt'` (greater than), `'gte'` (greater than or equal) define the lower bound of the values to be fetched and will determine the starting point where `'reverse'` is not `true`. Only records where the key is greater than (or equal to) this option will be included in the range. When `'reverse'` is 'true` the order will be reversed, but the records returned will be the same. * `'lt'` (less than), `'lte'` (less than or equal) define the higher bound of the range to be fetched and will determine the starting poitn where `'reverse'` is *not* `true`. Only key / value pairs where the key is less than (or equal to) this option will be included in the range. When `'reverse'` is `true` the order will be reversed, but the records returned will be the same. * `'start', 'end'` legacy ranges - instead use `'gte', 'lte'` * `'reverse'` *(boolean, default: `false`)*: a boolean, set to true if you want the stream to go in reverse order. Beware that due to the way LevelDB works, a reverse seek will be slower than a forward seek. * `'keys'` *(boolean, default: `true`)*: whether the callback to the `next()` method should receive a non-null `key`. There is a small efficiency gain if you ultimately don't care what the keys are as they don't need to be converted and copied into JavaScript. * `'values'` *(boolean, default: `true`)*: whether the callback to the `next()` method should receive a non-null `value`. There is a small efficiency gain if you ultimately don't care what the values are as they don't need to be converted and copied into JavaScript. * `'limit'` *(number, default: `-1`)*: limit the number of results collected by this iterator. This number represents a *maximum* number of results and may not be reached if you get to the end of the store or your `'end'` value first. A value of `-1` means there is no limit. * `'fillCache'` *(boolean, default: `false`)*: wheather LevelDB's LRU-cache should be filled with data read. * `'keyAsBuffer'` *(boolean, default: `true`)*: Used to determine whether to return the `key` of each entry as a `String` or a Node.js `Buffer` object. Note that converting from a `Buffer` to a `String` incurs a cost so if you need a `String` (and the `value` can legitimately become a UFT8 string) then you should fetch it as one. * `'valueAsBuffer'` *(boolean, default: `true`)*: Used to determine whether to return the `value` of each entry as a `String` or a Node.js `Buffer` object. -------------------------------------------------------- ### iterator#next(callback) next() is an instance method on an existing iterator object, used to increment the underlying LevelDB iterator and return the entry at that location. the `callback` function will be called with no arguments in any of the following situations: * the iterator comes to the end of the store * the `end` key has been reached; or * the `limit` has been reached Otherwise, the `callback` function will be called with the following 3 arguments: * `error` - any error that occurs while incrementing the iterator. * `key` - either a `String` or a Node.js `Buffer` object depending on the `keyAsBuffer` argument when the `iterator()` was called. * `value` - either a `String` or a Node.js `Buffer` object depending on the `valueAsBuffer` argument when the `iterator()` was called. -------------------------------------------------------- ### iterator#seek(key) seek() is an instance method on an existing iterator object, used to seek the underlying LevelDB iterator to a given key. By calling seek(key), subsequent calls to next(cb) will return key/values larger or smaller than key, based on your reverse setting in the iterator constructor. -------------------------------------------------------- ### iterator#end(callback) end() is an instance method on an existing iterator object. The underlying LevelDB iterator will be deleted and the `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if the operation failed for any reason. -------------------------------------------------------- ### leveldown.destroy(location, callback) destroy() is used to completely remove an existing LevelDB database directory. You can use this function in place of a full directory *rm* if you want to be sure to only remove LevelDB-related files. If the directory only contains LevelDB files, the directory itself will be removed as well. If there are additional, non-LevelDB files in the directory, those files, and the directory, will be left alone. The callback will be called when the destroy operation is complete, with a possible `error` argument. ### leveldown.repair(location, callback) repair() can be used to attempt a restoration of a damaged LevelDB store. From the LevelDB documentation: > If a DB cannot be opened, you may attempt to call this method to resurrect as much of the contents of the database as possible. Some data may be lost, so be careful when calling this function on a database that contains important information. You will find information on the *repair* operation in the *LOG* file inside the store directory. A `repair()` can also be used to perform a compaction of the LevelDB log into table files. The callback will be called when the repair operation is complete, with a possible `error` argument. Safety ------ ### Database state Currently LevelDOWN does not track the state of the underlying LevelDB instance. This means that calling `open()` on an already open database may result in an error. Likewise, calling any other operation on a non-open database may result in an error. LevelUP currently tracks and manages state and will prevent out-of-state operations from being send to LevelDOWN. If you use LevelDOWN directly then you must track and manage state for yourself. Snapshots --------------- LevelDOWN exposes a feature of LevelDB called [snapshots](http://leveldb.googlecode.com/git-history/f779e7a5d89f853fc5224f9eb8103ca2b8f2f555/doc/index.html). This means that when you do e.g. `createReadStream` and `createWriteStream` at the same time, any data modified by the write stream will not affect data emitted from the read stream. In other words, a LevelDB Snapshot captures the latest state at the time the snapshot was created, enabling the snapshot to iterate or read the data without seeing any subsequent writes. Any read not performed on a snapshot will implicitly use the latest state. Getting support --------------- There are multiple ways you can find help in using LevelDB in Node.js: * **IRC:** you'll find an active group of LevelUP users in the **##leveldb** channel on Freenode, including most of the contributors to this project. * **Mailing list:** there is an active [Node.js LevelDB](https://groups.google.com/forum/#!forum/node-levelup) Google Group. * **GitHub:** you're welcome to open an issue here on this GitHub repository if you have a question. Contributing ------------ LevelDOWN is an **OPEN Open Source Project**. This means that: > Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. See the [contribution guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details. ### Windows A large portion of the Windows support comes from code by [Krzysztof Kowalczyk](http://blog.kowalczyk.info/) [@kjk](https://twitter.com/kjk), see his Windows LevelDB port [here](http://code.google.com/r/kkowalczyk-leveldb/). If you're using LevelUP on Windows, you should give him your thanks! Prebuilt binaries ----------------- LevelDOWN uses `node-pre-gyp` to support prebuilt binaries. For a list of supported prebuilt platform binaries see https://github.com/Level/leveldown/releases License & copyright ------------------- Copyright © 2012-2015 **LevelDOWN** [contributors](https://github.com/level/community#contributors). **LevelDOWN** is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included `LICENSE.md` file for more details. *LevelDOWN builds on the excellent work of the LevelDB and Snappy teams from Google and additional contributors. LevelDB and Snappy are both issued under the [New BSD Licence](http://opensource.org/licenses/BSD-3-Clause).* node-leveldown-1.4.1+dfsg/bench/000077500000000000000000000000001260647373000164455ustar00rootroot00000000000000node-leveldown-1.4.1+dfsg/bench/db-bench-plot.sh000077500000000000000000000041751260647373000214310ustar00rootroot00000000000000#!/bin/sh gnuplot <= options.concurrency || totalWrites > options.num) return inProgress++ if (totalWrites % 100000 === 0) console.log('' + inProgress, totalWrites, Math.round(totalWrites / options.num * 100) + '%') if (totalWrites % 1000 === 0) { elapsed = Date.now() - startTime timesStream.write( elapsed + ',' + totalWrites + ',' + totalBytes + ',' + Math.floor(timesAccum / 1000) + ',' + (Math.floor(((totalBytes / 1048576) / (elapsed / 1000)) * 100) / 100) + '\n') timesAccum = 0 } var time = process.hrtime() db.put(make16CharPaddedKey(), randomString({ length: options.valueSize }), function (err) { if (err) throw err totalBytes += keyTmpl.length + options.valueSize timesAccum += process.hrtime(time)[1] inProgress-- process.nextTick(write) }) } for (var i = 0; i < options.concurrency; i++) write() } setTimeout(function () { db.open({ errorIfExists : false , createIfMissing : true , cacheSize : options.cacheSize << 20 , writeBufferSize : options.writeBufferSize << 20 }, function (err) { if (err) throw err start() }) }, 500) node-leveldown-1.4.1+dfsg/bench/write-random-plot.sh000077500000000000000000000014031260647373000223660ustar00rootroot00000000000000#!/bin/sh gnuplot <= concurrency || totalWrites > entryCount) return var time = process.hrtime() inProgress++ db.put(uuid.v4(), data, function (err) { if (err) throw err writeBuf += (Date.now() - startTime) + ',' + process.hrtime(time)[1] + '\n' inProgress-- process.nextTick(write) }) process.nextTick(write) } write() }) node-leveldown-1.4.1+dfsg/bench/write-sorted-plot.sh000077500000000000000000000012011260647373000224020ustar00rootroot00000000000000#!/bin/sh gnuplot <= concurrency || totalWrites > entryCount) return var time = process.hrtime() inProgress++ db.put(timestamp(), data, function (err) { if (err) throw err writeBuf += (Date.now() - startTime) + ',' + process.hrtime(time)[1] + '\n' inProgress-- process.nextTick(write) }) process.nextTick(write) } write() }) node-leveldown-1.4.1+dfsg/binding.gyp000066400000000000000000000022321260647373000175200ustar00rootroot00000000000000{ "targets": [{ "target_name": "leveldown" , "conditions": [ ["OS == 'win'", { "defines": [ "_HAS_EXCEPTIONS=0" ] , "msvs_settings": { "VCCLCompilerTool": { "RuntimeTypeInfo": "false" , "EnableFunctionLevelLinking": "true" , "ExceptionHandling": "2" , "DisableSpecificWarnings": [ "4355", "4530" ,"4267", "4244", "4506" ] } } }] , ['OS == "linux"', { 'cflags': [ ] , 'cflags!': [ '-fno-tree-vrp' ] }] ] , "dependencies": [ "<(module_root_dir)/deps/leveldb/leveldb.gyp:leveldb" ] , "include_dirs" : [ " (https://github.com/rvagg)", "John Chesley (https://github.com/chesles/)", "Jake Verbaten (https://github.com/raynos)", "Dominic Tarr (https://github.com/dominictarr)", "Max Ogden (https://github.com/maxogden)", "Lars-Magnus Skog (https://github.com/ralphtheninja)", "David Björklund (https://github.com/kesla)", "Julian Gruber (https://github.com/juliangruber)", "Paolo Fragomeni (https://github.com/hij1nx)", "Anton Whalley (https://github.com/No9)", "Matteo Collina (https://github.com/mcollina)", "Pedro Teixeira (https://github.com/pgte)", "James Halliday (https://github.com/substack)" ], "repository": { "type": "git", "url": "https://github.com/level/leveldown.git" }, "homepage": "https://github.com/level/leveldown", "keywords": [ "leveldb", "level" ], "main": "leveldown.js", "dependencies": { "abstract-leveldown": "~2.4.0", "bindings": "~1.2.1", "fast-future": "~1.0.0", "nan": "~2.0.0", "prebuild": "~2.3.3" }, "devDependencies": { "async": "~1.0.0", "delayed": "~1.0.1", "du": "~0.1.0", "faucet": "0.0.1", "mkfiletree": "~0.0.1", "monotonic-timestamp": "~0.0.8", "node-uuid": "~1.4.3", "optimist": "~0.6.1", "readfiletree": "~0.0.1", "rimraf": "~2.2.8", "slump": "~2.0.0", "tape": "~4.0.0" }, "scripts": { "install": "prebuild --download", "test": "tape test/*-test.js | faucet", "prebuild": "prebuild --verbose" }, "license": "MIT", "gypfile": true } node-leveldown-1.4.1+dfsg/src/000077500000000000000000000000001260647373000161555ustar00rootroot00000000000000node-leveldown-1.4.1+dfsg/src/async.h000066400000000000000000000014301260647373000174410ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_ASYNC_H #define LD_ASYNC_H #include #include #include "database.h" namespace leveldown { class Database; /* abstract */ class AsyncWorker : public Nan::AsyncWorker { public: AsyncWorker ( leveldown::Database* database , Nan::Callback *callback ) : Nan::AsyncWorker(callback), database(database) { } protected: void SetStatus(leveldb::Status status) { this->status = status; if (!status.ok()) SetErrorMessage(status.ToString().c_str()); } Database* database; private: leveldb::Status status; }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/batch.cc000066400000000000000000000074571260647373000175620ustar00rootroot00000000000000#include #include #include #include "database.h" #include "batch_async.h" #include "batch.h" #include "common.h" namespace leveldown { static Nan::Persistent batch_constructor; Batch::Batch (leveldown::Database* database, bool sync) : database(database) { options = new leveldb::WriteOptions(); options->sync = sync; batch = new leveldb::WriteBatch(); hasData = false; } Batch::~Batch () { delete options; delete batch; } leveldb::Status Batch::Write () { return database->WriteBatchToDatabase(options, batch); } void Batch::Init () { v8::Local tpl = Nan::New(Batch::New); batch_constructor.Reset(tpl); tpl->SetClassName(Nan::New("Batch").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "put", Batch::Put); Nan::SetPrototypeMethod(tpl, "del", Batch::Del); Nan::SetPrototypeMethod(tpl, "clear", Batch::Clear); Nan::SetPrototypeMethod(tpl, "write", Batch::Write); } NAN_METHOD(Batch::New) { Database* database = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); v8::Local optionsObj; if (info.Length() > 1 && info[1]->IsObject()) { optionsObj = v8::Local::Cast(info[1]); } bool sync = BooleanOptionValue(optionsObj, "sync"); Batch* batch = new Batch(database, sync); batch->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } v8::Local Batch::NewInstance ( v8::Local database , v8::Local optionsObj ) { Nan::EscapableHandleScope scope; v8::Local instance; v8::Local constructorHandle = Nan::New(batch_constructor); if (optionsObj.IsEmpty()) { v8::Local argv[1] = { database }; instance = constructorHandle->GetFunction()->NewInstance(1, argv); } else { v8::Local argv[2] = { database, optionsObj }; instance = constructorHandle->GetFunction()->NewInstance(2, argv); } return scope.Escape(instance); } NAN_METHOD(Batch::Put) { Batch* batch = ObjectWrap::Unwrap(info.Holder()); v8::Local callback; // purely for the error macros v8::Local keyBuffer = info[0]; v8::Local valueBuffer = info[1]; LD_STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, key) LD_STRING_OR_BUFFER_TO_SLICE(value, valueBuffer, value) batch->batch->Put(key, value); if (!batch->hasData) batch->hasData = true; DisposeStringOrBufferFromSlice(keyBuffer, key); DisposeStringOrBufferFromSlice(valueBuffer, value); info.GetReturnValue().Set(info.Holder()); } NAN_METHOD(Batch::Del) { Batch* batch = ObjectWrap::Unwrap(info.Holder()); v8::Local callback; // purely for the error macros v8::Local keyBuffer = info[0]; LD_STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, key) batch->batch->Delete(key); if (!batch->hasData) batch->hasData = true; DisposeStringOrBufferFromSlice(keyBuffer, key); info.GetReturnValue().Set(info.Holder()); } NAN_METHOD(Batch::Clear) { Batch* batch = ObjectWrap::Unwrap(info.Holder()); batch->batch->Clear(); batch->hasData = false; info.GetReturnValue().Set(info.Holder()); } NAN_METHOD(Batch::Write) { Batch* batch = ObjectWrap::Unwrap(info.Holder()); if (batch->hasData) { Nan::Callback *callback = new Nan::Callback(v8::Local::Cast(info[0])); BatchWriteWorker* worker = new BatchWriteWorker(batch, callback); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("batch", _this); Nan::AsyncQueueWorker(worker); } else { LD_RUN_CALLBACK(v8::Local::Cast(info[0]), 0, NULL); } } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/batch.h000066400000000000000000000014271260647373000174130ustar00rootroot00000000000000#ifndef LD_BATCH_H #define LD_BATCH_H #include #include #include #include "database.h" namespace leveldown { class Batch : public Nan::ObjectWrap { public: static void Init(); static v8::Local NewInstance ( v8::Local database , v8::Local optionsObj ); Batch (leveldown::Database* database, bool sync); ~Batch (); leveldb::Status Write (); private: leveldown::Database* database; leveldb::WriteOptions* options; leveldb::WriteBatch* batch; bool hasData; // keep track of whether we're writing data or not static NAN_METHOD(New); static NAN_METHOD(Put); static NAN_METHOD(Del); static NAN_METHOD(Clear); static NAN_METHOD(Write); }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/batch_async.cc000066400000000000000000000011161260647373000207410ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include "batch.h" #include "batch_async.h" namespace leveldown { /** NEXT WORKER **/ BatchWriteWorker::BatchWriteWorker ( Batch* batch , Nan::Callback *callback ) : AsyncWorker(NULL, callback) , batch(batch) {}; BatchWriteWorker::~BatchWriteWorker () {} void BatchWriteWorker::Execute () { SetStatus(batch->Write()); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/batch_async.h000066400000000000000000000011521260647373000206030ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_BATCH_ASYNC_H #define LD_BATCH_ASYNC_H #include #include #include "async.h" #include "batch.h" #include "database.h" namespace leveldown { class BatchWriteWorker : public AsyncWorker { public: BatchWriteWorker ( Batch* batch , Nan::Callback *callback ); virtual ~BatchWriteWorker (); virtual void Execute (); private: Batch* batch; }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/common.h000066400000000000000000000020171260647373000176160ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_COMMON_H #define LD_COMMON_H #include namespace leveldown { NAN_INLINE bool BooleanOptionValue(v8::Local options, const char* _key, bool def = false) { v8::Local key = Nan::New(_key).ToLocalChecked(); return !options.IsEmpty() && options->Has(key) ? options->Get(key)->BooleanValue() : def; } NAN_INLINE uint32_t UInt32OptionValue(v8::Local options, const char* _key, uint32_t def) { v8::Local key = Nan::New(_key).ToLocalChecked(); return !options.IsEmpty() && options->Has(key) && options->Get(key)->IsNumber() ? options->Get(key)->Uint32Value() : def; } } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/database.cc000066400000000000000000000337611260647373000202420ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include #include #include #include "leveldown.h" #include "database.h" #include "async.h" #include "database_async.h" #include "batch.h" #include "iterator.h" #include "common.h" namespace leveldown { static Nan::Persistent database_constructor; Database::Database (const v8::Local& from) : location(new Nan::Utf8String(from)) , db(NULL) , currentIteratorId(0) , pendingCloseWorker(NULL) , blockCache(NULL) , filterPolicy(NULL) {}; Database::~Database () { if (db != NULL) delete db; delete location; }; /* Calls from worker threads, NO V8 HERE *****************************/ leveldb::Status Database::OpenDatabase ( leveldb::Options* options ) { return leveldb::DB::Open(*options, **location, &db); } leveldb::Status Database::PutToDatabase ( leveldb::WriteOptions* options , leveldb::Slice key , leveldb::Slice value ) { return db->Put(*options, key, value); } leveldb::Status Database::GetFromDatabase ( leveldb::ReadOptions* options , leveldb::Slice key , std::string& value ) { return db->Get(*options, key, &value); } leveldb::Status Database::DeleteFromDatabase ( leveldb::WriteOptions* options , leveldb::Slice key ) { return db->Delete(*options, key); } leveldb::Status Database::WriteBatchToDatabase ( leveldb::WriteOptions* options , leveldb::WriteBatch* batch ) { return db->Write(*options, batch); } uint64_t Database::ApproximateSizeFromDatabase (const leveldb::Range* range) { uint64_t size; db->GetApproximateSizes(range, 1, &size); return size; } void Database::GetPropertyFromDatabase ( const leveldb::Slice& property , std::string* value) { db->GetProperty(property, value); } leveldb::Iterator* Database::NewIterator (leveldb::ReadOptions* options) { return db->NewIterator(*options); } const leveldb::Snapshot* Database::NewSnapshot () { return db->GetSnapshot(); } void Database::ReleaseSnapshot (const leveldb::Snapshot* snapshot) { return db->ReleaseSnapshot(snapshot); } void Database::ReleaseIterator (uint32_t id) { // called each time an Iterator is End()ed, in the main thread // we have to remove our reference to it and if it's the last iterator // we have to invoke a pending CloseWorker if there is one // if there is a pending CloseWorker it means that we're waiting for // iterators to end before we can close them iterators.erase(id); if (iterators.empty() && pendingCloseWorker != NULL) { Nan::AsyncQueueWorker((AsyncWorker*)pendingCloseWorker); pendingCloseWorker = NULL; } } void Database::CloseDatabase () { delete db; db = NULL; if (blockCache) { delete blockCache; blockCache = NULL; } if (filterPolicy) { delete filterPolicy; filterPolicy = NULL; } } /* V8 exposed functions *****************************/ NAN_METHOD(LevelDOWN) { v8::Local location = info[0].As(); info.GetReturnValue().Set(Database::NewInstance(location)); } void Database::Init () { v8::Local tpl = Nan::New(Database::New); database_constructor.Reset(tpl); tpl->SetClassName(Nan::New("Database").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "open", Database::Open); Nan::SetPrototypeMethod(tpl, "close", Database::Close); Nan::SetPrototypeMethod(tpl, "put", Database::Put); Nan::SetPrototypeMethod(tpl, "get", Database::Get); Nan::SetPrototypeMethod(tpl, "del", Database::Delete); Nan::SetPrototypeMethod(tpl, "batch", Database::Batch); Nan::SetPrototypeMethod(tpl, "approximateSize", Database::ApproximateSize); Nan::SetPrototypeMethod(tpl, "getProperty", Database::GetProperty); Nan::SetPrototypeMethod(tpl, "iterator", Database::Iterator); } NAN_METHOD(Database::New) { Database* obj = new Database(info[0]); obj->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } v8::Local Database::NewInstance (v8::Local &location) { Nan::EscapableHandleScope scope; v8::Local instance; v8::Local constructorHandle = Nan::New(database_constructor); v8::Local argv[] = { location }; instance = constructorHandle->GetFunction()->NewInstance(1, argv); return scope.Escape(instance); } NAN_METHOD(Database::Open) { LD_METHOD_SETUP_COMMON(open, 0, 1) bool createIfMissing = BooleanOptionValue(optionsObj, "createIfMissing", true); bool errorIfExists = BooleanOptionValue(optionsObj, "errorIfExists"); bool compression = BooleanOptionValue(optionsObj, "compression", true); uint32_t cacheSize = UInt32OptionValue(optionsObj, "cacheSize", 8 << 20); uint32_t writeBufferSize = UInt32OptionValue( optionsObj , "writeBufferSize" , 4 << 20 ); uint32_t blockSize = UInt32OptionValue(optionsObj, "blockSize", 4096); uint32_t maxOpenFiles = UInt32OptionValue(optionsObj, "maxOpenFiles", 1000); uint32_t blockRestartInterval = UInt32OptionValue( optionsObj , "blockRestartInterval" , 16 ); database->blockCache = leveldb::NewLRUCache(cacheSize); database->filterPolicy = leveldb::NewBloomFilterPolicy(10); OpenWorker* worker = new OpenWorker( database , new Nan::Callback(callback) , database->blockCache , database->filterPolicy , createIfMissing , errorIfExists , compression , writeBufferSize , blockSize , maxOpenFiles , blockRestartInterval ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } // for an empty callback to iterator.end() NAN_METHOD(EmptyMethod) { } NAN_METHOD(Database::Close) { LD_METHOD_SETUP_COMMON_ONEARG(close) CloseWorker* worker = new CloseWorker( database , new Nan::Callback(callback) ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); if (!database->iterators.empty()) { // yikes, we still have iterators open! naughty naughty. // we have to queue up a CloseWorker and manually close each of them. // the CloseWorker will be invoked once they are all cleaned up database->pendingCloseWorker = worker; for ( std::map< uint32_t, leveldown::Iterator * >::iterator it = database->iterators.begin() ; it != database->iterators.end() ; ++it) { // for each iterator still open, first check if it's already in // the process of ending (ended==true means an async End() is // in progress), if not, then we call End() with an empty callback // function and wait for it to hit ReleaseIterator() where our // CloseWorker will be invoked leveldown::Iterator *iterator = it->second; if (!iterator->ended) { v8::Local end = v8::Local::Cast(iterator->handle()->Get( Nan::New("end").ToLocalChecked())); v8::Local argv[] = { Nan::New(EmptyMethod)->GetFunction() // empty callback }; Nan::MakeCallback( iterator->handle() , end , 1 , argv ); } } } else { Nan::AsyncQueueWorker(worker); } } NAN_METHOD(Database::Put) { LD_METHOD_SETUP_COMMON(put, 2, 3) v8::Local keyHandle = info[0].As(); v8::Local valueHandle = info[1].As(); LD_STRING_OR_BUFFER_TO_SLICE(key, keyHandle, key); LD_STRING_OR_BUFFER_TO_SLICE(value, valueHandle, value); bool sync = BooleanOptionValue(optionsObj, "sync"); WriteWorker* worker = new WriteWorker( database , new Nan::Callback(callback) , key , value , sync , keyHandle , valueHandle ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } NAN_METHOD(Database::Get) { LD_METHOD_SETUP_COMMON(get, 1, 2) v8::Local keyHandle = info[0].As(); LD_STRING_OR_BUFFER_TO_SLICE(key, keyHandle, key); bool asBuffer = BooleanOptionValue(optionsObj, "asBuffer", true); bool fillCache = BooleanOptionValue(optionsObj, "fillCache", true); ReadWorker* worker = new ReadWorker( database , new Nan::Callback(callback) , key , asBuffer , fillCache , keyHandle ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } NAN_METHOD(Database::Delete) { LD_METHOD_SETUP_COMMON(del, 1, 2) v8::Local keyHandle = info[0].As(); LD_STRING_OR_BUFFER_TO_SLICE(key, keyHandle, key); bool sync = BooleanOptionValue(optionsObj, "sync"); DeleteWorker* worker = new DeleteWorker( database , new Nan::Callback(callback) , key , sync , keyHandle ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } NAN_METHOD(Database::Batch) { if ((info.Length() == 0 || info.Length() == 1) && !info[0]->IsArray()) { v8::Local optionsObj; if (info.Length() > 0 && info[0]->IsObject()) { optionsObj = info[0].As(); } info.GetReturnValue().Set(Batch::NewInstance(info.This(), optionsObj)); return; } LD_METHOD_SETUP_COMMON(batch, 1, 2); bool sync = BooleanOptionValue(optionsObj, "sync"); v8::Local array = v8::Local::Cast(info[0]); leveldb::WriteBatch* batch = new leveldb::WriteBatch(); bool hasData = false; for (unsigned int i = 0; i < array->Length(); i++) { if (!array->Get(i)->IsObject()) continue; v8::Local obj = v8::Local::Cast(array->Get(i)); v8::Local keyBuffer = obj->Get(Nan::New("key").ToLocalChecked()); v8::Local type = obj->Get(Nan::New("type").ToLocalChecked()); if (type->StrictEquals(Nan::New("del").ToLocalChecked())) { LD_STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, key) batch->Delete(key); if (!hasData) hasData = true; DisposeStringOrBufferFromSlice(keyBuffer, key); } else if (type->StrictEquals(Nan::New("put").ToLocalChecked())) { v8::Local valueBuffer = obj->Get(Nan::New("value").ToLocalChecked()); LD_STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, key) LD_STRING_OR_BUFFER_TO_SLICE(value, valueBuffer, value) batch->Put(key, value); if (!hasData) hasData = true; DisposeStringOrBufferFromSlice(keyBuffer, key); DisposeStringOrBufferFromSlice(valueBuffer, value); } } // don't allow an empty batch through if (hasData) { BatchWorker* worker = new BatchWorker( database , new Nan::Callback(callback) , batch , sync ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } else { LD_RUN_CALLBACK(callback, 0, NULL); } } NAN_METHOD(Database::ApproximateSize) { v8::Local startHandle = info[0].As(); v8::Local endHandle = info[1].As(); LD_METHOD_SETUP_COMMON(approximateSize, -1, 2) LD_STRING_OR_BUFFER_TO_SLICE(start, startHandle, start) LD_STRING_OR_BUFFER_TO_SLICE(end, endHandle, end) ApproximateSizeWorker* worker = new ApproximateSizeWorker( database , new Nan::Callback(callback) , start , end , startHandle , endHandle ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("database", _this); Nan::AsyncQueueWorker(worker); } NAN_METHOD(Database::GetProperty) { v8::Local propertyHandle = info[0].As(); v8::Local callback; // for LD_STRING_OR_BUFFER_TO_SLICE LD_STRING_OR_BUFFER_TO_SLICE(property, propertyHandle, property) leveldown::Database* database = Nan::ObjectWrap::Unwrap(info.This()); std::string* value = new std::string(); database->GetPropertyFromDatabase(property, value); v8::Local returnValue = Nan::New(value->c_str(), value->length()).ToLocalChecked(); delete value; delete[] property.data(); info.GetReturnValue().Set(returnValue); } NAN_METHOD(Database::Iterator) { Database* database = Nan::ObjectWrap::Unwrap(info.This()); v8::Local optionsObj; if (info.Length() > 0 && info[0]->IsObject()) { optionsObj = v8::Local::Cast(info[0]); } // each iterator gets a unique id for this Database, so we can // easily store & lookup on our `iterators` map uint32_t id = database->currentIteratorId++; v8::TryCatch try_catch; v8::Local iteratorHandle = Iterator::NewInstance( info.This() , Nan::New(id) , optionsObj ); if (try_catch.HasCaught()) { // NB: node::FatalException can segfault here if there is no room on stack. return Nan::ThrowError("Fatal Error in Database::Iterator!"); } leveldown::Iterator *iterator = Nan::ObjectWrap::Unwrap(iteratorHandle); database->iterators[id] = iterator; // register our iterator /* v8::Local obj = Nan::New(); obj->Set(Nan::New("iterator"), iteratorHandle); Nan::Persistent persistent; persistent.Reset(nan_isolate, obj); database->iterators.insert(std::pair< uint32_t, Nan::Persistent & > (id, persistent)); */ info.GetReturnValue().Set(iteratorHandle); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/database.h000066400000000000000000000055711260647373000201020ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_DATABASE_H #define LD_DATABASE_H #include #include #include #include #include #include #include #include "leveldown.h" #include "iterator.h" namespace leveldown { NAN_METHOD(LevelDOWN); struct Reference { Nan::Persistent handle; leveldb::Slice slice; Reference(v8::Local obj, leveldb::Slice slice) : slice(slice) { v8::Local _obj = Nan::New(); _obj->Set(Nan::New("obj").ToLocalChecked(), obj); handle.Reset(_obj); }; }; static inline void ClearReferences (std::vector *references) { for (std::vector::iterator it = references->begin() ; it != references->end() ; ) { DisposeStringOrBufferFromSlice((*it)->handle, (*it)->slice); it = references->erase(it); } delete references; } class Database : public Nan::ObjectWrap { public: static void Init (); static v8::Local NewInstance (v8::Local &location); leveldb::Status OpenDatabase (leveldb::Options* options); leveldb::Status PutToDatabase ( leveldb::WriteOptions* options , leveldb::Slice key , leveldb::Slice value ); leveldb::Status GetFromDatabase ( leveldb::ReadOptions* options , leveldb::Slice key , std::string& value ); leveldb::Status DeleteFromDatabase ( leveldb::WriteOptions* options , leveldb::Slice key ); leveldb::Status WriteBatchToDatabase ( leveldb::WriteOptions* options , leveldb::WriteBatch* batch ); uint64_t ApproximateSizeFromDatabase (const leveldb::Range* range); void GetPropertyFromDatabase (const leveldb::Slice& property, std::string* value); leveldb::Iterator* NewIterator (leveldb::ReadOptions* options); const leveldb::Snapshot* NewSnapshot (); void ReleaseSnapshot (const leveldb::Snapshot* snapshot); void CloseDatabase (); void ReleaseIterator (uint32_t id); Database (const v8::Local& from); ~Database (); private: Nan::Utf8String* location; leveldb::DB* db; uint32_t currentIteratorId; void(*pendingCloseWorker); leveldb::Cache* blockCache; const leveldb::FilterPolicy* filterPolicy; std::map< uint32_t, leveldown::Iterator * > iterators; static void WriteDoing(uv_work_t *req); static void WriteAfter(uv_work_t *req); static NAN_METHOD(New); static NAN_METHOD(Open); static NAN_METHOD(Close); static NAN_METHOD(Put); static NAN_METHOD(Delete); static NAN_METHOD(Get); static NAN_METHOD(Batch); static NAN_METHOD(Write); static NAN_METHOD(Iterator); static NAN_METHOD(ApproximateSize); static NAN_METHOD(GetProperty); }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/database_async.cc000066400000000000000000000141731260647373000214330ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include #include #include #include "database.h" #include "leveldown.h" #include "async.h" #include "database_async.h" namespace leveldown { /** OPEN WORKER **/ OpenWorker::OpenWorker ( Database *database , Nan::Callback *callback , leveldb::Cache* blockCache , const leveldb::FilterPolicy* filterPolicy , bool createIfMissing , bool errorIfExists , bool compression , uint32_t writeBufferSize , uint32_t blockSize , uint32_t maxOpenFiles , uint32_t blockRestartInterval ) : AsyncWorker(database, callback) { options = new leveldb::Options(); options->block_cache = blockCache; options->filter_policy = filterPolicy; options->create_if_missing = createIfMissing; options->error_if_exists = errorIfExists; options->compression = compression ? leveldb::kSnappyCompression : leveldb::kNoCompression; options->write_buffer_size = writeBufferSize; options->block_size = blockSize; options->max_open_files = maxOpenFiles; options->block_restart_interval = blockRestartInterval; }; OpenWorker::~OpenWorker () { delete options; } void OpenWorker::Execute () { SetStatus(database->OpenDatabase(options)); } /** CLOSE WORKER **/ CloseWorker::CloseWorker ( Database *database , Nan::Callback *callback ) : AsyncWorker(database, callback) {}; CloseWorker::~CloseWorker () {} void CloseWorker::Execute () { database->CloseDatabase(); } void CloseWorker::WorkComplete () { Nan::HandleScope scope; HandleOKCallback(); delete callback; callback = NULL; } /** IO WORKER (abstract) **/ IOWorker::IOWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , v8::Local &keyHandle ) : AsyncWorker(database, callback) , key(key) { Nan::HandleScope scope; SaveToPersistent("key", keyHandle); }; IOWorker::~IOWorker () {} void IOWorker::WorkComplete () { Nan::HandleScope scope; DisposeStringOrBufferFromSlice(GetFromPersistent("key"), key); AsyncWorker::WorkComplete(); } /** READ WORKER **/ ReadWorker::ReadWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , bool asBuffer , bool fillCache , v8::Local &keyHandle ) : IOWorker(database, callback, key, keyHandle) , asBuffer(asBuffer) { Nan::HandleScope scope; options = new leveldb::ReadOptions(); options->fill_cache = fillCache; SaveToPersistent("key", keyHandle); }; ReadWorker::~ReadWorker () { delete options; } void ReadWorker::Execute () { SetStatus(database->GetFromDatabase(options, key, value)); } void ReadWorker::HandleOKCallback () { Nan::HandleScope scope; v8::Local returnValue; if (asBuffer) { //TODO: could use NewBuffer if we carefully manage the lifecycle of `value` //and avoid an an extra allocation. We'd have to clean up properly when not OK //and let the new Buffer manage the data when OK returnValue = Nan::CopyBuffer((char*)value.data(), value.size()).ToLocalChecked(); } else { returnValue = Nan::New((char*)value.data(), value.size()).ToLocalChecked(); } v8::Local argv[] = { Nan::Null() , returnValue }; callback->Call(2, argv); } /** DELETE WORKER **/ DeleteWorker::DeleteWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , bool sync , v8::Local &keyHandle ) : IOWorker(database, callback, key, keyHandle) { Nan::HandleScope scope; options = new leveldb::WriteOptions(); options->sync = sync; SaveToPersistent("key", keyHandle); }; DeleteWorker::~DeleteWorker () { delete options; } void DeleteWorker::Execute () { SetStatus(database->DeleteFromDatabase(options, key)); } /** WRITE WORKER **/ WriteWorker::WriteWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , leveldb::Slice value , bool sync , v8::Local &keyHandle , v8::Local &valueHandle ) : DeleteWorker(database, callback, key, sync, keyHandle) , value(value) { Nan::HandleScope scope; SaveToPersistent("value", valueHandle); }; WriteWorker::~WriteWorker () { } void WriteWorker::Execute () { SetStatus(database->PutToDatabase(options, key, value)); } void WriteWorker::WorkComplete () { Nan::HandleScope scope; DisposeStringOrBufferFromSlice(GetFromPersistent("value"), value); IOWorker::WorkComplete(); } /** BATCH WORKER **/ BatchWorker::BatchWorker ( Database *database , Nan::Callback *callback , leveldb::WriteBatch* batch , bool sync ) : AsyncWorker(database, callback) , batch(batch) { options = new leveldb::WriteOptions(); options->sync = sync; }; BatchWorker::~BatchWorker () { delete batch; delete options; } void BatchWorker::Execute () { SetStatus(database->WriteBatchToDatabase(options, batch)); } /** APPROXIMATE SIZE WORKER **/ ApproximateSizeWorker::ApproximateSizeWorker ( Database *database , Nan::Callback *callback , leveldb::Slice start , leveldb::Slice end , v8::Local &startHandle , v8::Local &endHandle ) : AsyncWorker(database, callback) , range(start, end) { Nan::HandleScope scope; SaveToPersistent("start", startHandle); SaveToPersistent("end", endHandle); }; ApproximateSizeWorker::~ApproximateSizeWorker () {} void ApproximateSizeWorker::Execute () { size = database->ApproximateSizeFromDatabase(&range); } void ApproximateSizeWorker::WorkComplete() { Nan::HandleScope scope; DisposeStringOrBufferFromSlice(GetFromPersistent("start"), range.start); DisposeStringOrBufferFromSlice(GetFromPersistent("end"), range.limit); AsyncWorker::WorkComplete(); } void ApproximateSizeWorker::HandleOKCallback () { Nan::HandleScope scope; v8::Local returnValue = Nan::New((double) size); v8::Local argv[] = { Nan::Null() , returnValue }; callback->Call(2, argv); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/database_async.h000066400000000000000000000063111260647373000212700ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_DATABASE_ASYNC_H #define LD_DATABASE_ASYNC_H #include #include #include #include "async.h" namespace leveldown { class OpenWorker : public AsyncWorker { public: OpenWorker ( Database *database , Nan::Callback *callback , leveldb::Cache* blockCache , const leveldb::FilterPolicy* filterPolicy , bool createIfMissing , bool errorIfExists , bool compression , uint32_t writeBufferSize , uint32_t blockSize , uint32_t maxOpenFiles , uint32_t blockRestartInterval ); virtual ~OpenWorker (); virtual void Execute (); private: leveldb::Options* options; }; class CloseWorker : public AsyncWorker { public: CloseWorker ( Database *database , Nan::Callback *callback ); virtual ~CloseWorker (); virtual void Execute (); virtual void WorkComplete (); }; class IOWorker : public AsyncWorker { public: IOWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , v8::Local &keyHandle ); virtual ~IOWorker (); virtual void WorkComplete (); protected: leveldb::Slice key; }; class ReadWorker : public IOWorker { public: ReadWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , bool asBuffer , bool fillCache , v8::Local &keyHandle ); virtual ~ReadWorker (); virtual void Execute (); virtual void HandleOKCallback (); private: bool asBuffer; leveldb::ReadOptions* options; std::string value; }; class DeleteWorker : public IOWorker { public: DeleteWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , bool sync , v8::Local &keyHandle ); virtual ~DeleteWorker (); virtual void Execute (); protected: leveldb::WriteOptions* options; }; class WriteWorker : public DeleteWorker { public: WriteWorker ( Database *database , Nan::Callback *callback , leveldb::Slice key , leveldb::Slice value , bool sync , v8::Local &keyHandle , v8::Local &valueHandle ); virtual ~WriteWorker (); virtual void Execute (); virtual void WorkComplete (); private: leveldb::Slice value; }; class BatchWorker : public AsyncWorker { public: BatchWorker ( Database *database , Nan::Callback *callback , leveldb::WriteBatch* batch , bool sync ); virtual ~BatchWorker (); virtual void Execute (); private: leveldb::WriteOptions* options; leveldb::WriteBatch* batch; }; class ApproximateSizeWorker : public AsyncWorker { public: ApproximateSizeWorker ( Database *database , Nan::Callback *callback , leveldb::Slice start , leveldb::Slice end , v8::Local &startHandle , v8::Local &endHandle ); virtual ~ApproximateSizeWorker (); virtual void Execute (); virtual void HandleOKCallback (); virtual void WorkComplete (); private: leveldb::Range range; uint64_t size; }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/iterator.cc000066400000000000000000000337621260647373000203300ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include #include "database.h" #include "iterator.h" #include "iterator_async.h" #include "common.h" namespace leveldown { static Nan::Persistent iterator_constructor; Iterator::Iterator ( Database* database , uint32_t id , leveldb::Slice* start , std::string* end , bool reverse , bool keys , bool values , int limit , std::string* lt , std::string* lte , std::string* gt , std::string* gte , bool fillCache , bool keyAsBuffer , bool valueAsBuffer , v8::Local &startHandle , size_t highWaterMark ) : database(database) , id(id) , start(start) , end(end) , reverse(reverse) , keys(keys) , values(values) , limit(limit) , lt(lt) , lte(lte) , gt(gt) , gte(gte) , highWaterMark(highWaterMark) , keyAsBuffer(keyAsBuffer) , valueAsBuffer(valueAsBuffer) { Nan::HandleScope scope; v8::Local obj = Nan::New(); if (!startHandle.IsEmpty()) obj->Set(Nan::New("start").ToLocalChecked(), startHandle); persistentHandle.Reset(obj); options = new leveldb::ReadOptions(); options->fill_cache = fillCache; // get a snapshot of the current state options->snapshot = database->NewSnapshot(); dbIterator = NULL; count = 0; seeking = false; nexting = false; ended = false; endWorker = NULL; }; Iterator::~Iterator () { delete options; if (!persistentHandle.IsEmpty()) persistentHandle.Reset(); if (start != NULL) delete start; if (end != NULL) delete end; }; bool Iterator::GetIterator () { if (dbIterator == NULL) { dbIterator = database->NewIterator(options); if (start != NULL) { dbIterator->Seek(*start); if (reverse) { if (!dbIterator->Valid()) { // if it's past the last key, step back dbIterator->SeekToLast(); } else { std::string key_ = dbIterator->key().ToString(); if (lt != NULL) { if (lt->compare(key_) <= 0) dbIterator->Prev(); } else if (lte != NULL) { if (lte->compare(key_) < 0) dbIterator->Prev(); } else if (start != NULL) { if (start->compare(key_)) dbIterator->Prev(); } } if (dbIterator->Valid() && lt != NULL) { if (lt->compare(dbIterator->key().ToString()) <= 0) dbIterator->Prev(); } } else { if (dbIterator->Valid() && gt != NULL && gt->compare(dbIterator->key().ToString()) == 0) dbIterator->Next(); } } else if (reverse) { dbIterator->SeekToLast(); } else { dbIterator->SeekToFirst(); } return true; } return false; } bool Iterator::Read (std::string& key, std::string& value) { // if it's not the first call, move to next item. if (!GetIterator() && !seeking) { if (reverse) dbIterator->Prev(); else dbIterator->Next(); } seeking = false; // now check if this is the end or not, if not then return the key & value if (dbIterator->Valid()) { std::string key_ = dbIterator->key().ToString(); int isEnd = end == NULL ? 1 : end->compare(key_); if ((limit < 0 || ++count <= limit) && (end == NULL || (reverse && (isEnd <= 0)) || (!reverse && (isEnd >= 0))) && ( lt != NULL ? (lt->compare(key_) > 0) : lte != NULL ? (lte->compare(key_) >= 0) : true ) && ( gt != NULL ? (gt->compare(key_) < 0) : gte != NULL ? (gte->compare(key_) <= 0) : true ) ) { if (keys) key.assign(dbIterator->key().data(), dbIterator->key().size()); if (values) value.assign(dbIterator->value().data(), dbIterator->value().size()); return true; } } return false; } bool Iterator::IteratorNext (std::vector >& result) { size_t size = 0; while(true) { std::string key, value; bool ok = Read(key, value); if (ok) { result.push_back(std::make_pair(key, value)); size = size + key.size() + value.size(); if (size > highWaterMark) return true; } else { return false; } } } leveldb::Status Iterator::IteratorStatus () { return dbIterator->status(); } void Iterator::IteratorEnd () { //TODO: could return it->status() delete dbIterator; dbIterator = NULL; } void Iterator::Release () { database->ReleaseIterator(id); } void checkEndCallback (Iterator* iterator) { iterator->nexting = false; if (iterator->endWorker != NULL) { Nan::AsyncQueueWorker(iterator->endWorker); iterator->endWorker = NULL; } } NAN_METHOD(Iterator::Seek) { Iterator* iterator = Nan::ObjectWrap::Unwrap(info.This()); iterator->GetIterator(); leveldb::Iterator* dbIterator = iterator->dbIterator; Nan::Utf8String key(info[0]); dbIterator->Seek(*key); iterator->seeking = true; if (dbIterator->Valid()) { int cmp = dbIterator->key().compare(*key); if (cmp > 0 && iterator->reverse) { dbIterator->Prev(); } else if (cmp < 0 && !iterator->reverse) { dbIterator->Next(); } } else { if (iterator->reverse) { dbIterator->SeekToLast(); } else { dbIterator->SeekToFirst(); } if (dbIterator->Valid()) { int cmp = dbIterator->key().compare(*key); if (cmp > 0 && iterator->reverse) { dbIterator->SeekToFirst(); dbIterator->Prev(); } else if (cmp < 0 && !iterator->reverse) { dbIterator->SeekToLast(); dbIterator->Next(); } } } info.GetReturnValue().Set(info.Holder()); } NAN_METHOD(Iterator::Next) { Iterator* iterator = Nan::ObjectWrap::Unwrap(info.This()); if (!info[0]->IsFunction()) { return Nan::ThrowError("next() requires a callback argument"); } v8::Local callback = info[0].As(); NextWorker* worker = new NextWorker( iterator , new Nan::Callback(callback) , checkEndCallback ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("iterator", _this); iterator->nexting = true; Nan::AsyncQueueWorker(worker); info.GetReturnValue().Set(info.Holder()); } NAN_METHOD(Iterator::End) { Iterator* iterator = Nan::ObjectWrap::Unwrap(info.This()); if (!info[0]->IsFunction()) { return Nan::ThrowError("end() requires a callback argument"); } if (!iterator->ended) { v8::Local callback = v8::Local::Cast(info[0]); EndWorker* worker = new EndWorker( iterator , new Nan::Callback(callback) ); // persist to prevent accidental GC v8::Local _this = info.This(); worker->SaveToPersistent("iterator", _this); iterator->ended = true; if (iterator->nexting) { // waiting for a next() to return, queue the end iterator->endWorker = worker; } else { Nan::AsyncQueueWorker(worker); } } info.GetReturnValue().Set(info.Holder()); } void Iterator::Init () { v8::Local tpl = Nan::New(Iterator::New); iterator_constructor.Reset(tpl); tpl->SetClassName(Nan::New("Iterator").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Nan::SetPrototypeMethod(tpl, "seek", Iterator::Seek); Nan::SetPrototypeMethod(tpl, "next", Iterator::Next); Nan::SetPrototypeMethod(tpl, "end", Iterator::End); } v8::Local Iterator::NewInstance ( v8::Local database , v8::Local id , v8::Local optionsObj ) { Nan::EscapableHandleScope scope; v8::Local instance; v8::Local constructorHandle = Nan::New(iterator_constructor); if (optionsObj.IsEmpty()) { v8::Local argv[2] = { database, id }; instance = constructorHandle->GetFunction()->NewInstance(2, argv); } else { v8::Local argv[3] = { database, id, optionsObj }; instance = constructorHandle->GetFunction()->NewInstance(3, argv); } return scope.Escape(instance); } NAN_METHOD(Iterator::New) { Database* database = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); //TODO: remove this, it's only here to make LD_STRING_OR_BUFFER_TO_SLICE happy v8::Local callback; v8::Local startHandle; leveldb::Slice* start = NULL; std::string* end = NULL; int limit = -1; // default highWaterMark from Readble-streams size_t highWaterMark = 16 * 1024; v8::Local id = info[1]; v8::Local optionsObj; v8::Local ltHandle; v8::Local lteHandle; v8::Local gtHandle; v8::Local gteHandle; std::string* lt = NULL; std::string* lte = NULL; std::string* gt = NULL; std::string* gte = NULL; //default to forward. bool reverse = false; if (info.Length() > 1 && info[2]->IsObject()) { optionsObj = v8::Local::Cast(info[2]); reverse = BooleanOptionValue(optionsObj, "reverse"); if (optionsObj->Has(Nan::New("start").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("start").ToLocalChecked())) || optionsObj->Get(Nan::New("start").ToLocalChecked())->IsString())) { startHandle = optionsObj->Get(Nan::New("start").ToLocalChecked()).As(); // 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 (optionsObj->Has(Nan::New("end").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("end").ToLocalChecked())) || optionsObj->Get(Nan::New("end").ToLocalChecked())->IsString())) { v8::Local endBuffer = optionsObj->Get(Nan::New("end").ToLocalChecked()); // 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()); } } if (!optionsObj.IsEmpty() && optionsObj->Has(Nan::New("limit").ToLocalChecked())) { limit = v8::Local::Cast(optionsObj->Get( Nan::New("limit").ToLocalChecked()))->Value(); } if (optionsObj->Has(Nan::New("highWaterMark").ToLocalChecked())) { highWaterMark = v8::Local::Cast(optionsObj->Get( Nan::New("highWaterMark").ToLocalChecked()))->Value(); } if (optionsObj->Has(Nan::New("lt").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("lt").ToLocalChecked())) || optionsObj->Get(Nan::New("lt").ToLocalChecked())->IsString())) { v8::Local ltBuffer = optionsObj->Get(Nan::New("lt").ToLocalChecked()); // 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()); if (reverse) start = new leveldb::Slice(_lt.data(), _lt.size()); } } if (optionsObj->Has(Nan::New("lte").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("lte").ToLocalChecked())) || optionsObj->Get(Nan::New("lte").ToLocalChecked())->IsString())) { v8::Local lteBuffer = optionsObj->Get(Nan::New("lte").ToLocalChecked()); // 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()); if (reverse) start = new leveldb::Slice(_lte.data(), _lte.size()); } } if (optionsObj->Has(Nan::New("gt").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("gt").ToLocalChecked())) || optionsObj->Get(Nan::New("gt").ToLocalChecked())->IsString())) { v8::Local gtBuffer = optionsObj->Get(Nan::New("gt").ToLocalChecked()); // 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()); if (!reverse) start = new leveldb::Slice(_gt.data(), _gt.size()); } } if (optionsObj->Has(Nan::New("gte").ToLocalChecked()) && (node::Buffer::HasInstance(optionsObj->Get(Nan::New("gte").ToLocalChecked())) || optionsObj->Get(Nan::New("gte").ToLocalChecked())->IsString())) { v8::Local gteBuffer = optionsObj->Get(Nan::New("gte").ToLocalChecked()); // 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()); if (!reverse) start = new leveldb::Slice(_gte.data(), _gte.size()); } } } bool keys = BooleanOptionValue(optionsObj, "keys", true); bool values = BooleanOptionValue(optionsObj, "values", true); bool keyAsBuffer = BooleanOptionValue(optionsObj, "keyAsBuffer", true); bool valueAsBuffer = BooleanOptionValue(optionsObj, "valueAsBuffer", true); bool fillCache = BooleanOptionValue(optionsObj, "fillCache"); Iterator* iterator = new Iterator( database , (uint32_t)id->Int32Value() , start , end , reverse , keys , values , limit , lt , lte , gt , gte , fillCache , keyAsBuffer , valueAsBuffer , startHandle , highWaterMark ); iterator->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/iterator.h000066400000000000000000000036561260647373000201710ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_ITERATOR_H #define LD_ITERATOR_H #include #include #include #include "leveldown.h" #include "database.h" #include "async.h" namespace leveldown { class Database; class AsyncWorker; class Iterator : public Nan::ObjectWrap { public: static void Init (); static v8::Local NewInstance ( v8::Local database , v8::Local id , v8::Local optionsObj ); Iterator ( Database* database , uint32_t id , leveldb::Slice* start , std::string* end , bool reverse , bool keys , bool values , int limit , std::string* lt , std::string* lte , std::string* gt , std::string* gte , bool fillCache , bool keyAsBuffer , bool valueAsBuffer , v8::Local &startHandle , size_t highWaterMark ); ~Iterator (); bool IteratorNext (std::vector >& result); leveldb::Status IteratorStatus (); void IteratorEnd (); void Release (); private: Database* database; uint32_t id; leveldb::Iterator* dbIterator; leveldb::ReadOptions* options; leveldb::Slice* start; std::string* end; bool seeking; bool reverse; bool keys; bool values; int limit; std::string* lt; std::string* lte; std::string* gt; std::string* gte; int count; size_t highWaterMark; public: bool keyAsBuffer; bool valueAsBuffer; bool nexting; bool ended; AsyncWorker* endWorker; private: Nan::Persistent persistentHandle; bool Read (std::string& key, std::string& value); bool GetIterator (); static NAN_METHOD(New); static NAN_METHOD(Seek); static NAN_METHOD(Next); static NAN_METHOD(End); }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/iterator_async.cc000066400000000000000000000052121260647373000215120ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include #include "database.h" #include "leveldown.h" #include "async.h" #include "iterator_async.h" namespace leveldown { /** NEXT-MULTI WORKER **/ NextWorker::NextWorker ( Iterator* iterator , Nan::Callback *callback , void (*localCallback)(Iterator*) ) : AsyncWorker(NULL, callback) , iterator(iterator) , localCallback(localCallback) {}; NextWorker::~NextWorker () {} void NextWorker::Execute () { ok = iterator->IteratorNext(result); if (!ok) SetStatus(iterator->IteratorStatus()); } void NextWorker::HandleOKCallback () { size_t idx = 0; size_t arraySize = result.size() * 2; v8::Local returnArray = Nan::New(arraySize); for(idx = 0; idx < result.size(); ++idx) { std::pair row = result[idx]; std::string key = row.first; std::string value = row.second; v8::Local returnKey; if (iterator->keyAsBuffer) { //TODO: use NewBuffer, see database_async.cc returnKey = Nan::CopyBuffer((char*)key.data(), key.size()).ToLocalChecked(); } else { returnKey = Nan::New((char*)key.data(), key.size()).ToLocalChecked(); } v8::Local returnValue; if (iterator->valueAsBuffer) { //TODO: use NewBuffer, see database_async.cc returnValue = Nan::CopyBuffer((char*)value.data(), value.size()).ToLocalChecked(); } else { returnValue = Nan::New((char*)value.data(), value.size()).ToLocalChecked(); } // put the key & value in a descending order, so that they can be .pop:ed in javascript-land returnArray->Set(Nan::New(static_cast(arraySize - idx * 2 - 1)), returnKey); returnArray->Set(Nan::New(static_cast(arraySize - idx * 2 - 2)), returnValue); } // clean up & handle the next/end state see iterator.cc/checkEndCallback localCallback(iterator); v8::Local argv[] = { Nan::Null() , returnArray // when ok === false all data has been read, so it's then finished , Nan::New(!ok) }; callback->Call(3, argv); } /** END WORKER **/ EndWorker::EndWorker ( Iterator* iterator , Nan::Callback *callback ) : AsyncWorker(NULL, callback) , iterator(iterator) {}; EndWorker::~EndWorker () { } void EndWorker::Execute () { iterator->IteratorEnd(); } void EndWorker::HandleOKCallback () { iterator->Release(); callback->Call(0, NULL); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/iterator_async.h000066400000000000000000000020031260647373000213470ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_ITERATOR_ASYNC_H #define LD_ITERATOR_ASYNC_H #include #include #include "async.h" #include "iterator.h" namespace leveldown { class NextWorker : public AsyncWorker { public: NextWorker ( Iterator* iterator , Nan::Callback *callback , void (*localCallback)(Iterator*) ); virtual ~NextWorker (); virtual void Execute (); virtual void HandleOKCallback (); private: Iterator* iterator; void (*localCallback)(Iterator*); std::vector > result; bool ok; }; class EndWorker : public AsyncWorker { public: EndWorker ( Iterator* iterator , Nan::Callback *callback ); virtual ~EndWorker (); virtual void Execute (); virtual void HandleOKCallback (); private: Iterator* iterator; }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/src/leveldown.cc000066400000000000000000000032301260647373000204610ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include "leveldown.h" #include "database.h" #include "iterator.h" #include "batch.h" #include "leveldown_async.h" namespace leveldown { NAN_METHOD(DestroyDB) { Nan::HandleScope scope; Nan::Utf8String* location = new Nan::Utf8String(info[0]); Nan::Callback* callback = new Nan::Callback( v8::Local::Cast(info[1])); DestroyWorker* worker = new DestroyWorker( location , callback ); Nan::AsyncQueueWorker(worker); info.GetReturnValue().SetUndefined(); } NAN_METHOD(RepairDB) { Nan::HandleScope scope; Nan::Utf8String* location = new Nan::Utf8String(info[0]); Nan::Callback* callback = new Nan::Callback( v8::Local::Cast(info[1])); RepairWorker* worker = new RepairWorker( location , callback ); Nan::AsyncQueueWorker(worker); info.GetReturnValue().SetUndefined(); } void Init (v8::Local target) { Database::Init(); leveldown::Iterator::Init(); leveldown::Batch::Init(); v8::Local leveldown = Nan::New(LevelDOWN)->GetFunction(); leveldown->Set( Nan::New("destroy").ToLocalChecked() , Nan::New(DestroyDB)->GetFunction() ); leveldown->Set( Nan::New("repair").ToLocalChecked() , Nan::New(RepairDB)->GetFunction() ); target->Set(Nan::New("leveldown").ToLocalChecked(), leveldown); } NODE_MODULE(leveldown, Init) } // namespace leveldown node-leveldown-1.4.1+dfsg/src/leveldown.h000066400000000000000000000132721260647373000203320ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_LEVELDOWN_H #define LD_LEVELDOWN_H #include #include #include #include static inline size_t StringOrBufferLength(v8::Local obj) { Nan::HandleScope scope; return (!obj->ToObject().IsEmpty() && node::Buffer::HasInstance(obj->ToObject())) ? node::Buffer::Length(obj->ToObject()) : obj->ToString()->Utf8Length(); } // NOTE: this MUST be called on objects created by // LD_STRING_OR_BUFFER_TO_SLICE static inline void DisposeStringOrBufferFromSlice( Nan::Persistent &handle , leveldb::Slice slice) { Nan::HandleScope scope; if (!slice.empty()) { v8::Local obj = Nan::New(handle)->Get(Nan::New("obj").ToLocalChecked()); if (!node::Buffer::HasInstance(obj)) delete[] slice.data(); } handle.Reset(); } static inline void DisposeStringOrBufferFromSlice( v8::Local handle , leveldb::Slice slice) { if (!slice.empty() && !node::Buffer::HasInstance(handle)) delete[] slice.data(); } // NOTE: must call DisposeStringOrBufferFromSlice() on objects created here #define LD_STRING_OR_BUFFER_TO_SLICE(to, from, name) \ size_t to ## Sz_; \ char* to ## Ch_; \ if (from->IsNull() || from->IsUndefined()) { \ to ## Sz_ = 0; \ to ## Ch_ = 0; \ } else if (!from->ToObject().IsEmpty() \ && node::Buffer::HasInstance(from->ToObject())) { \ to ## Sz_ = node::Buffer::Length(from->ToObject()); \ to ## Ch_ = node::Buffer::Data(from->ToObject()); \ } else { \ v8::Local 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 \ ); \ } \ leveldb::Slice to(to ## Ch_, to ## Sz_); #define LD_RETURN_CALLBACK_OR_ERROR(callback, msg) \ if (!callback.IsEmpty() && callback->IsFunction()) { \ v8::Local argv[] = { \ Nan::Error(msg) \ }; \ LD_RUN_CALLBACK(callback, 1, argv) \ info.GetReturnValue().SetUndefined(); \ return; \ } \ return Nan::ThrowError(msg); #define LD_RUN_CALLBACK(callback, argc, argv) \ Nan::MakeCallback( \ Nan::GetCurrentContext()->Global(), callback, argc, argv); /* LD_METHOD_SETUP_COMMON setup the following objects: * - Database* database * - v8::Local optionsObj (may be empty) * - Nan::Persistent callback (won't be empty) * Will throw/return if there isn't a callback in arg 0 or 1 */ #define LD_METHOD_SETUP_COMMON(name, optionPos, callbackPos) \ if (info.Length() == 0) \ return Nan::ThrowError(#name "() requires a callback argument"); \ leveldown::Database* database = \ Nan::ObjectWrap::Unwrap(info.This()); \ v8::Local optionsObj; \ v8::Local callback; \ if (optionPos == -1 && info[callbackPos]->IsFunction()) { \ callback = info[callbackPos].As(); \ } else if (optionPos != -1 && info[callbackPos - 1]->IsFunction()) { \ callback = info[callbackPos - 1].As(); \ } else if (optionPos != -1 \ && info[optionPos]->IsObject() \ && info[callbackPos]->IsFunction()) { \ optionsObj = info[optionPos].As(); \ callback = info[callbackPos].As(); \ } else { \ return Nan::ThrowError(#name "() requires a callback argument"); \ } #define LD_METHOD_SETUP_COMMON_ONEARG(name) LD_METHOD_SETUP_COMMON(name, -1, 0) #endif node-leveldown-1.4.1+dfsg/src/leveldown_async.cc000066400000000000000000000017621260647373000216660ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #include #include "leveldown.h" #include "leveldown_async.h" namespace leveldown { /** DESTROY WORKER **/ DestroyWorker::DestroyWorker ( Nan::Utf8String* location , Nan::Callback *callback ) : AsyncWorker(NULL, callback) , location(location) {}; DestroyWorker::~DestroyWorker () { delete location; } void DestroyWorker::Execute () { leveldb::Options options; SetStatus(leveldb::DestroyDB(**location, options)); } /** REPAIR WORKER **/ RepairWorker::RepairWorker ( Nan::Utf8String* location , Nan::Callback *callback ) : AsyncWorker(NULL, callback) , location(location) {}; RepairWorker::~RepairWorker () { delete location; } void RepairWorker::Execute () { leveldb::Options options; SetStatus(leveldb::RepairDB(**location, options)); } } // namespace leveldown node-leveldown-1.4.1+dfsg/src/leveldown_async.h000066400000000000000000000014621260647373000215250ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelDOWN contributors * See list at * MIT License */ #ifndef LD_LEVELDOWN_ASYNC_H #define LD_LEVELDOWN_ASYNC_H #include #include "async.h" namespace leveldown { class DestroyWorker : public AsyncWorker { public: DestroyWorker ( Nan::Utf8String* location , Nan::Callback *callback ); virtual ~DestroyWorker (); virtual void Execute (); private: Nan::Utf8String* location; }; class RepairWorker : public AsyncWorker { public: RepairWorker ( Nan::Utf8String* location , Nan::Callback *callback ); virtual ~RepairWorker (); virtual void Execute (); private: Nan::Utf8String* location; }; } // namespace leveldown #endif node-leveldown-1.4.1+dfsg/test/000077500000000000000000000000001260647373000163455ustar00rootroot00000000000000node-leveldown-1.4.1+dfsg/test/approximate-size-test.js000066400000000000000000000003741260647373000231650ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/approximate-size-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/batch-test.js000066400000000000000000000003611260647373000207410ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/batch-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/chained-batch-test.js000066400000000000000000000003711260647373000223330ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/chained-batch-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/cleanup-hanging-iterators-test.js000066400000000000000000000031531260647373000247340ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , makeTest = require('./make') makeTest('test ended iterator', function (db, t, done) { // standard iterator with an end() properly called, easy var it = db.iterator({ keyAsBuffer: false, valueAsBuffer: false }) it.next(function (err, key, value) { t.notOk(err, 'no error from next()') t.equal(key, 'one', 'correct key') t.equal(value, '1', 'correct value') it.end(function (err) { t.notOk(err, 'no error from next()') done() }) }) }) makeTest('test non-ended iterator', function (db, t, done) { // no end() call on our iterator, cleanup should crash Node if not handled properly var it = db.iterator({ keyAsBuffer: false, valueAsBuffer: false }) it.next(function (err, key, value) { t.notOk(err, 'no error from next()') t.equal(key, 'one', 'correct key') t.equal(value, '1', 'correct value') done() }) }) makeTest('test multiple non-ended iterators', function (db, t, done) { // no end() call on our iterator, cleanup should crash Node if not handled properly db.iterator() db.iterator().next(function () {}) db.iterator().next(function () {}) db.iterator().next(function () {}) setTimeout(done, 50) }) makeTest('test ending iterators', function (db, t, done) { // at least one end() should be in progress when we try to close the db var it1 = db.iterator().next(function () { it1.end(function () {}) }) , it2 = db.iterator().next(function () { it2.end(function () {}) done() }) }) node-leveldown-1.4.1+dfsg/test/close-test.js000066400000000000000000000011011260647373000207560ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/close-test') module.exports.setUp = function () { test('setUp', testCommon.setUp) } module.exports.close = abstract.close module.exports.tearDown = function () { test('tearDown', testCommon.tearDown) } module.exports.all = function (leveldown) { module.exports.setUp() module.exports.close(leveldown, test, testCommon) module.exports.tearDown() } module.exports.all(leveldown) node-leveldown-1.4.1+dfsg/test/compression-test.js000066400000000000000000000061061260647373000222240ustar00rootroot00000000000000/* Copyright (c) 2012-2015 LevelUP contributors * See list at * MIT License */ var async = require('async') , du = require('du') , delayed = require('delayed') , common = require('abstract-leveldown/testCommon') , leveldown = require('../') , test = require('tape') , compressableData = new Buffer(Array.apply(null, Array(1024 * 100)).map(function () { return 'aaaaaaaaaa' }).join('')) , multiples = 10 , dataSize = compressableData.length * multiples , verify = function (location, compression, t) { du(location, function (err, size) { t.error(err) if (compression) t.ok(size < dataSize, 'on-disk size (' + size + ') is less than data size (' + dataSize + ')') else t.ok(size >= dataSize, 'on-disk size (' + size + ') is greater than data size (' + dataSize + ')') t.end() }) } // close, open, close again.. 'compaction' is also performed on open()s , cycle = function (db, compression, t, callback) { var location = db.location db.close(function (err) { t.error(err) db = leveldown(location) db.open({ errorIfExists: false, compression: compression }, function () { t.error(err) db.close(function (err) { t.error(err) callback() }) }) }) } test('Compression', function (t) { t.test('set up', common.setUp) t.test('test data is compressed by default (db.put())', function (t) { var db = leveldown(common.location()) db.open(function (err) { t.error(err) async.forEach( Array.apply(null, Array(multiples)).map(function (e, i) { return [ i, compressableData ] }) , function (args, callback) { db.put.apply(db, args.concat([callback])) } , cycle.bind(null, db, true, t, delayed.delayed(verify.bind(null, db.location, true, t), 0.01)) ) }) }) t.test('test data is not compressed with compression=false on open() (db.put())', function (t) { var db = leveldown(common.location()) db.open({ compression: false }, function (err) { t.error(err) async.forEach( Array.apply(null, Array(multiples)).map(function (e, i) { return [ i, compressableData ] }) , function (args, callback) { db.put.apply(db, args.concat([callback])) } , cycle.bind(null, db, false, t, delayed.delayed(verify.bind(null, db.location, false, t), 0.01)) ) }) }) t.test('test data is compressed by default (db.batch())', function (t) { var db = leveldown(common.location()) db.open(function (err) { t.error(err) db.batch( Array.apply(null, Array(multiples)).map(function (e, i) { return { type: 'put', key: i, value: compressableData } }) , cycle.bind(null, db, false, t, delayed.delayed(verify.bind(null, db.location, false, t), 0.01)) ) }) }) }) node-leveldown-1.4.1+dfsg/test/data/000077500000000000000000000000001260647373000172565ustar00rootroot00000000000000node-leveldown-1.4.1+dfsg/test/data/testdata.bin000066400000000000000000000111201260647373000215540ustar00rootroot00000000000000PNG  IHDR@<WLVtEXtSoftwareAdobe ImageReadyqe<$iTXtXML:com.adobe.xmp g|1PLTE/,菫ۙUvNLKs.uiYI͉-*0Gpm2/+Gy.tDɾD%ye'yyzHess5h{ب|"0u AX4!jjGp2gMlrwp XyifcaI0WjV*[]ft7e{pxt;XUSNziH$yڂXeܩI-LWҁ]ylSlxr/Va bAVѤ8i͏KIrDGxIZuHtB&"!iwD(KTX^YR.\jlĄҊk[U: Ѓ9vtq@;8֘"g:M  Pm5D᲻t*426Xxc>nJa  llk ߱Nw|Vَ fB%awFCc]LZy1(7%CmMo_:LtRNSS% IDATxڔ TSWHx?#H acrC1 R%LMK"D F,M)R *B3Lg-)̹uVrswC~Vm7v_idގ=L+0ٳ5Cxpt=Lmo<.hC{j@{zEWn<`YJs=ڑLiOsw{mmcϱ=ٽZ,)Yb|+c|b}J+qݏr|{/N'h ;ZTw|fiiyݤO, _ 7-nwY`W6oo7o/-ҕ:PCvE:p?_ٵkMK\ >RБ-k M_nܸb">t@_`7wmΦM;QWiobbe%W$ ػPʝ 8%,雍6ܨ*n ʄ0ׁ~~@ꯋ𳜋7z\LXkmy2E/{&KNˀYH-uh†ŭwk8|LBLL¿-}h_(Y4^t(F}q=M@IFl- g[AT$}98 zB22iZuеZLjrT|j|{?S*ԄR,% F 0  ઙje Tb,m}_u&DT*` *~m0ND5e}^vDH>jS_5124 z,[gϸQQUnbЫ^[9]lzfS=; { `Fc-$j$r*_f 뎖LqYmʎqƝQ n2CN7\;b@|]ī) I2.5d>up%n *j3 . OL1m@] dOTvY;ӕÑ]wZjjIFS&&b]3(Hj*QRS 4˪ZTTO'({ h FBc((AnRXIpik.ډN`*@N\G㈶>2L'~ۯI5 Ӹ\.@AP(u?ŝڒśR욝l"vT$R2f|\aYc5‹'#aع>u7JN""2YB&i;QlA5 :R]KJyyˋ[5-0vۣPGf)p6;}8,└a;f;wTwc]h!$Sz8mv+.bFrJ+$]Te{~YF8<0Wjdqr)Iyŝů&l(MwʜLEa:U’"K9Q 3, 'leveldb.stats has > 3 newlines') t.end() }) test('test invalid getProperty("leveldb.sstables")', function (t) { var expected = [0,1,2,3,4,5,6].map(function (l) { return '--- level ' + l + ' ---' }).join('\n') + '\n' t.equal(db.getProperty('leveldb.sstables'), expected, 'leveldb.sstables') t.end() }) test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) node-leveldown-1.4.1+dfsg/test/iterator-recursion-test.js000066400000000000000000000032721260647373000235240ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , child_process = require('child_process') var db , sourceData = (function () { var d = [] , i = 0 , k for (; i < 100000; i++) { k = (i < 10 ? '0' : '') + i d.push({ type : 'put' , key : k , value : Math.random() }) } return d }()) test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = leveldown(testCommon.location()) db.open(function () { db.batch(sourceData, t.end.bind(t)) }) }) test('try to create an iterator with a blown stack', function (t) { // Reducing the stack size down from the default 984 for the child node // process makes it easier to trigger the bug condition. But making it too low // causes the child process to die for other reasons. var opts = { execArgv: [ '--stack-size=128' ] } , child = child_process.fork(__dirname + '/stack-blower.js', [ 'run' ], opts) t.plan(2) child.on('message', function (m) { t.ok(true, m) child.disconnect() }) child.on('exit', function (code, sig) { t.equal(code, 0, 'child exited normally') }) }) test('iterate over a large iterator with a large watermark', function (t) { var iterator = db.iterator({ highWaterMark: 10000000 }) , count = 0 , read = function () { iterator.next(function () { count++ if (!arguments.length) t.end() else read() }) } read() }) test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) node-leveldown-1.4.1+dfsg/test/iterator-test.js000066400000000000000000000035651260647373000215220ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/iterator-test') , make = require('./make') abstract.all(leveldown, test, testCommon) make('iterator throws if key is not a string', function (db, t, done) { var ite = db.iterator() var error try { ite.seek() } catch (e) { error = e } t.ok(error, 'had error') t.end() }) make('iterator is seekable', function (db, t, done) { var ite = db.iterator() ite.seek('two') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'two', 'key matches') t.same(value.toString(), '2', 'value matches') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key, undefined, 'end of iterator') t.same(value, undefined, 'end of iterator') ite.end(done) }) }) }) make('reverse seek in the middle', function (db, t, done) { var ite = db.iterator({reverse: true, limit: 1}) ite.seek('three!') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'three', 'key matches') t.same(value.toString(), '3', 'value matches') ite.end(done) }) }) make('iterator invalid seek', function (db, t, done) { var ite = db.iterator() ite.seek('zzz') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key, undefined, 'end of iterator') t.same(value, undefined, 'end of iterator') ite.end(done) }) }) make('reverse seek from invalid range', function (db, t, done) { var ite = db.iterator({reverse: true}) ite.seek('zzz') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'two', 'end of iterator') t.same(value.toString(), '2', 'end of iterator') ite.end(done) }) }) node-leveldown-1.4.1+dfsg/test/leak-tester-batch.js000066400000000000000000000037041260647373000222060ustar00rootroot00000000000000const BUFFERS = false , CHAINED = false var leveldown = require('..') , crypto = require('crypto') , assert = require('assert') , writeCount = 0 , rssBase , db function print () { if (writeCount % 100 === 0) { if (typeof gc != 'undefined') gc() console.log( 'writeCount =' , writeCount , ', rss =' , Math.round(process.memoryUsage().rss / rssBase * 100) + '%' , Math.round(process.memoryUsage().rss / 1024 / 1024) + 'M' , JSON.stringify([0,1,2,3,4,5,6].map(function (l) { return db.getProperty('leveldb.num-files-at-level' + l) })) ) } } var run = CHAINED ? function () { var batch = db.batch() , i = 0 , key , value for (i = 0; i < 100; i++) { key = 'long key to test memory usage ' + String(Math.floor(Math.random() * 10000000)) if (BUFFERS) key = new Buffer(key) value = crypto.randomBytes(1024) if (!BUFFERS) value = value.toString('hex') batch.put(key, value) } batch.write(function (err) { assert(!err) process.nextTick(run) }) writeCount++ print() } : function () { var batch = [] , i , key , value for (i = 0; i < 100; i++) { key = 'long key to test memory usage ' + String(Math.floor(Math.random() * 10000000)) if (BUFFERS) key = new Buffer(key) value = crypto.randomBytes(1024) if (!BUFFERS) value = value.toString('hex') batch.push({ type: 'put', key: key, value: value }) } db.batch(batch, function (err) { assert(!err) process.nextTick(run) }) writeCount++ print() } leveldown.destroy('./leakydb', function () { db = leveldown('./leakydb') db.open({ xcacheSize: 0, xmaxOpenFiles: 10 }, function () { rssBase = process.memoryUsage().rss run() }) })node-leveldown-1.4.1+dfsg/test/leak-tester.js000066400000000000000000000023751260647373000211320ustar00rootroot00000000000000const BUFFERS = false var leveldown = require('..') , crypto = require('crypto') , putCount = 0 , getCount = 0 , rssBase , db function run () { var key = 'long key to test memory usage ' + String(Math.floor(Math.random() * 10000000)) if (BUFFERS) key = new Buffer(key) db.get(key, function (err, value) { getCount++ if (err) { var putValue = crypto.randomBytes(1024) if (!BUFFERS) putValue = putValue.toString('hex') return db.put(key, putValue, function () { putCount++ process.nextTick(run) }) } process.nextTick(run) }) if (getCount % 1000 === 0) { if (typeof gc != 'undefined') gc() console.log( 'getCount =' , getCount , ', putCount = ' , putCount , ', rss =' , Math.round(process.memoryUsage().rss / rssBase * 100) + '%' , Math.round(process.memoryUsage().rss / 1024 / 1024) + 'M' , JSON.stringify([0,1,2,3,4,5,6].map(function (l) { return db.getProperty('leveldb.num-files-at-level' + l) })) ) } } leveldown.destroy('./leakydb', function () { db = leveldown('./leakydb') db.open({ xcacheSize: 0, xmaxOpenFiles: 10 }, function () { rssBase = process.memoryUsage().rss run() }) })node-leveldown-1.4.1+dfsg/test/leveldown-test.js000066400000000000000000000002531260647373000216570ustar00rootroot00000000000000const test = require('tape') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/leveldown-test') abstract.args(leveldown, test) node-leveldown-1.4.1+dfsg/test/make.js000066400000000000000000000021241260647373000176170ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , cleanup = testCommon.cleanup , location = testCommon.location , leveldown = require('../') function makeTest (name, testFn) { test(name, function (t) { cleanup(function () { var loc = location() , db = leveldown(loc) , done = function (close) { if (close === false) return cleanup(t.end.bind(t)) db.close(function (err) { t.notOk(err, 'no error from close()') cleanup(t.end.bind(t)) }) } db.open(function (err) { t.notOk(err, 'no error from open()') db.batch( [ { type: 'put', key: 'one', value: '1' } , { type: 'put', key: 'two', value: '2' } , { type: 'put', key: 'three', value: '3' } ] , function (err) { t.notOk(err, 'no error from batch()') testFn(db, t, done, loc) } ) }) }) }) } module.exports = makeTest node-leveldown-1.4.1+dfsg/test/open-test.js000066400000000000000000000003601260647373000206200ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/open-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/port-libuv-fix-test.js000066400000000000000000000010531260647373000225460ustar00rootroot00000000000000const test = require('tape') , path = require('path') , fs = require('fs') test('test port-libuv is being used', function (t) { var version = fs.readFileSync(path.join(__dirname, '../deps/leveldb/leveldb.gyp'), 'utf8') .match(/'ldbversion': '([^']+)'/)[1] , porth t.ok(version, 'matched current leveldb version') porth = fs.readFileSync(path.join(__dirname, '../deps/leveldb/leveldb-' + version + '/port/port.h'), 'utf8') t.ok(/"port_uv\.h"/.test(porth), 'port.h includes reference to port_uv.h') t.end() }) node-leveldown-1.4.1+dfsg/test/put-get-del-test.js000066400000000000000000000006251260647373000220120ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , fs = require('fs') , path = require('path') , testBuffer = fs.readFileSync(path.join(__dirname, 'data/testdata.bin')) , abstract = require('abstract-leveldown/abstract/put-get-del-test') abstract.all(leveldown, test, testCommon, testBuffer) node-leveldown-1.4.1+dfsg/test/put-test.js000066400000000000000000000003571260647373000204750ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/put-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/ranges-test.js000066400000000000000000000003621260647373000211400ustar00rootroot00000000000000const test = require('tape') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , abstract = require('abstract-leveldown/abstract/ranges-test') abstract.all(leveldown, test, testCommon) node-leveldown-1.4.1+dfsg/test/repair-test.js000066400000000000000000000034221260647373000211430ustar00rootroot00000000000000const test = require('tape') , fs = require('fs') , path = require('path') , mkfiletree = require('mkfiletree') , readfiletree = require('readfiletree') , testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') , makeTest = require('./make') test('test argument-less repair() throws', function (t) { t.throws( leveldown.repair , { name: 'Error', message: 'repair() requires `location` and `callback` arguments' } , 'no-arg repair() throws' ) t.end() }) test('test callback-less, 1-arg, repair() throws', function (t) { t.throws( leveldown.repair.bind(null, 'foo') , { name: 'Error', message: 'repair() requires `location` and `callback` arguments' } , 'callback-less, 1-arg repair() throws' ) t.end() }) test('test repair non-existant directory returns error', function (t) { leveldown.repair('/1/2/3/4', function (err) { t.ok(/no such/i.test(err), 'error on callback') t.end() }) }) // a proxy indicator that RepairDB is being called and doing its thing makeTest('test repair() compacts', function (db, t, done, location) { db.close(function (err) { t.notOk(err, 'no error') var files = fs.readdirSync(location) t.ok(files.some(function (f) { return (/\.log$/).test(f) }), 'directory contains log file(s)') t.notOk(files.some(function (f) { return (/\.ldb$/).test(f) }), 'directory does not contain ldb file(s)') leveldown.repair(location, function () { files = fs.readdirSync(location) t.notOk(files.some(function (f) { return (/\.log$/).test(f) }), 'directory does not contain log file(s)') t.ok(files.some(function (f) { return (/\.ldb$/).test(f) }), 'directory contains ldb file(s)') done(false) }) }) }) node-leveldown-1.4.1+dfsg/test/stack-blower.js000066400000000000000000000015111260647373000212760ustar00rootroot00000000000000/** * This test uses infinite recursion to test iterator creation with limited * stack space. In order to isolate the test harness, we run in a different * process. This is achieved through a fork() command in * iterator-recursion-test.js. To prevent tap from trying to run this test * directly, we check for a command-line argument. */ const testCommon = require('abstract-leveldown/testCommon') , leveldown = require('../') if (process.argv[2] == 'run') { testCommon.cleanup(function () { var db = leveldown(testCommon.location()) , depth = 0 db.open(function () { function recurse() { db.iterator({ start: '0' }) depth++ recurse() } try { recurse() } catch (e) { process.send("Catchable error at depth " + depth) } }) }) }