├── libraries └── liblmdb │ ├── .gitignore │ ├── COPYRIGHT │ ├── mdb_copy.1 │ ├── sample-mdb.txt │ ├── mdb_stat.1 │ ├── mdb_copy.c │ ├── sample-bdb.txt │ ├── LICENSE │ ├── Makefile │ ├── CHANGES │ ├── mtest2.c │ ├── mtest3.c │ ├── mtest5.c │ ├── mtest6.c │ ├── mtest4.c │ ├── midl.h │ ├── mtest.c │ ├── mdb_stat.c │ └── midl.c ├── .gitignore ├── package.json ├── binding.gyp ├── LICENSE ├── example7-largedb.js ├── example6-asyncio.js ├── example1-env.js ├── src ├── node-lmdb.cpp ├── misc.cpp ├── dbi.cpp ├── txn.cpp ├── cursor.cpp ├── env.cpp └── node-lmdb.h ├── example3-multiple-transactions.js ├── example2-datatypes.js ├── example4-cursors.js ├── example5-dupsort.js ├── example-advanced1-indexing.js └── README.md /libraries/liblmdb/.gitignore: -------------------------------------------------------------------------------- 1 | mtest 2 | mtest[23456] 3 | testdb 4 | mdb_copy 5 | mdb_stat 6 | *.[ao] 7 | *.so 8 | *[~#] 9 | *.bak 10 | *.orig 11 | *.rej 12 | core 13 | core.* 14 | valgrind.* 15 | man/ 16 | html/ 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | build 3 | testdata 4 | 5 | # qmake autogenerated files 6 | moc_* 7 | qrc_* 8 | ui_* 9 | Makefile 10 | 11 | # Qt Creator's stuff 12 | *.pro.user 13 | qtc_packaging 14 | 15 | # Other generated files 16 | *.o 17 | *.slo 18 | *.lo 19 | *.core 20 | MANIFEST 21 | 22 | # gedit's temp files 23 | *~ 24 | .goutputstream* 25 | 26 | # Compiled Dynamic libraries 27 | *.so 28 | *.dylib 29 | 30 | # Compiled Static libraries 31 | *.lai 32 | *.la 33 | *.a 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-lmdb", 3 | "description": "Node binding for LMDB, the Lightning Memory-Mapped Database", 4 | "author": "Timur Kristóf ", 5 | "license": "MIT", 6 | "keywords": [ 7 | "lmdb", 8 | "database", 9 | "mdb", 10 | "lightning", 11 | "binding" 12 | ], 13 | "repository": "https://github.com/Venemo/node-lmdb", 14 | "version": "0.2.2", 15 | "main": "./build/Release/node-lmdb", 16 | "gypfile": true 17 | } 18 | -------------------------------------------------------------------------------- /libraries/liblmdb/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2011-2013 Howard Chu, Symas Corp. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted only as authorized by the OpenLDAP 6 | Public License. 7 | 8 | A copy of this license is available in the file LICENSE in the 9 | top-level directory of the distribution or, alternatively, at 10 | . 11 | 12 | OpenLDAP is a registered trademark of the OpenLDAP Foundation. 13 | 14 | Individual files and/or contributed packages may be copyright by 15 | other parties and/or subject to additional restrictions. 16 | 17 | This work also contains materials derived from public sources. 18 | 19 | Additional information about OpenLDAP can be obtained at 20 | . 21 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "node-lmdb", 5 | "sources": [ 6 | "libraries/liblmdb/mdb.c", 7 | "libraries/liblmdb/lmdb.h", 8 | "libraries/liblmdb/midl.h", 9 | "libraries/liblmdb/midl.c", 10 | "src/node-lmdb.cpp", 11 | "src/env.cpp", 12 | "src/misc.cpp", 13 | "src/txn.cpp", 14 | "src/dbi.cpp", 15 | "src/cursor.cpp" 16 | ], 17 | "conditions": [ 18 | ["OS=='linux'", { 19 | "ldflags": [ 20 | "-O3", 21 | "-rdynamic" 22 | ], 23 | "cflags": [ 24 | "-fPIC", 25 | "-fvisibility-inlines-hidden", 26 | "-O3", 27 | "-std=c++0x" 28 | ] 29 | }], 30 | ["OS=='mac'", { 31 | "xcode_settings": { 32 | "OTHER_CPLUSPLUSFLAGS" : ["-std=c++11","-stdlib=libc++","-mmacosx-version-min=10.7"], 33 | "OTHER_LDFLAGS": ["-std=c++11"], 34 | } 35 | }], 36 | ], 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Timur Kristóf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /example7-largedb.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Example that shows how to use node-lmdb with LARGE databases 4 | */ 5 | 6 | // Set things up 7 | 8 | var lmdb = require('./build/Release/node-lmdb'); 9 | var fs = require('fs'); 10 | 11 | var env = new lmdb.Env(); 12 | env.open({ path: './testdata', mapSize: 16 * 1024 * 1024 * 1024 }); 13 | var dbi = env.openDbi({ name: 'test', create: true }); 14 | 15 | // See how much we can squeeze into the db 16 | 17 | try { 18 | while (true) { 19 | for (var i = 0; i < 1000; i++) { 20 | var txn = env.beginTxn(); 21 | txn.putString(dbi, randomString(128), randomString(512)); 22 | txn.commit(); 23 | } 24 | console.log('database size', getDbSize(), 'MB'); 25 | } 26 | } 27 | catch (error) { 28 | console.log('database size', getDbSize(), 'MB'); 29 | console.log('error is', error); 30 | } 31 | 32 | // Utility functions 33 | 34 | function getDbSize () { 35 | return fs.statSync('./testdata/data.mdb').size / 1024 / 1024; 36 | } 37 | 38 | function randomString (length) { 39 | var result = ''; 40 | while (length-- > 0) { 41 | result += String.fromCharCode(97 + Math.floor(Math.random() * 26)); 42 | } 43 | return result; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /example6-asyncio.js: -------------------------------------------------------------------------------- 1 | 2 | // Require the module 3 | var lmdb = require('./build/Release/node-lmdb'); 4 | 5 | // Create new LMDB environment 6 | var env = new lmdb.Env(); 7 | // Open the environment 8 | env.open({ 9 | path: "./testdata", 10 | maxDbs: 10, 11 | 12 | // These options prevent LMDB from automatically syncing on commit 13 | noMetaSync: true, 14 | noSync: true 15 | }); 16 | // Open database 17 | var dbi = env.openDbi({ 18 | name: "mydb1", 19 | create: true 20 | }); 21 | 22 | // Manipulate some data 23 | var txn = env.beginTxn(); 24 | var data = txn.getString(dbi, "hello"); 25 | console.log(data); 26 | if (data === null) { 27 | txn.putString(dbi, "hello", "Hello world!"); 28 | } 29 | else { 30 | txn.del(dbi, "hello"); 31 | } 32 | txn.commit(); 33 | 34 | // Manually sync the environment 35 | env.sync(function(err) { 36 | if (err) { 37 | // There was an error 38 | console.log("error", err); 39 | } 40 | else { 41 | console.log("successful sync"); 42 | } 43 | 44 | // Close the database 45 | dbi.close(); 46 | // Close the environment 47 | env.close(); 48 | }); 49 | 50 | console.log(""); 51 | console.log("Run this example again to see the alterations on the database!"); 52 | 53 | -------------------------------------------------------------------------------- /example1-env.js: -------------------------------------------------------------------------------- 1 | 2 | // Require the module 3 | var lmdb = require('./build/Release/node-lmdb'); 4 | // Now you can use the module 5 | 6 | // Print the version 7 | console.log("Current lmdb version is", lmdb.version); 8 | // Create new LMDB environment 9 | var env = new lmdb.Env(); 10 | // Open the environment 11 | env.open({ 12 | // Path to the environment 13 | // IMPORTANT: you will get an error if the directory doesn't exist! 14 | path: "./testdata", 15 | // Maximum number of databases 16 | maxDbs: 10 17 | }); 18 | // Open database 19 | var dbi = env.openDbi({ 20 | name: "mydb1", 21 | create: true 22 | }); 23 | 24 | // Begin transaction 25 | var txn = env.beginTxn(); 26 | 27 | // Get data 28 | var data = txn.getString(dbi, "hello"); 29 | console.log(data); 30 | 31 | var stat = dbi.stat(txn); 32 | console.log("\ndatabase statistics:"); 33 | console.dir(stat); 34 | 35 | if (data === null) { 36 | // Put data 37 | txn.putString(dbi, "hello", "Hello world!"); 38 | } 39 | else { 40 | // Delete data 41 | txn.del(dbi, "hello"); 42 | } 43 | 44 | console.log(""); 45 | console.log("Run this example again to see the alterations on the database!"); 46 | 47 | // Commit transaction 48 | txn.commit(); 49 | 50 | // Close the database 51 | dbi.close(); 52 | // Close the environment 53 | env.close(); 54 | -------------------------------------------------------------------------------- /libraries/liblmdb/mdb_copy.1: -------------------------------------------------------------------------------- 1 | .TH MDB_COPY 1 "2012/12/12" "LMDB 0.9.5" 2 | .\" Copyright 2012 Howard Chu, Symas Corp. All Rights Reserved. 3 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. 4 | .SH NAME 5 | mdb_copy \- LMDB environment copy tool 6 | .SH SYNOPSIS 7 | .B mdb_copy 8 | [\c 9 | .BR \-n ] 10 | .B srcpath 11 | [\c 12 | .BR dstpath ] 13 | .SH DESCRIPTION 14 | The 15 | .B mdb_copy 16 | utility copies an LMDB environment. The environment can 17 | be copied regardless of whether it is currently in use. 18 | No lockfile is created, since it gets recreated at need. 19 | 20 | If 21 | .I dstpath 22 | is specified it must be the path of an empty directory 23 | for storing the backup. Otherwise, the backup will be 24 | written to stdout. 25 | 26 | .SH OPTIONS 27 | .BR \-n 28 | Open LDMB environment(s) which do not use subdirectories. 29 | 30 | .SH DIAGNOSTICS 31 | Exit status is zero if no errors occur. 32 | Errors result in a non-zero exit status and 33 | a diagnostic message being written to standard error. 34 | .SH CAVEATS 35 | This utility can trigger significant file size growth if run 36 | in parallel with write transactions, because pages which they 37 | free during copying cannot be reused until the copy is done. 38 | .SH "SEE ALSO" 39 | .BR mdb_stat (1) 40 | .SH AUTHOR 41 | Howard Chu of Symas Corporation 42 | -------------------------------------------------------------------------------- /src/node-lmdb.cpp: -------------------------------------------------------------------------------- 1 | 2 | // This file is part of node-lmdb, the Node.js binding for lmdb 3 | // Copyright (c) 2013 Timur Kristóf 4 | // Licensed to you under the terms of the MIT license 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #include "node-lmdb.h" 25 | 26 | using namespace v8; 27 | using namespace node; 28 | 29 | extern "C" { 30 | // Initializes the module 31 | void initializeModule(Handle exports) { 32 | // Export Env as constructor for EnvWrap 33 | EnvWrap::setupExports(exports); 34 | 35 | // Export Cursor as constructor for CursorWrap 36 | CursorWrap::setupExports(exports); 37 | 38 | // Export misc things 39 | setupExportMisc(exports); 40 | } 41 | 42 | // The standard node macro 43 | NODE_MODULE(node_lmdb, initializeModule) 44 | } 45 | -------------------------------------------------------------------------------- /example3-multiple-transactions.js: -------------------------------------------------------------------------------- 1 | 2 | var lmdb = require('./build/Release/node-lmdb'); 3 | var env = new lmdb.Env(); 4 | env.open({ 5 | // Path to the environment 6 | path: "./testdata", 7 | // Maximum number of databases 8 | maxDbs: 10 9 | }); 10 | var dbi = env.openDbi({ 11 | name: "mydb3", 12 | create: true, 13 | keyIsUint32: true 14 | }); 15 | 16 | var data; 17 | 18 | // Write values 19 | 20 | var txn0 = env.beginTxn(); 21 | txn0.putString(dbi, 1, "Hello1"); 22 | txn0.putString(dbi, 2, "Hello2"); 23 | txn0.commit(); 24 | console.log("wrote initial values"); 25 | 26 | // Now mess around with transactions 27 | 28 | var txn1 = env.beginTxn({ readOnly: true }); 29 | console.log("txn1: started (read only)"); 30 | data = txn1.getString(dbi, 1); 31 | console.log("-----", "txn1", 1, data); 32 | 33 | var txn2 = env.beginTxn(); 34 | console.log("txn2: started"); 35 | txn2.putString(dbi, 1, "Ha ha ha"); 36 | console.log("txn2: put other value to key 1"); 37 | 38 | // txn2 sees the new value immediately 39 | data = txn2.getString(dbi, 1); 40 | console.log("-----", "txn2", 1, data); 41 | 42 | // txn1 still sees the old value 43 | data = txn1.getString(dbi, 1); 44 | console.log("-----", "txn1", 1, data); 45 | 46 | txn2.commit(); 47 | console.log("txn2: committed"); 48 | 49 | // txn1 still sees the old value! 50 | data = txn1.getString(dbi, 1); 51 | console.log("-----", "txn1", 1, data); 52 | 53 | txn1.reset(); 54 | txn1.renew(); 55 | console.log("rxn1: reset+renewed"); 56 | 57 | // now txn1 sees the new value 58 | data = txn1.getString(dbi, 1); 59 | console.log("-----", "txn1", 1, data); 60 | 61 | try { 62 | console.log("error expected here:"); 63 | // txn1 is readonly, this will throw an exception! 64 | txn1.putString(dbi, 2, "hööhh"); 65 | } 66 | catch (err) { 67 | console.log(err); 68 | } 69 | 70 | txn1.commit(); 71 | console.log("txn1: aborted"); 72 | 73 | dbi.close(); 74 | env.close(); 75 | 76 | -------------------------------------------------------------------------------- /libraries/liblmdb/sample-mdb.txt: -------------------------------------------------------------------------------- 1 | /* sample-mdb.txt - MDB toy/sample 2 | * 3 | * Do a line-by-line comparison of this and sample-bdb.txt 4 | */ 5 | /* 6 | * Copyright 2012 Howard Chu, Symas Corp. 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted only as authorized by the OpenLDAP 11 | * Public License. 12 | * 13 | * A copy of this license is available in the file LICENSE in the 14 | * top-level directory of the distribution or, alternatively, at 15 | * . 16 | */ 17 | #include 18 | #include "lmdb.h" 19 | 20 | int main(int argc,char * argv[]) 21 | { 22 | int rc; 23 | MDB_env *env; 24 | MDB_dbi dbi; 25 | MDB_val key, data; 26 | MDB_txn *txn; 27 | MDB_cursor *cursor; 28 | char sval[32]; 29 | 30 | /* Note: Most error checking omitted for simplicity */ 31 | 32 | rc = mdb_env_create(&env); 33 | rc = mdb_env_open(env, "./testdb", 0, 0664); 34 | rc = mdb_txn_begin(env, NULL, 0, &txn); 35 | rc = mdb_open(txn, NULL, 0, &dbi); 36 | 37 | key.mv_size = sizeof(int); 38 | key.mv_data = sval; 39 | data.mv_size = sizeof(sval); 40 | data.mv_data = sval; 41 | 42 | sprintf(sval, "%03x %d foo bar", 32, 3141592); 43 | rc = mdb_put(txn, dbi, &key, &data, 0); 44 | rc = mdb_txn_commit(txn); 45 | if (rc) { 46 | fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc)); 47 | goto leave; 48 | } 49 | rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); 50 | rc = mdb_cursor_open(txn, dbi, &cursor); 51 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 52 | printf("key: %p %.*s, data: %p %.*s\n", 53 | key.mv_data, (int) key.mv_size, (char *) key.mv_data, 54 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); 55 | } 56 | mdb_cursor_close(cursor); 57 | mdb_txn_abort(txn); 58 | leave: 59 | mdb_close(env, dbi); 60 | mdb_env_close(env); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /libraries/liblmdb/mdb_stat.1: -------------------------------------------------------------------------------- 1 | .TH MDB_STAT 1 "2012/12/12" "LMDB 0.9.5" 2 | .\" Copyright 2012 Howard Chu, Symas Corp. All Rights Reserved. 3 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. 4 | .SH NAME 5 | mdb_stat \- LMDB environment status tool 6 | .SH SYNOPSIS 7 | .B mdb_stat 8 | .BR \ envpath 9 | [\c 10 | .BR \-e ] 11 | [\c 12 | .BR \-f [ f [ f ]]] 13 | [\c 14 | .BR \-n ] 15 | [\c 16 | .BR \-r [ r ]] 17 | [\c 18 | .BR \-a \ | 19 | .BI \-s \ subdb\fR] 20 | .SH DESCRIPTION 21 | The 22 | .B mdb_stat 23 | utility displays the status of an LMDB environment. 24 | .SH OPTIONS 25 | .TP 26 | .BR \-e 27 | Display information about the database environment. 28 | .TP 29 | .BR \-f 30 | Display information about the environment freelist. 31 | If \fB\-ff\fP is given, summarize each freelist entry. 32 | If \fB\-fff\fP is given, display the full list of page IDs in the freelist. 33 | .TP 34 | .BR \-n 35 | Display the status of an LMDB database which does not use subdirectories. 36 | .TP 37 | .BR \-r 38 | Display information about the environment reader table. 39 | Shows the process ID, thread ID, and transaction ID for each active 40 | reader slot. The process ID and transaction ID are in decimal, the 41 | thread ID is in hexadecimal. The transaction ID is displayed as "-" 42 | if the reader does not currently have a read transaction open. 43 | If \fB\-rr\fP is given, check for stale entries in the reader 44 | table and clear them. The reader table will be printed again 45 | after the check is performed. 46 | .TP 47 | .BR \-a 48 | Display the status of all of the subdatabases in the environment. 49 | .TP 50 | .BR \-s \ subdb 51 | Display the status of a specific subdatabase. 52 | .SH DIAGNOSTICS 53 | Exit status is zero if no errors occur. 54 | Errors result in a non-zero exit status and 55 | a diagnostic message being written to standard error. 56 | .SH "SEE ALSO" 57 | .BR mdb_copy (1) 58 | .SH AUTHOR 59 | Howard Chu of Symas Corporation 60 | -------------------------------------------------------------------------------- /libraries/liblmdb/mdb_copy.c: -------------------------------------------------------------------------------- 1 | /* mdb_copy.c - memory-mapped database backup tool */ 2 | /* 3 | * Copyright 2012 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | #ifdef _WIN32 15 | #include 16 | #define MDB_STDOUT GetStdHandle(STD_OUTPUT_HANDLE) 17 | #else 18 | #define MDB_STDOUT 1 19 | #endif 20 | #include 21 | #include 22 | #include 23 | #include "lmdb.h" 24 | 25 | static void 26 | sighandle(int sig) 27 | { 28 | } 29 | 30 | int main(int argc,char * argv[]) 31 | { 32 | int rc; 33 | MDB_env *env; 34 | const char *progname = argv[0], *act; 35 | unsigned flags = MDB_RDONLY; 36 | 37 | for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) { 38 | if (argv[1][1] == 'n' && argv[1][2] == '\0') 39 | flags |= MDB_NOSUBDIR; 40 | else 41 | argc = 0; 42 | } 43 | 44 | if (argc<2 || argc>3) { 45 | fprintf(stderr, "usage: %s [-n] srcpath [dstpath]\n", progname); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | #ifdef SIGPIPE 50 | signal(SIGPIPE, sighandle); 51 | #endif 52 | #ifdef SIGHUP 53 | signal(SIGHUP, sighandle); 54 | #endif 55 | signal(SIGINT, sighandle); 56 | signal(SIGTERM, sighandle); 57 | 58 | act = "opening environment"; 59 | rc = mdb_env_create(&env); 60 | if (rc == MDB_SUCCESS) { 61 | rc = mdb_env_open(env, argv[1], flags, 0); 62 | } 63 | if (rc == MDB_SUCCESS) { 64 | act = "copying"; 65 | if (argc == 2) 66 | rc = mdb_env_copyfd(env, MDB_STDOUT); 67 | else 68 | rc = mdb_env_copy(env, argv[2]); 69 | } 70 | if (rc) 71 | fprintf(stderr, "%s: %s failed, error %d (%s)\n", 72 | progname, act, rc, mdb_strerror(rc)); 73 | mdb_env_close(env); 74 | 75 | return rc ? EXIT_FAILURE : EXIT_SUCCESS; 76 | } 77 | -------------------------------------------------------------------------------- /libraries/liblmdb/sample-bdb.txt: -------------------------------------------------------------------------------- 1 | /* sample-bdb.txt - BerkeleyDB toy/sample 2 | * 3 | * Do a line-by-line comparison of this and sample-mdb.txt 4 | */ 5 | /* 6 | * Copyright 2012 Howard Chu, Symas Corp. 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted only as authorized by the OpenLDAP 11 | * Public License. 12 | * 13 | * A copy of this license is available in the file LICENSE in the 14 | * top-level directory of the distribution or, alternatively, at 15 | * . 16 | */ 17 | #include 18 | #include 19 | #include 20 | 21 | int main(int argc,char * argv[]) 22 | { 23 | int rc; 24 | DB_ENV *env; 25 | DB *dbi; 26 | DBT key, data; 27 | DB_TXN *txn; 28 | DBC *cursor; 29 | char sval[32], kval[32]; 30 | 31 | /* Note: Most error checking omitted for simplicity */ 32 | 33 | #define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD) 34 | rc = db_env_create(&env, 0); 35 | rc = env->open(env, "./testdb", FLAGS, 0664); 36 | rc = db_create(&dbi, env, 0); 37 | rc = env->txn_begin(env, NULL, &txn, 0); 38 | rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664); 39 | 40 | memset(&key, 0, sizeof(DBT)); 41 | memset(&data, 0, sizeof(DBT)); 42 | key.size = sizeof(int); 43 | key.data = sval; 44 | data.size = sizeof(sval); 45 | data.data = sval; 46 | 47 | sprintf(sval, "%03x %d foo bar", 32, 3141592); 48 | rc = dbi->put(dbi, txn, &key, &data, 0); 49 | rc = txn->commit(txn, 0); 50 | if (rc) { 51 | fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc)); 52 | goto leave; 53 | } 54 | rc = env->txn_begin(env, NULL, &txn, 0); 55 | rc = dbi->cursor(dbi, txn, &cursor, 0); 56 | key.flags = DB_DBT_USERMEM; 57 | key.data = kval; 58 | key.ulen = sizeof(kval); 59 | data.flags = DB_DBT_USERMEM; 60 | data.data = sval; 61 | data.ulen = sizeof(sval); 62 | while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) { 63 | printf("key: %p %.*s, data: %p %.*s\n", 64 | key.data, (int) key.size, (char *) key.data, 65 | data.data, (int) data.size, (char *) data.data); 66 | } 67 | rc = cursor->c_close(cursor); 68 | rc = txn->abort(txn); 69 | leave: 70 | rc = dbi->close(dbi, 0); 71 | rc = env->close(env, 0); 72 | return rc; 73 | } 74 | -------------------------------------------------------------------------------- /example2-datatypes.js: -------------------------------------------------------------------------------- 1 | 2 | var lmdb = require('./build/Release/node-lmdb'); 3 | var env = new lmdb.Env(); 4 | env.open({ 5 | // Path to the environment 6 | path: "./testdata", 7 | // Maximum number of databases 8 | maxDbs: 10 9 | }); 10 | var dbi = env.openDbi({ 11 | name: "mydb2", 12 | create: true 13 | }); 14 | 15 | // Create transaction 16 | var txn = env.beginTxn(); 17 | 18 | // Example for getting/putting/deleting string data 19 | // ---------- 20 | var stringData = txn.getString(dbi, "key1"); 21 | // Print the string 22 | console.log("string data: ", stringData); 23 | // Toggle the value 24 | if (stringData === null) 25 | txn.putString(dbi, "key1", "Hello world!"); 26 | else 27 | txn.del(dbi, "key1"); 28 | 29 | // Example for getting/putting/deleting binary data 30 | // ---------- 31 | var binaryData = txn.getBinary(dbi, "key2"); 32 | // Print the string representation of the binary 33 | console.log("binary data: ", binaryData ? binaryData.toString() : null); 34 | // Toggle the value 35 | if (stringData === null) { 36 | var buffer = new Buffer("Hey my friend"); 37 | txn.putBinary(dbi, "key2", buffer); 38 | } 39 | else { 40 | txn.del(dbi, "key2"); 41 | } 42 | 43 | // Example for getting/putting/deleting number data 44 | // ---------- 45 | var numberData = txn.getNumber(dbi, "key3"); 46 | // Print the number 47 | console.log("number data: ", numberData); 48 | // Toggle the value 49 | if (numberData === null) 50 | txn.putNumber(dbi, "key3", 42); 51 | else 52 | txn.del(dbi, "key3"); 53 | 54 | // Example for getting/putting/deleting boolean data 55 | // ---------- 56 | var booleanData = txn.getBoolean(dbi, "key4"); 57 | // Print the boolean 58 | console.log("boolean data: ", booleanData); 59 | // Toggle the value 60 | if (booleanData === null) 61 | txn.putBoolean(dbi, "key4", true); 62 | else 63 | txn.del(dbi, "key4"); 64 | 65 | // Example for using integer key 66 | // ---------- 67 | var data = txn.getString(dbi, "key5"); 68 | console.log("integer key value: ", data); 69 | if (data === null) 70 | txn.putString(dbi, "key5", "Hello worllld!"); 71 | else 72 | txn.del(dbi, "key5"); 73 | 74 | console.log(""); 75 | console.log("Run this example again to see the alterations on the database!"); 76 | 77 | // Commit transaction 78 | txn.commit(); 79 | 80 | dbi.close(); 81 | env.close(); 82 | 83 | -------------------------------------------------------------------------------- /libraries/liblmdb/LICENSE: -------------------------------------------------------------------------------- 1 | The OpenLDAP Public License 2 | Version 2.8, 17 August 2003 3 | 4 | Redistribution and use of this software and associated documentation 5 | ("Software"), with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | 1. Redistributions in source form must retain copyright statements 9 | and notices, 10 | 11 | 2. Redistributions in binary form must reproduce applicable copyright 12 | statements and notices, this list of conditions, and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution, and 15 | 16 | 3. Redistributions must contain a verbatim copy of this document. 17 | 18 | The OpenLDAP Foundation may revise this license from time to time. 19 | Each revision is distinguished by a version number. You may use 20 | this Software under terms of this license revision or under the 21 | terms of any subsequent revision of the license. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS 24 | CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 25 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 26 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 27 | SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) 28 | OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | POSSIBILITY OF SUCH DAMAGE. 36 | 37 | The names of the authors and copyright holders must not be used in 38 | advertising or otherwise to promote the sale, use or other dealing 39 | in this Software without specific, written prior permission. Title 40 | to copyright in this Software shall at all times remain with copyright 41 | holders. 42 | 43 | OpenLDAP is a registered trademark of the OpenLDAP Foundation. 44 | 45 | Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, 46 | California, USA. All Rights Reserved. Permission to copy and 47 | distribute verbatim copies of this document is granted. 48 | -------------------------------------------------------------------------------- /libraries/liblmdb/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for liblmdb (Lightning memory-mapped database library). 2 | 3 | ######################################################################## 4 | # Configuration. The compiler options must enable threaded compilation. 5 | # 6 | # Preprocessor macros (for CPPFLAGS) of interest... 7 | # Note that the defaults should already be correct for most 8 | # platforms; you should not need to change any of these. 9 | # Read their descriptions in mdb.c if you do: 10 | # 11 | # - MDB_USE_POSIX_SEM 12 | # - MDB_DSYNC 13 | # - MDB_FDATASYNC 14 | # - MDB_USE_PWRITEV 15 | # 16 | # There may be other macros in mdb.c of interest. You should 17 | # read mdb.c before changing any of them. 18 | # 19 | CC = gcc 20 | W = -W -Wall -Wno-unused-parameter -Wbad-function-cast 21 | THREADS = -pthread 22 | OPT = -O2 -g 23 | CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS) 24 | LDLIBS = 25 | SOLIBS = 26 | prefix = /usr/local 27 | 28 | ######################################################################## 29 | 30 | IHDRS = lmdb.h 31 | ILIBS = liblmdb.a liblmdb.so 32 | IPROGS = mdb_stat mdb_copy 33 | IDOCS = mdb_stat.1 mdb_copy.1 34 | PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5 35 | all: $(ILIBS) $(PROGS) 36 | 37 | install: $(ILIBS) $(IPROGS) $(IHDRS) 38 | for f in $(IPROGS); do cp $$f $(DESTDIR)$(prefix)/bin; done 39 | for f in $(ILIBS); do cp $$f $(DESTDIR)$(prefix)/lib; done 40 | for f in $(IHDRS); do cp $$f $(DESTDIR)$(prefix)/include; done 41 | for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done 42 | 43 | clean: 44 | rm -rf $(PROGS) *.[ao] *.so *~ testdb 45 | 46 | test: all 47 | mkdir testdb 48 | ./mtest && ./mdb_stat testdb 49 | 50 | liblmdb.a: mdb.o midl.o 51 | ar rs $@ mdb.o midl.o 52 | 53 | liblmdb.so: mdb.o midl.o 54 | # $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) 55 | $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.o midl.o $(SOLIBS) 56 | 57 | mdb_stat: mdb_stat.o liblmdb.a 58 | mdb_copy: mdb_copy.o liblmdb.a 59 | mtest: mtest.o liblmdb.a 60 | mtest2: mtest2.o liblmdb.a 61 | mtest3: mtest3.o liblmdb.a 62 | mtest4: mtest4.o liblmdb.a 63 | mtest5: mtest5.o liblmdb.a 64 | mtest6: mtest6.o liblmdb.a 65 | 66 | mdb.o: mdb.c lmdb.h midl.h 67 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c 68 | 69 | midl.o: midl.c midl.h 70 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c 71 | 72 | %: %.o 73 | $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ 74 | 75 | %.o: %.c lmdb.h 76 | $(CC) $(CFLAGS) $(CPPFLAGS) -c $< 77 | -------------------------------------------------------------------------------- /example4-cursors.js: -------------------------------------------------------------------------------- 1 | 2 | var lmdb = require('./build/Release/node-lmdb'); 3 | var env = new lmdb.Env(); 4 | env.open({ 5 | // Path to the environment 6 | path: "./testdata", 7 | // Maximum number of databases 8 | maxDbs: 10 9 | }); 10 | 11 | // Ensure that the database is empty 12 | var dbi = env.openDbi({ 13 | name: "mydb4", 14 | create: true 15 | }); 16 | dbi.drop(); 17 | dbi = env.openDbi({ 18 | name: "mydb4", 19 | create: true 20 | }); 21 | 22 | // Write test values 23 | 24 | var txn0 = env.beginTxn(); 25 | txn0.putString(dbi, "a", "Helló1"); 26 | txn0.putString(dbi, "b", "Hello2"); 27 | txn0.putNumber(dbi, "c", 43); 28 | /* key 'd' is omitted intentionally */ 29 | txn0.putBinary(dbi, "e", new Buffer("öüóőúéáű")); 30 | txn0.putBoolean(dbi, "f", false); 31 | txn0.putString(dbi, "g", "Hello6"); 32 | txn0.commit(); 33 | console.log("wrote initial values"); 34 | 35 | var printFunc = function(key, data) { 36 | console.log("-----> key:", key); 37 | console.log("-----> data:", data); 38 | } 39 | 40 | // Begin transaction 41 | var txn = env.beginTxn(); 42 | 43 | // Create cursor 44 | var cursor = new lmdb.Cursor(txn, dbi); 45 | 46 | console.log("first (expected a)"); 47 | cursor.goToFirst(); 48 | cursor.getCurrentString(printFunc); 49 | 50 | console.log("next (expected b)"); 51 | cursor.goToNext(); 52 | cursor.getCurrentString(printFunc); 53 | 54 | console.log("next (expected c)"); 55 | cursor.goToNext(); 56 | cursor.getCurrentNumber(printFunc); 57 | 58 | 59 | console.log("next (expected e)"); 60 | cursor.goToNext(); 61 | cursor.getCurrentBinary(printFunc); 62 | 63 | 64 | console.log("prev (expected c)"); 65 | cursor.goToPrev(); 66 | cursor.getCurrentNumber(printFunc); 67 | 68 | 69 | console.log("last (expected g)"); 70 | cursor.goToLast(); 71 | cursor.getCurrentString(printFunc); 72 | 73 | 74 | console.log("prev (expected f)"); 75 | cursor.goToPrev(); 76 | cursor.getCurrentBoolean(printFunc); 77 | 78 | 79 | console.log("go to key 'b' (expected b)"); 80 | cursor.goToKey('b'); 81 | cursor.getCurrentString(printFunc); 82 | 83 | 84 | console.log("go to range 'd' (expected e)"); 85 | cursor.goToRange('d'); 86 | cursor.getCurrentBinary(printFunc); 87 | 88 | 89 | console.log("del (expected f)"); 90 | cursor.del(); 91 | cursor.getCurrentBoolean(printFunc); 92 | 93 | console.log(""); 94 | console.log("now iterating through all the keys"); 95 | 96 | for (var found = cursor.goToFirst(); found; found = cursor.goToNext()) { 97 | console.log("-----> key:", found); 98 | } 99 | 100 | // Close cursor 101 | cursor.close(); 102 | 103 | // Commit transaction 104 | txn.commit(); 105 | 106 | dbi.close(); 107 | env.close(); 108 | 109 | -------------------------------------------------------------------------------- /example5-dupsort.js: -------------------------------------------------------------------------------- 1 | 2 | var lmdb, env, dbi; 3 | 4 | lmdb = require('./build/Release/node-lmdb'); 5 | env = new lmdb.Env(); 6 | env.open({ 7 | // Path to the environment 8 | path: "./testdata", 9 | // Maximum number of databases 10 | maxDbs: 10 11 | }); 12 | 13 | try { 14 | // If the database exists, drop it 15 | dbi = env.openDbi({ 16 | name: "example5-dupsort", 17 | dupSort: true 18 | }); 19 | dbi.drop(); 20 | } 21 | catch (err) {} 22 | dbi = env.openDbi({ 23 | name: "example5-dupsort", 24 | create: true, 25 | dupSort: true, 26 | dupFixed: true, 27 | integerDup: true 28 | }); 29 | 30 | console.log("ensured database is empty"); 31 | 32 | var printFunc = function(key, data) { 33 | console.log("----------> key:", key); 34 | console.log("----------> data:", data); 35 | } 36 | 37 | var txn, cursor; 38 | 39 | txn = env.beginTxn(); 40 | txn.putNumber(dbi, "hello", 1); 41 | txn.putNumber(dbi, "apple", 2); 42 | txn.putNumber(dbi, "orange", 3); 43 | txn.putNumber(dbi, "apple", 4); 44 | txn.putNumber(dbi, "hello", 5); 45 | txn.putNumber(dbi, "appricot", 6); 46 | txn.putNumber(dbi, "hello", 7); 47 | txn.commit(); 48 | 49 | console.log("wrote test values"); 50 | 51 | txn = env.beginTxn({ readOnly: true }); 52 | cursor = new lmdb.Cursor(txn, dbi); 53 | 54 | console.log("goToRange 'banana'"); 55 | cursor.goToRange("banana"); 56 | cursor.getCurrentNumber(printFunc); 57 | 58 | console.log("goToNext"); 59 | cursor.goToNext(); 60 | cursor.getCurrentNumber(printFunc); 61 | 62 | console.log("goToNext"); 63 | cursor.goToNext(); 64 | cursor.getCurrentNumber(printFunc); 65 | 66 | console.log("goToNext"); 67 | cursor.goToNext(); 68 | cursor.getCurrentNumber(printFunc); 69 | 70 | console.log("goToDup 'apple', 4"); 71 | cursor.goToDup("apple", 4); 72 | cursor.getCurrentNumber(printFunc); 73 | 74 | console.log("goToDupRange 'hello', 0"); 75 | cursor.goToDup("hello", 0); 76 | cursor.getCurrentNumber(printFunc); 77 | 78 | console.log(""); 79 | console.log("iterating through a duplicate key: if-do-while"); 80 | 81 | var key = "hello"; 82 | 83 | if (cursor.goToRange(key) === key) { 84 | do { 85 | cursor.getCurrentNumber(function(key, data) { 86 | // do something with data 87 | console.log(key, data); 88 | }); 89 | } while (cursor.goToNextDup()); 90 | } 91 | 92 | console.log(""); 93 | console.log("iterating through a duplicate key: for"); 94 | 95 | var key = "apple"; 96 | 97 | for (var found = (cursor.goToRange(key) === key); found; found = cursor.goToNextDup()) { 98 | cursor.getCurrentNumber(function(key, data) { 99 | // do something with data 100 | console.log(key, data); 101 | }); 102 | } 103 | 104 | cursor.close(); 105 | txn.abort(); 106 | dbi.close(); 107 | env.close(); 108 | 109 | -------------------------------------------------------------------------------- /libraries/liblmdb/CHANGES: -------------------------------------------------------------------------------- 1 | LMDB 0.9 Change Log 2 | 3 | LMDB 0.9.11 Release (2014/01/15) 4 | Add mdb_env_set_assert() (ITS#7775) 5 | Fix: invalidate txn on page allocation errors (ITS#7377) 6 | Fix xcursor tracking in mdb_cursor_del0() (ITS#7771) 7 | Fix corruption from deletes (ITS#7756) 8 | Fix Windows/MSVC build issues 9 | Raise safe limit of max MDB_MAXKEYSIZE 10 | Misc code cleanup 11 | Documentation 12 | Remove spurious note about non-overlapping flags (ITS#7665) 13 | 14 | LMDB 0.9.10 Release (2013/11/12) 15 | Add MDB_NOMEMINIT option 16 | Fix mdb_page_split() again (ITS#7589) 17 | Fix MDB_NORDAHEAD definition (ITS#7734) 18 | Fix mdb_cursor_del() positioning (ITS#7733) 19 | Partial fix for larger page sizes (ITS#7713) 20 | Fix Windows64/MSVC build issues 21 | 22 | LMDB 0.9.9 Release (2013/10/24) 23 | Add mdb_env_get_fd() 24 | Add MDB_NORDAHEAD option 25 | Add MDB_NOLOCK option 26 | Avoid wasting space in mdb_page_split() (ITS#7589) 27 | Fix mdb_page_merge() cursor fixup (ITS#7722) 28 | Fix mdb_cursor_del() on last delete (ITS#7718) 29 | Fix adding WRITEMAP on existing env (ITS#7715) 30 | Fix nested txns (ITS#7515) 31 | Fix mdb_env_copy() O_DIRECT bug (ITS#7682) 32 | Fix mdb_cursor_set(SET_RANGE) return code (ITS#7681) 33 | Fix mdb_rebalance() cursor fixup (ITS#7701) 34 | Misc code cleanup 35 | Documentation 36 | Note that by default, readers need write access 37 | 38 | 39 | LMDB 0.9.8 Release (2013/09/09) 40 | Allow mdb_env_set_mapsize() on an open environment 41 | Fix mdb_dbi_flags() (ITS#7672) 42 | Fix mdb_page_unspill() in nested txns 43 | Fix mdb_cursor_get(CURRENT|NEXT) after a delete 44 | Fix mdb_cursor_get(DUP) to always return key (ITS#7671) 45 | Fix mdb_cursor_del() to always advance to next item (ITS#7670) 46 | Fix mdb_cursor_set(SET_RANGE) for tree with single page (ITS#7681) 47 | Fix mdb_env_copy() retry open if O_DIRECT fails (ITS#7682) 48 | Tweak mdb_page_spill() to be less aggressive 49 | Documentation 50 | Update caveats since mdb_reader_check() added in 0.9.7 51 | 52 | LMDB 0.9.7 Release (2013/08/17) 53 | Don't leave stale lockfile on failed RDONLY open (ITS#7664) 54 | Fix mdb_page_split() ref beyond cursor depth 55 | Fix read txn data race (ITS#7635) 56 | Fix mdb_rebalance (ITS#7536, #7538) 57 | Fix mdb_drop() (ITS#7561) 58 | Misc DEBUG macro fixes 59 | Add MDB_NOTLS envflag 60 | Add mdb_env_copyfd() 61 | Add mdb_txn_env() (ITS#7660) 62 | Add mdb_dbi_flags() (ITS#7661) 63 | Add mdb_env_get_maxkeysize() 64 | Add mdb_env_reader_list()/mdb_env_reader_check() 65 | Add mdb_page_spill/unspill, remove hard txn size limit 66 | Use shorter names for semaphores (ITS#7615) 67 | Build 68 | Fix install target (ITS#7656) 69 | Documentation 70 | Misc updates for cursors, DB handles, data lifetime 71 | 72 | LMDB 0.9.6 Release (2013/02/25) 73 | Many fixes/enhancements 74 | 75 | LMDB 0.9.5 Release (2012/11/30) 76 | Renamed from libmdb to liblmdb 77 | Many fixes/enhancements 78 | -------------------------------------------------------------------------------- /libraries/liblmdb/mtest2.c: -------------------------------------------------------------------------------- 1 | /* mtest2.c - memory-mapped database tester/toy */ 2 | /* 3 | * Copyright 2011 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | 15 | /* Just like mtest.c, but using a subDB instead of the main DB */ 16 | 17 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 18 | #include 19 | #include 20 | #include 21 | #include "lmdb.h" 22 | 23 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 24 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 25 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 26 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 27 | 28 | int main(int argc,char * argv[]) 29 | { 30 | int i = 0, j = 0, rc; 31 | MDB_env *env; 32 | MDB_dbi dbi; 33 | MDB_val key, data; 34 | MDB_txn *txn; 35 | MDB_stat mst; 36 | MDB_cursor *cursor; 37 | int count; 38 | int *values; 39 | char sval[32] = ""; 40 | 41 | srandom(time(NULL)); 42 | 43 | count = (random()%384) + 64; 44 | values = (int *)malloc(count*sizeof(int)); 45 | 46 | for(i = 0;i -1; i-= (random()%5)) { 86 | j++; 87 | txn=NULL; 88 | E(mdb_txn_begin(env, NULL, 0, &txn)); 89 | sprintf(sval, "%03x ", values[i]); 90 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { 91 | j--; 92 | mdb_txn_abort(txn); 93 | } else { 94 | E(mdb_txn_commit(txn)); 95 | } 96 | } 97 | free(values); 98 | printf("Deleted %d values\n", j); 99 | 100 | E(mdb_env_stat(env, &mst)); 101 | E(mdb_txn_begin(env, NULL, 1, &txn)); 102 | E(mdb_cursor_open(txn, dbi, &cursor)); 103 | printf("Cursor next\n"); 104 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 105 | printf("key: %.*s, data: %.*s\n", 106 | (int) key.mv_size, (char *) key.mv_data, 107 | (int) data.mv_size, (char *) data.mv_data); 108 | } 109 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 110 | printf("Cursor prev\n"); 111 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 112 | printf("key: %.*s, data: %.*s\n", 113 | (int) key.mv_size, (char *) key.mv_data, 114 | (int) data.mv_size, (char *) data.mv_data); 115 | } 116 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 117 | mdb_cursor_close(cursor); 118 | mdb_close(env, dbi); 119 | 120 | mdb_txn_abort(txn); 121 | mdb_env_close(env); 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /libraries/liblmdb/mtest3.c: -------------------------------------------------------------------------------- 1 | /* mtest3.c - memory-mapped database tester/toy */ 2 | /* 3 | * Copyright 2011 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | 15 | /* Tests for sorted duplicate DBs */ 16 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "lmdb.h" 22 | 23 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 24 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 25 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 26 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 27 | 28 | int main(int argc,char * argv[]) 29 | { 30 | int i = 0, j = 0, rc; 31 | MDB_env *env; 32 | MDB_dbi dbi; 33 | MDB_val key, data; 34 | MDB_txn *txn; 35 | MDB_stat mst; 36 | MDB_cursor *cursor; 37 | int count; 38 | int *values; 39 | char sval[32]; 40 | char kval[sizeof(int)]; 41 | 42 | srandom(time(NULL)); 43 | 44 | memset(sval, 0, sizeof(sval)); 45 | 46 | count = (random()%384) + 64; 47 | values = (int *)malloc(count*sizeof(int)); 48 | 49 | for(i = 0;i -1; i-= (random()%5)) { 91 | j++; 92 | txn=NULL; 93 | E(mdb_txn_begin(env, NULL, 0, &txn)); 94 | sprintf(kval, "%03x", values[i & ~0x0f]); 95 | sprintf(sval, "%03x %d foo bar", values[i], values[i]); 96 | key.mv_size = sizeof(int); 97 | key.mv_data = kval; 98 | data.mv_size = sizeof(sval); 99 | data.mv_data = sval; 100 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { 101 | j--; 102 | mdb_txn_abort(txn); 103 | } else { 104 | E(mdb_txn_commit(txn)); 105 | } 106 | } 107 | free(values); 108 | printf("Deleted %d values\n", j); 109 | 110 | E(mdb_env_stat(env, &mst)); 111 | E(mdb_txn_begin(env, NULL, 1, &txn)); 112 | E(mdb_cursor_open(txn, dbi, &cursor)); 113 | printf("Cursor next\n"); 114 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 115 | printf("key: %.*s, data: %.*s\n", 116 | (int) key.mv_size, (char *) key.mv_data, 117 | (int) data.mv_size, (char *) data.mv_data); 118 | } 119 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 120 | printf("Cursor prev\n"); 121 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 122 | printf("key: %.*s, data: %.*s\n", 123 | (int) key.mv_size, (char *) key.mv_data, 124 | (int) data.mv_size, (char *) data.mv_data); 125 | } 126 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 127 | mdb_cursor_close(cursor); 128 | mdb_close(env, dbi); 129 | 130 | mdb_txn_abort(txn); 131 | mdb_env_close(env); 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /libraries/liblmdb/mtest5.c: -------------------------------------------------------------------------------- 1 | /* mtest5.c - memory-mapped database tester/toy */ 2 | /* 3 | * Copyright 2011 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | 15 | /* Tests for sorted duplicate DBs using cursor_put */ 16 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "lmdb.h" 22 | 23 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 24 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 25 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 26 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 27 | 28 | int main(int argc,char * argv[]) 29 | { 30 | int i = 0, j = 0, rc; 31 | MDB_env *env; 32 | MDB_dbi dbi; 33 | MDB_val key, data; 34 | MDB_txn *txn; 35 | MDB_stat mst; 36 | MDB_cursor *cursor; 37 | int count; 38 | int *values; 39 | char sval[32]; 40 | char kval[sizeof(int)]; 41 | 42 | srandom(time(NULL)); 43 | 44 | memset(sval, 0, sizeof(sval)); 45 | 46 | count = (random()%384) + 64; 47 | values = (int *)malloc(count*sizeof(int)); 48 | 49 | for(i = 0;i -1; i-= (random()%5)) { 93 | j++; 94 | txn=NULL; 95 | E(mdb_txn_begin(env, NULL, 0, &txn)); 96 | sprintf(kval, "%03x", values[i & ~0x0f]); 97 | sprintf(sval, "%03x %d foo bar", values[i], values[i]); 98 | key.mv_size = sizeof(int); 99 | key.mv_data = kval; 100 | data.mv_size = sizeof(sval); 101 | data.mv_data = sval; 102 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { 103 | j--; 104 | mdb_txn_abort(txn); 105 | } else { 106 | E(mdb_txn_commit(txn)); 107 | } 108 | } 109 | free(values); 110 | printf("Deleted %d values\n", j); 111 | 112 | E(mdb_env_stat(env, &mst)); 113 | E(mdb_txn_begin(env, NULL, 1, &txn)); 114 | E(mdb_cursor_open(txn, dbi, &cursor)); 115 | printf("Cursor next\n"); 116 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 117 | printf("key: %.*s, data: %.*s\n", 118 | (int) key.mv_size, (char *) key.mv_data, 119 | (int) data.mv_size, (char *) data.mv_data); 120 | } 121 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 122 | printf("Cursor prev\n"); 123 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 124 | printf("key: %.*s, data: %.*s\n", 125 | (int) key.mv_size, (char *) key.mv_data, 126 | (int) data.mv_size, (char *) data.mv_data); 127 | } 128 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 129 | mdb_cursor_close(cursor); 130 | mdb_close(env, dbi); 131 | 132 | mdb_txn_abort(txn); 133 | mdb_env_close(env); 134 | 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /libraries/liblmdb/mtest6.c: -------------------------------------------------------------------------------- 1 | /* mtest6.c - memory-mapped database tester/toy */ 2 | /* 3 | * Copyright 2011 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | 15 | /* Tests for DB splits and merges */ 16 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "lmdb.h" 22 | 23 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 24 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 25 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 26 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 27 | 28 | char dkbuf[1024]; 29 | 30 | int main(int argc,char * argv[]) 31 | { 32 | int i = 0, j = 0, rc; 33 | MDB_env *env; 34 | MDB_dbi dbi; 35 | MDB_val key, data; 36 | MDB_txn *txn; 37 | MDB_stat mst; 38 | MDB_cursor *cursor; 39 | int count; 40 | int *values; 41 | long kval; 42 | char *sval; 43 | 44 | srandom(time(NULL)); 45 | 46 | E(mdb_env_create(&env)); 47 | E(mdb_env_set_mapsize(env, 10485760)); 48 | E(mdb_env_set_maxdbs(env, 4)); 49 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); 50 | E(mdb_txn_begin(env, NULL, 0, &txn)); 51 | E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); 52 | E(mdb_cursor_open(txn, dbi, &cursor)); 53 | E(mdb_stat(txn, dbi, &mst)); 54 | 55 | sval = calloc(1, mst.ms_psize / 4); 56 | key.mv_size = sizeof(long); 57 | key.mv_data = &kval; 58 | data.mv_size = mst.ms_psize / 4 - 30; 59 | data.mv_data = sval; 60 | 61 | printf("Adding 12 values, should yield 3 splits\n"); 62 | for (i=0;i<12;i++) { 63 | kval = i*5; 64 | sprintf(sval, "%08x", kval); 65 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); 66 | } 67 | printf("Adding 12 more values, should yield 3 splits\n"); 68 | for (i=0;i<12;i++) { 69 | kval = i*5+4; 70 | sprintf(sval, "%08x", kval); 71 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); 72 | } 73 | printf("Adding 12 more values, should yield 3 splits\n"); 74 | for (i=0;i<12;i++) { 75 | kval = i*5+1; 76 | sprintf(sval, "%08x", kval); 77 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); 78 | } 79 | E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); 80 | 81 | do { 82 | printf("key: %p %s, data: %p %.*s\n", 83 | key.mv_data, mdb_dkey(&key, dkbuf), 84 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); 85 | } while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0); 86 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 87 | mdb_cursor_close(cursor); 88 | mdb_txn_commit(txn); 89 | 90 | #if 0 91 | j=0; 92 | 93 | for (i= count - 1; i > -1; i-= (random()%5)) { 94 | j++; 95 | txn=NULL; 96 | E(mdb_txn_begin(env, NULL, 0, &txn)); 97 | sprintf(kval, "%03x", values[i & ~0x0f]); 98 | sprintf(sval, "%03x %d foo bar", values[i], values[i]); 99 | key.mv_size = sizeof(int); 100 | key.mv_data = kval; 101 | data.mv_size = sizeof(sval); 102 | data.mv_data = sval; 103 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { 104 | j--; 105 | mdb_txn_abort(txn); 106 | } else { 107 | E(mdb_txn_commit(txn)); 108 | } 109 | } 110 | free(values); 111 | printf("Deleted %d values\n", j); 112 | 113 | E(mdb_env_stat(env, &mst)); 114 | E(mdb_txn_begin(env, NULL, 1, &txn)); 115 | E(mdb_cursor_open(txn, dbi, &cursor)); 116 | printf("Cursor next\n"); 117 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 118 | printf("key: %.*s, data: %.*s\n", 119 | (int) key.mv_size, (char *) key.mv_data, 120 | (int) data.mv_size, (char *) data.mv_data); 121 | } 122 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 123 | printf("Cursor prev\n"); 124 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 125 | printf("key: %.*s, data: %.*s\n", 126 | (int) key.mv_size, (char *) key.mv_data, 127 | (int) data.mv_size, (char *) data.mv_data); 128 | } 129 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 130 | mdb_cursor_close(cursor); 131 | mdb_close(env, dbi); 132 | 133 | mdb_txn_abort(txn); 134 | #endif 135 | mdb_env_close(env); 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /example-advanced1-indexing.js: -------------------------------------------------------------------------------- 1 | 2 | // Indexing engine example 3 | // ---------- 4 | // 5 | // The purpose of this example is to show how to implement an indexing engine using node-lmdb. 6 | // It's not intended to be feature-full, just enough to give you an idea how to use the LMDB API. 7 | // 8 | // Limitations of this indexing engine: 9 | // * Doesn't support fields or advanced querying 10 | // * Tokenization is very simple, no stemming or stop words 11 | // * No phrase search, can only search for single words 12 | // 13 | // But hey, it's only ~100 LOC, so we're still cool :) 14 | 15 | 16 | // Indexing engine (implemented with the module pattern) 17 | var indexingEngine = (function() { 18 | var lmdb, env, dbi; 19 | 20 | // initializer function, call this before using the index 21 | var init = function() { 22 | lmdb = require('./build/Release/node-lmdb'); 23 | env = new lmdb.Env(); 24 | env.open({ 25 | path: "./testdata", 26 | maxDbs: 10 27 | }); 28 | 29 | dbi = env.openDbi({ 30 | name: "example-advanced-indexing", 31 | create: true, 32 | dupSort: true 33 | }); 34 | }; 35 | 36 | // destroy function, call this when you no longer need the index 37 | var destroy = function() { 38 | dbi.close(); 39 | env.close(); 40 | }; 41 | 42 | // simple tokenizer 43 | var tokenize = function(document) { 44 | var tokens = []; 45 | for (var i in document) { 46 | if (document.hasOwnProperty(i) && typeof(document[i]) === "string") { 47 | var stripped = document[i].replace(/[\.!,?\[\]\\]/g, " "); 48 | var splitted = stripped.split(" "); 49 | 50 | for (var j = splitted.length; j--; ) { 51 | if (splitted[j] !== '' && tokens.indexOf(splitted[j]) === -1) { 52 | tokens.push(splitted[j].toLowerCase()); 53 | } 54 | } 55 | } 56 | } 57 | return tokens; 58 | }; 59 | 60 | // adds a document to the index 61 | var addDocument = function(document) { 62 | if (typeof(document.id) !== "number") { 63 | throw new Error("document must have an id property"); 64 | } 65 | 66 | var tokens = tokenize(document); 67 | var txn = env.beginTxn(); 68 | 69 | for (var i = tokens.length; i--; ) { 70 | //console.log(tokens[i], document.id); 71 | txn.putNumber(dbi, tokens[i], document.id); 72 | } 73 | 74 | txn.commit(); 75 | }; 76 | 77 | // adds multiple documents to the index 78 | var addDocuments = function(array) { 79 | if (!(array instanceof Array)) { 80 | throw new Error("This function expects an array."); 81 | } 82 | 83 | for (var i = array.length; i--; ) { 84 | addDocument(array[i]); 85 | } 86 | }; 87 | 88 | // performs a search in the index for the given word 89 | var searchForDocuments = function(str) { 90 | str = str.toLowerCase(); 91 | var txn = env.beginTxn({ readOnly: true }); 92 | var cursor = new lmdb.Cursor(txn, dbi); 93 | var results = []; 94 | 95 | // Go the the first occourence of `str` and iterate from there 96 | for (var found = cursor.goToRange(str); found; found = cursor.goToNext()) { 97 | // Stop the loop if the current key is no longer what we're looking for 98 | if (found !== str) 99 | break; 100 | 101 | // Get current data item and push it to results 102 | cursor.getCurrentNumber(function(key, data) { 103 | results.push(data); 104 | }); 105 | } 106 | 107 | cursor.close(); 108 | txn.abort(); 109 | 110 | return results; 111 | }; 112 | 113 | // The object we return here is the public API of the indexing engine 114 | return Object.freeze({ 115 | init: init, 116 | destroy: destroy, 117 | addDocument: addDocument, 118 | addDocuments: addDocuments, 119 | searchForDocuments: searchForDocuments 120 | }); 121 | })(); 122 | 123 | indexingEngine.init(); 124 | 125 | var docs = []; 126 | docs.push({ 127 | id: 1, 128 | title: "Lord of the Rings", 129 | text: "Great book by J.R.R. Tolkien!" 130 | }); 131 | docs.push({ 132 | id: 2, 133 | title: "A Game of Thrones", 134 | text: "Fantasy book by George R.R. Martin, which also has a television adaptation." 135 | }); 136 | docs.push({ 137 | id: 3, 138 | title: "Caves of Steel", 139 | text: "Science fiction by the great writer Isaac Asimov" 140 | }); 141 | 142 | for (var i = docs.length; i--; ) { 143 | console.log("document details:", JSON.stringify(docs[i])); 144 | } 145 | 146 | indexingEngine.addDocuments(docs); 147 | console.log("successfully added documents to index"); 148 | 149 | var s; 150 | 151 | console.log("search:", s = "Great", indexingEngine.searchForDocuments(s)); 152 | console.log("search:", s = "Asimov", indexingEngine.searchForDocuments(s)); 153 | console.log("search:", s = "of", indexingEngine.searchForDocuments(s)); 154 | console.log("search:", s = "Lord", indexingEngine.searchForDocuments(s)); 155 | 156 | indexingEngine.destroy(); 157 | -------------------------------------------------------------------------------- /libraries/liblmdb/mtest4.c: -------------------------------------------------------------------------------- 1 | /* mtest4.c - memory-mapped database tester/toy */ 2 | /* 3 | * Copyright 2011 Howard Chu, Symas Corp. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted only as authorized by the OpenLDAP 8 | * Public License. 9 | * 10 | * A copy of this license is available in the file LICENSE in the 11 | * top-level directory of the distribution or, alternatively, at 12 | * . 13 | */ 14 | 15 | /* Tests for sorted duplicate DBs with fixed-size keys */ 16 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "lmdb.h" 22 | 23 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 24 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 25 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 26 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 27 | 28 | int main(int argc,char * argv[]) 29 | { 30 | int i = 0, j = 0, rc; 31 | MDB_env *env; 32 | MDB_dbi dbi; 33 | MDB_val key, data; 34 | MDB_txn *txn; 35 | MDB_stat mst; 36 | MDB_cursor *cursor; 37 | int count; 38 | int *values; 39 | char sval[8]; 40 | char kval[sizeof(int)]; 41 | 42 | memset(sval, 0, sizeof(sval)); 43 | 44 | count = 510; 45 | values = (int *)malloc(count*sizeof(int)); 46 | 47 | for(i = 0;i -1; i-= (random()%3)) { 127 | j++; 128 | txn=NULL; 129 | E(mdb_txn_begin(env, NULL, 0, &txn)); 130 | sprintf(sval, "%07x", values[i]); 131 | key.mv_size = sizeof(int); 132 | key.mv_data = kval; 133 | data.mv_size = sizeof(sval); 134 | data.mv_data = sval; 135 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { 136 | j--; 137 | mdb_txn_abort(txn); 138 | } else { 139 | E(mdb_txn_commit(txn)); 140 | } 141 | } 142 | free(values); 143 | printf("Deleted %d values\n", j); 144 | 145 | E(mdb_env_stat(env, &mst)); 146 | E(mdb_txn_begin(env, NULL, 1, &txn)); 147 | E(mdb_cursor_open(txn, dbi, &cursor)); 148 | printf("Cursor next\n"); 149 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 150 | printf("key: %.*s, data: %.*s\n", 151 | (int) key.mv_size, (char *) key.mv_data, 152 | (int) data.mv_size, (char *) data.mv_data); 153 | } 154 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 155 | printf("Cursor prev\n"); 156 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 157 | printf("key: %.*s, data: %.*s\n", 158 | (int) key.mv_size, (char *) key.mv_data, 159 | (int) data.mv_size, (char *) data.mv_data); 160 | } 161 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 162 | mdb_cursor_close(cursor); 163 | mdb_close(env, dbi); 164 | 165 | mdb_txn_abort(txn); 166 | mdb_env_close(env); 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /libraries/liblmdb/midl.h: -------------------------------------------------------------------------------- 1 | /** @file midl.h 2 | * @brief mdb ID List header file. 3 | * 4 | * This file was originally part of back-bdb but has been 5 | * modified for use in libmdb. Most of the macros defined 6 | * in this file are unused, just left over from the original. 7 | * 8 | * This file is only used internally in libmdb and its definitions 9 | * are not exposed publicly. 10 | */ 11 | /* $OpenLDAP$ */ 12 | /* This work is part of OpenLDAP Software . 13 | * 14 | * Copyright 2000-2013 The OpenLDAP Foundation. 15 | * All rights reserved. 16 | * 17 | * Redistribution and use in source and binary forms, with or without 18 | * modification, are permitted only as authorized by the OpenLDAP 19 | * Public License. 20 | * 21 | * A copy of this license is available in the file LICENSE in the 22 | * top-level directory of the distribution or, alternatively, at 23 | * . 24 | */ 25 | 26 | #ifndef _MDB_MIDL_H_ 27 | #define _MDB_MIDL_H_ 28 | 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /** @defgroup internal MDB Internals 36 | * @{ 37 | */ 38 | 39 | /** @defgroup idls ID List Management 40 | * @{ 41 | */ 42 | /** A generic unsigned ID number. These were entryIDs in back-bdb. 43 | * Preferably it should have the same size as a pointer. 44 | */ 45 | typedef size_t MDB_ID; 46 | 47 | /** An IDL is an ID List, a sorted array of IDs. The first 48 | * element of the array is a counter for how many actual 49 | * IDs are in the list. In the original back-bdb code, IDLs are 50 | * sorted in ascending order. For libmdb IDLs are sorted in 51 | * descending order. 52 | */ 53 | typedef MDB_ID *MDB_IDL; 54 | 55 | /* IDL sizes - likely should be even bigger 56 | * limiting factors: sizeof(ID), thread stack size 57 | */ 58 | #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ 59 | #define MDB_IDL_DB_SIZE (1<. 13 | */ 14 | #define _XOPEN_SOURCE 500 /* srandom(), random() */ 15 | #include 16 | #include 17 | #include 18 | #include "lmdb.h" 19 | 20 | #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) 21 | #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) 22 | #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ 23 | "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) 24 | 25 | int main(int argc,char * argv[]) 26 | { 27 | int i = 0, j = 0, rc; 28 | MDB_env *env; 29 | MDB_dbi dbi; 30 | MDB_val key, data; 31 | MDB_txn *txn; 32 | MDB_stat mst; 33 | MDB_cursor *cursor, *cur2; 34 | MDB_cursor_op op; 35 | int count; 36 | int *values; 37 | char sval[32] = ""; 38 | 39 | srandom(time(NULL)); 40 | 41 | count = (random()%384) + 64; 42 | values = (int *)malloc(count*sizeof(int)); 43 | 44 | for(i = 0;i -1; i-= (random()%5)) { 86 | j++; 87 | txn=NULL; 88 | E(mdb_txn_begin(env, NULL, 0, &txn)); 89 | sprintf(sval, "%03x ", values[i]); 90 | if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { 91 | j--; 92 | mdb_txn_abort(txn); 93 | } else { 94 | E(mdb_txn_commit(txn)); 95 | } 96 | } 97 | free(values); 98 | printf("Deleted %d values\n", j); 99 | 100 | E(mdb_env_stat(env, &mst)); 101 | E(mdb_txn_begin(env, NULL, 1, &txn)); 102 | E(mdb_cursor_open(txn, dbi, &cursor)); 103 | printf("Cursor next\n"); 104 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 105 | printf("key: %.*s, data: %.*s\n", 106 | (int) key.mv_size, (char *) key.mv_data, 107 | (int) data.mv_size, (char *) data.mv_data); 108 | } 109 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 110 | printf("Cursor last\n"); 111 | E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); 112 | printf("key: %.*s, data: %.*s\n", 113 | (int) key.mv_size, (char *) key.mv_data, 114 | (int) data.mv_size, (char *) data.mv_data); 115 | printf("Cursor prev\n"); 116 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { 117 | printf("key: %.*s, data: %.*s\n", 118 | (int) key.mv_size, (char *) key.mv_data, 119 | (int) data.mv_size, (char *) data.mv_data); 120 | } 121 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); 122 | printf("Cursor last/prev\n"); 123 | E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); 124 | printf("key: %.*s, data: %.*s\n", 125 | (int) key.mv_size, (char *) key.mv_data, 126 | (int) data.mv_size, (char *) data.mv_data); 127 | E(mdb_cursor_get(cursor, &key, &data, MDB_PREV)); 128 | printf("key: %.*s, data: %.*s\n", 129 | (int) key.mv_size, (char *) key.mv_data, 130 | (int) data.mv_size, (char *) data.mv_data); 131 | 132 | mdb_txn_abort(txn); 133 | 134 | printf("Deleting with cursor\n"); 135 | E(mdb_txn_begin(env, NULL, 0, &txn)); 136 | E(mdb_cursor_open(txn, dbi, &cur2)); 137 | for (i=0; i<50; i++) { 138 | if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT))) 139 | break; 140 | printf("key: %p %.*s, data: %p %.*s\n", 141 | key.mv_data, (int) key.mv_size, (char *) key.mv_data, 142 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); 143 | E(mdb_del(txn, dbi, &key, NULL)); 144 | } 145 | 146 | printf("Restarting cursor in txn\n"); 147 | for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { 148 | if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op))) 149 | break; 150 | printf("key: %p %.*s, data: %p %.*s\n", 151 | key.mv_data, (int) key.mv_size, (char *) key.mv_data, 152 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); 153 | } 154 | mdb_cursor_close(cur2); 155 | E(mdb_txn_commit(txn)); 156 | 157 | printf("Restarting cursor outside txn\n"); 158 | E(mdb_txn_begin(env, NULL, 0, &txn)); 159 | E(mdb_cursor_open(txn, dbi, &cursor)); 160 | for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { 161 | if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op))) 162 | break; 163 | printf("key: %p %.*s, data: %p %.*s\n", 164 | key.mv_data, (int) key.mv_size, (char *) key.mv_data, 165 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); 166 | } 167 | mdb_cursor_close(cursor); 168 | mdb_close(env, dbi); 169 | 170 | mdb_txn_abort(txn); 171 | mdb_env_close(env); 172 | 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /src/misc.cpp: -------------------------------------------------------------------------------- 1 | 2 | // This file is part of node-lmdb, the Node.js binding for lmdb 3 | // Copyright (c) 2013 Timur Kristóf 4 | // Licensed to you under the terms of the MIT license 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #include "node-lmdb.h" 25 | #include 26 | #include 27 | 28 | void setupExportMisc(Handle exports) { 29 | Local versionObj = Object::New(); 30 | 31 | int major, minor, patch; 32 | char *str = mdb_version(&major, &minor, &patch); 33 | versionObj->Set(String::NewSymbol("versionString"), String::New(str)); 34 | versionObj->Set(String::NewSymbol("major"), Integer::New(major)); 35 | versionObj->Set(String::NewSymbol("minor"), Integer::New(minor)); 36 | versionObj->Set(String::NewSymbol("patch"), Integer::New(patch)); 37 | 38 | Persistent v = Persistent::New(versionObj); 39 | exports->Set(String::NewSymbol("version"), v); 40 | } 41 | 42 | void setFlagFromValue(int *flags, int flag, const char *name, bool defaultValue, Local options) { 43 | Handle opt = options->Get(String::NewSymbol(name)); 44 | if (opt->IsBoolean() ? opt->BooleanValue() : defaultValue) { 45 | *flags |= flag; 46 | } 47 | } 48 | 49 | argtokey_callback_t argToKey(const Handle &val, MDB_val &key, bool keyIsUint32) { 50 | // Check key type 51 | if (keyIsUint32 && !val->IsUint32()) { 52 | ThrowException(Exception::Error(String::New("Invalid key. keyIsUint32 specified on the database, but the given key was not an unsigned 32-bit integer"))); 53 | return nullptr; 54 | } 55 | if (!keyIsUint32 && !val->IsString()) { 56 | ThrowException(Exception::Error(String::New("Invalid key. String key expected, because keyIsUint32 isn't specified on the database."))); 57 | return nullptr; 58 | } 59 | 60 | // Handle uint32_t key 61 | if (keyIsUint32) { 62 | uint32_t *v = new uint32_t; 63 | *v = val->Uint32Value(); 64 | 65 | key.mv_size = sizeof(uint32_t); 66 | key.mv_data = v; 67 | 68 | return ([](MDB_val &key) -> void { 69 | delete (uint32_t*)key.mv_data; 70 | }); 71 | } 72 | 73 | // Handle string key 74 | CustomExternalStringResource::writeTo(val->ToString(), &key); 75 | return ([](MDB_val &key) -> void { 76 | delete (uint16_t*)key.mv_data; 77 | }); 78 | 79 | return nullptr; 80 | } 81 | 82 | Handle keyToHandle(MDB_val &key, bool keyIsUint32) { 83 | if (keyIsUint32) { 84 | return Integer::NewFromUnsigned(*((uint32_t*)key.mv_data)); 85 | } 86 | else { 87 | return valToString(key); 88 | } 89 | } 90 | 91 | Handle valToString(MDB_val &data) { 92 | return String::NewExternal(new CustomExternalStringResource(&data)); 93 | } 94 | 95 | Handle valToBinary(MDB_val &data) { 96 | return Buffer::New( 97 | // NOTE: newer node API will need this parameter 98 | // v8::Isolate::GetCurrent(), 99 | (char*)data.mv_data, 100 | data.mv_size, 101 | [](char*, void*) -> void { 102 | /* Don't need to do anything here, because the data belongs to LMDB anyway */ 103 | }, 104 | nullptr 105 | )->handle_; 106 | } 107 | 108 | Handle valToNumber(MDB_val &data) { 109 | return Number::New(*((double*)data.mv_data)); 110 | } 111 | 112 | Handle valToBoolean(MDB_val &data) { 113 | return Boolean::New(*((bool*)data.mv_data)); 114 | } 115 | 116 | void consoleLog(const char *msg) { 117 | Handle str = String::New("console.log('"); 118 | str = String::Concat(str, String::New(msg)); 119 | str = String::Concat(str, String::New("');")); 120 | 121 | Local