├── .gitignore ├── .travis.yml ├── AUTHORS ├── LICENSE ├── Makefile ├── README.md ├── build.sh ├── doc └── index.html ├── lua └── examples │ ├── basic.lua │ ├── filter.lua │ ├── iterator.lua │ ├── rmdbs.sh │ ├── runtests.sh │ ├── serialize.lua │ └── tostring.lua ├── rebuild.sh ├── remove.sh ├── rockspec ├── lua-leveldb-0.2-2.rockspec ├── lua-leveldb-0.2-3.rockspec ├── lua-leveldb-0.3-1.rockspec ├── lua-leveldb-0.4-1.rockspec └── lua-leveldb-git-1.rockspec └── src ├── batch.cc ├── batch.hpp ├── db.cc ├── db.hpp ├── iter.cc ├── iter.hpp ├── lib.hpp ├── lua-leveldb.cc ├── lua-leveldb.hpp ├── lua.c ├── lua.h ├── lua.hpp ├── opt.cc ├── opt.hpp ├── utils.cc └── utils.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Luarocks 2 | build.luarocks/ 3 | 4 | # Eclipse stuff 5 | .project 6 | .cproject 7 | .settings 8 | .buildpath 9 | 10 | # Examples dbs 11 | lua/examples/*.db 12 | lua/unit/*.db 13 | 14 | # http://www.gnu.org/software/automake 15 | 16 | Makefile.in 17 | /ar-lib 18 | /mdate-sh 19 | /py-compile 20 | /test-driver 21 | /ylwrap 22 | 23 | # http://www.gnu.org/software/autoconf 24 | 25 | /autom4te.cache 26 | /autoscan.log 27 | /autoscan-*.log 28 | /aclocal.m4 29 | /compile 30 | /config.guess 31 | /config.h.in 32 | /config.sub 33 | /configure 34 | /configure.scan 35 | /depcomp 36 | /install-sh 37 | /missing 38 | /stamp-h1 39 | 40 | # https://www.gnu.org/software/libtool/ 41 | 42 | /ltmain.sh 43 | 44 | # http://www.gnu.org/software/texinfo 45 | 46 | /texinfo.tex 47 | 48 | # http://www.gnu.org/software/m4/ 49 | 50 | m4/libtool.m4 51 | m4/ltoptions.m4 52 | m4/ltsugar.m4 53 | m4/ltversion.m4 54 | m4/lt~obsolete.m4 55 | autom4te.cache 56 | 57 | # C ignores 58 | # Prerequisites 59 | *.d 60 | 61 | # Object files 62 | *.o 63 | *.ko 64 | *.obj 65 | *.elf 66 | 67 | # Linker output 68 | *.ilk 69 | *.map 70 | *.exp 71 | 72 | # Precompiled Headers 73 | *.gch 74 | *.pch 75 | 76 | # Libraries 77 | *.lib 78 | *.a 79 | *.la 80 | *.lo 81 | *.Plo 82 | 83 | # Shared objects (inc. Windows DLLs) 84 | *.dll 85 | *.so 86 | *.so.* 87 | *.dylib 88 | 89 | # Executables 90 | *.exe 91 | *.out 92 | *.app 93 | *.i*86 94 | *.x86_64 95 | *.hex 96 | 97 | # Debug files 98 | *.dSYM/ 99 | *.su 100 | *.idb 101 | *.pdb 102 | 103 | # Kernel Module Compile Results 104 | *.mod* 105 | *.cmd 106 | .tmp_versions/ 107 | modules.order 108 | Module.symvers 109 | Mkfile.old 110 | dkms.conf 111 | 112 | # GDB 113 | .gdb_history 114 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: C++ 2 | 3 | before_install: 4 | - sudo apt-get update -qq 5 | - sudo apt-get install -y lua5.1 liblua5.1-dev lua5.2 liblua5.2-dev lua5.3 liblua5.3-dev libsnappy-dev libleveldb-dev 6 | 7 | install: true 8 | 9 | matrix: 10 | include: 11 | - name: "Lua 5.1" 12 | env: LUA_VERSION=5.1 13 | - name: "Lua 5.2" 14 | env: LUA_VERSION=5.2 15 | - name: "Lua 5.3" 16 | env: LUA_VERSION=5.3 17 | 18 | script: make LUA_VERSION=$LUA_VERSION 19 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Marco Pompili 2 | ============= 3 | pompilimrc@gmail.com 4 | lua@mg.odd.red 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | lua-leveldb license 2 | ------------------- 3 | 4 | The lua-leveldb code is licensed under the terms of the MIT license reproduced below. 5 | This means that lua-leveldb is free software and can be used for both academic and 6 | commercial purposes at absolutely no cost. 7 | 8 | Note that leveldb library itself (included for convenience) is licensed under: 9 | BSD-3 (http://opensource.org/licenses/BSD-3-Clause). 10 | 11 | =============================================================================== 12 | The MIT License (MIT) 13 | 14 | Copyright(c) 2011—2021 lua-leveldb author Marco Pompili 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in 24 | all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | THE SOFTWARE. 33 | 34 | =============================================================================== 35 | 36 | (end of LICENSE) 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | CFLAGS=-Wall -fPIC -shared 4 | CXXFLAGS=-Wall -fPIC -shared 5 | VPATH=src 6 | LDLIBS=-lleveldb -lsnappy -lpthread 7 | CDEPS=src/*.h 8 | CXXDEPS=src/*.hpp 9 | OBJS=src/lua.o src/batch.o src/db.o src/iter.o src/opt.o src/utils.o src/lua-leveldb.o 10 | RM=rm -f 11 | TARGET=lualeveldb.so 12 | 13 | # Add a custom version below (5.1/5.2/5.3) 14 | LUA_VERSION?=5.3 15 | LUA_PREFIX_DIR?=/usr 16 | LUA_LIBDIR=$(LUA_PREFIX_DIR)/lib/lua/$(LUA_VERSION) 17 | LUA_INCDIR=$(LUA_PREFIX_DIR)/include/lua$(LUA_VERSION) 18 | LUA_SHAREDIR=$(LUA_PREFIX_DIR)/share/lua/$(LUA_VERSION) 19 | 20 | 21 | $(TARGET): $(OBJS) 22 | @echo -e '\033[0;36mBuilding target $@\033[0m' 23 | ifneq ($(wildcard $(LUA_LIBDIR)),) 24 | $(CXX) $(CXXFLAGS) -o $(TARGET) -L$(LUA_LIBDIR) $(OBJS) $(LDLIBS) 25 | else 26 | $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS) $(LDLIBS) 27 | endif 28 | 29 | %.o: %.c $(CDEPS) 30 | ifneq ($(wildcard $(LUA_INCDIR)),) 31 | $(CC) -c -o $@ $< $(CFLAGS) -I$(LUA_INCDIR) 32 | else 33 | $(CC) -c -o $@ $< $(CFLAGS) 34 | endif 35 | 36 | %.o: %.cc $(CXXDEPS) 37 | ifneq ($(wildcard $(LUA_INCDIR)),) 38 | $(CXX) -c -o $@ $< $(CXXFLAGS) -I$(LUA_INCDIR) 39 | else 40 | $(CXX) -c -o $@ $< $(CXXFLAGS) 41 | endif 42 | 43 | liblualeveldb.o: lua.h batch.hpp db.hpp iter.hpp opt.hpp utils.hpp lua-leveldb.hpp 44 | ifneq ($(wildcard $(LUA_INCDIR)),) 45 | $(CXX) $(CXXFLAGS) -o -I$(LUA_INCDIR) 46 | else 47 | $(CXX) $(CXXFLAGS) -o 48 | endif 49 | 50 | .PHONY: clean 51 | clean: 52 | $(RM) $(OBJS) 53 | $(RM) $(TARGET) 54 | 55 | install: 56 | @echo -e '\033[0;32mInstalling with luarocks\033[0m' 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-leveldb 2 | =========== 3 | Lua bindings for Google's LevelDB key/store database. 4 | 5 | [![Build Status](https://travis-ci.org/marcopompili/lua-leveldb.svg?branch=master)][travis] [![](https://img.shields.io/luarocks/v/marcopompili/lua-leveldb)](https://luarocks.org/modules/marcopompili/lua-leveldb) 6 | 7 | From the GoogleCode page: 8 | "The LevelDB library provides a persistent key value store. Keys and values are arbitrary byte arrays. 9 | The keys are ordered within the key value store according to a user-specified comparator function." 10 | 11 | I wrote this extension because I needed a fast embeddable key/value database for TCP/IP packet analysis. I had to analyze big files in pcap format and divide the traffic using some specific rules. This simple Lua extension allows you to access LevelDB from Lua in a quite simple way. Lua is also used as extension language for WireShark. 12 | 13 | Most of the basic options and functions are supported right now, but still not the full set of operations permitted by LevelDB. Take a look at the examples below. 14 | 15 | Installation 16 | ------------ 17 | 18 | ### Using Luarocks (Recommended) 19 | You can install lua-leveldb with the Luarocks packaging system (if you got Lua >= 5.1): 20 | ``` 21 | sudo luarocks install lua-leveldb 22 | ``` 23 | 24 | Or if you want to build the latest Luarock locally use the make script like this: 25 | ``` 26 | ./make.sh git 1 27 | ``` 28 | 29 | Or if you want to build the latest binary locally use `make` like this (for Lua = 5.1): 30 | ``` 31 | LUA_VERSION=5.1 make 32 | ``` 33 | 34 | ### Manually 35 | The library is packed as a Luarock extension, check out [luarocks.org](http://luarocks.org/). 36 | * Before installing be sure that you got LevelDB correctly installed for your Linux distribution. 37 | * To install execute `make.sh` as `root`, this script should build the library and install it as a Luarock package. 38 | * To remove the library use `remove.sh` (as `root`) to remove the package and delete the built files. 39 | * You can rebuild lua-leveldb using the `rebuild.sh` script. 40 | 41 | Manual (system-wide) installation (on Debian 8): 42 | ``` 43 | sudo cp liblualeveldb.so /usr/local/lib/ 44 | sudo mkdir /usr/local/lib/lua/5.1/ 45 | cd /usr/local/lib/lua/5.1/ 46 | sudo ln -s ../../lua-leveldb.so lua-leveldb.so 47 | ``` 48 | 49 | Note - Library name collision with leveldb.so 50 | --------------------------------------------- 51 | 52 | When LevelDB libraries are installed, there is a file with name `libleveldb.so` in `/usr/lib/`. When doing a `require 'leveldb'` in your lua-code, the loader code will find that file first. To make the loading unambiguous, it is necessary to refer this library as `lualeveldb.so`. 53 | See the below example code for `require 'lualeveldb'`. 54 | 55 | Support 56 | ------- 57 | The extension still not support the full set of operations permitted by the LevelDB library. 58 | 59 | These are the current possible operation: 60 | * Basic open/close/repair database operations supported. 61 | * Basic database write, read and delete operations. 62 | * Partial access to most important options settings is supported. 63 | * Iterators with seek and iteration operations are supported. 64 | * Atomic batch updates supported. 65 | * Experimental support for unique values. 66 | * Added support for storing string, numeric and boolean values. 67 | * ToString support for various objects. 68 | 69 | Basic Example 70 | ------------- 71 | This is a simple example about how to use the Lua extension for Google's LevelDB, just putting some data and getting it back: 72 | 73 | ```lua 74 | leveldb = require 'lualeveldb' 75 | 76 | opt = leveldb.options() 77 | opt.createIfMissing = true 78 | opt.errorIfExists = false 79 | 80 | local test_key = 'key1' 81 | local test_val = 'value1' 82 | 83 | print ('opening test.db') 84 | testdb = leveldb.open(opt, 'test.db') 85 | 86 | if leveldb.check(testdb) 87 | then 88 | if testdb:put(test_key, test_val) 89 | then 90 | print ('key1: '.. testdb:get(test_key)) 91 | end 92 | end 93 | 94 | leveldb.close(testdb) 95 | 96 | testdb = leveldb.open(opt, 'test.db') 97 | testdb:put('key2', 123456) 98 | 99 | print ('key2: ' .. testdb:get('key2')) 100 | 101 | leveldb.close(testdb) 102 | ``` 103 | 104 | Iterator Example 105 | ---------------- 106 | An example using iterators: 107 | 108 | ```lua 109 | leveldb = require 'lualeveldb' 110 | 111 | local opt = leveldb.options() 112 | opt.createIfMissing = true 113 | opt.errorIfExists = false 114 | 115 | -- db example 116 | local db = leveldb.open(opt, 'iterator.db') 117 | 118 | assert(db:put('key1s', 'value1')) 119 | assert(db:put('key1n', 1)) 120 | assert(db:put('key2s', 'value2')) 121 | assert(db:put('key2n', 2)) 122 | assert(db:put('key3s', 'value3')) 123 | assert(db:put('key3n', 3.14)) 124 | 125 | local iter = db:iterator() 126 | 127 | iter:seekToFirst() 128 | 129 | while(iter:valid()) 130 | do 131 | local key = iter:key() 132 | local value = iter:value(); 133 | print(iter:key() .. ' => ' .. '(' .. type(value) .. ') ' .. tostring(value)) 134 | 135 | iter:next() 136 | end 137 | 138 | iter:del() 139 | 140 | leveldb.close(db) 141 | 142 | ``` 143 | 144 | Using the Bloom filter 145 | ---------------------- 146 | ```lua 147 | leveldb = require 'lualeveldb' 148 | 149 | opt = leveldb.options() 150 | opt.createIfMissing = true 151 | opt.errorIfExists = false 152 | 153 | -- setting the bloom filter into the options 154 | leveldb.bloomFilterPolicy(opt, 10) 155 | 156 | print(opt) 157 | ``` 158 | 159 | Serialization 160 | ------------- 161 | Here an examples of dealing with serialization. 162 | ```lua 163 | leveldb = require 'lualeveldb' 164 | require 'serialization' 165 | 166 | --[[ 167 | Lua >=5.3.3 extended the format option "%q" to work also with 168 | numbers (plus nil and Booleans), again writing them in a 169 | proper way to be read back by Lua. 170 | ]]-- 171 | function serialize(o) 172 | local t = type(o) 173 | if t == "number" 174 | or t == "string" 175 | or t == "boolean" 176 | or t == "nil" 177 | then 178 | return string.format("%q", o) 179 | else 180 | error("cannot serialize a: " .. type(o)) 181 | end 182 | end 183 | 184 | function deserialize(s) 185 | local n = tonumber(s) 186 | if n ~= nil then 187 | return n 188 | elseif s == 'true' then 189 | return true 190 | elseif s == 'false' then 191 | return false 192 | else 193 | return s 194 | end 195 | end 196 | 197 | local opt = leveldb.options() 198 | opt.createIfMissing = true 199 | opt.errorIfExists = false 200 | 201 | local db = leveldb.open(opt, 'types.db') 202 | 203 | -- serialization example: simple serialization can be used for storing values, tables too. 204 | 205 | assert(db:put("string", "Oh hai Mark!")) 206 | assert(db:put("number", serialize(123456))) 207 | assert(db:put("boolean", serialize(true))) 208 | 209 | local function check(val, expected) 210 | assert(type(deserialize(val)) == expected, "expected " .. expected .. ", found: " .. type(val)) 211 | end 212 | 213 | check(db:get("string"), "string") 214 | check(db:get("number"), "number") 215 | check(db:get("boolean"), "boolean") 216 | 217 | print("all type tests are fine!") 218 | 219 | leveldb.close(db) 220 | ``` 221 | 222 | Example files 223 | ------------- 224 | Examples above can be found in the `lua/example` folder. 225 | 226 | Notes 227 | ----- 228 | Lua-leveldb is compatible with Lua 5.1 and newer. 229 | 230 | Versions 231 | -------- 232 | - =0.4: Requires Lua 5.1 or newer, compatible with LuaJIT, writes simple buffers. 233 | - =0.3: Requires Lua 5.2 or newer, incompatible with LuaJIT, uses internal serialization for simple Lua types (no tables). 234 | - <=0.2: Old versions, stay away. 235 | 236 | License 237 | ------- 238 | The lua-leveldb code is licensed under the terms of the MIT license. 239 | This means that lua-leveldb is free software and can be used for both academic and 240 | commercial purposes at absolutely no cost, check the LICENSE file for details. 241 | 242 | Note that LevelDB library itself (included for convenience) is licensed under [BSD-3](http://opensource.org/licenses/BSD-3-Clause). 243 | 244 | Donate 245 | ------ 246 | Like the software? Feeling generous? Buy me a beer! :P 247 | - [![PayPal](https://img.shields.io/badge/%24-paypal-f39c12.svg)][paypal-donations] 248 | - BTC: `1DVAWeg259xjFWToQ3bycyE19Qy7dAVDKR` 249 | 250 | Contacts 251 | -------- 252 | - Problems? Questions? Open an issue here on GitHub. 253 | - [Twitter](https://twitter.com/pompilimrc) 254 | - [StackOverflow](https://stackoverflow.com/users/2555321/marcs) 255 | 256 | [travis]: https://travis-ci.org/marcopompili/lua-leveldb 257 | [paypal-donations]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZCEWXHNPK8JXN 258 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Author: Marco Pompili - pompilimrc@gmail.com 4 | # Script file for installing the dev version of lua-leveldb. 5 | 6 | if [ $# -lt 2 ] 7 | then 8 | echo -e "\e[1;31mUSAGE: $0 \e[0;31m[luarocks-path]\e[0m" 9 | echo -e "\e[0;32m[luarocks-path] is optional, just use it if you want to use a specific version of Lua.\e[0m" 10 | exit 1 11 | fi 12 | 13 | if [ $# -gt 2 ] 14 | then 15 | LUAROCKS=$3 16 | else 17 | LUAROCKS=luarocks 18 | fi 19 | 20 | set -e 21 | 22 | VERSION=$1 23 | REVISION=$2 24 | 25 | echo -e "Going for version $1 and revision $2..." 26 | 27 | echo -e "\033[0;32mlua-leveldb $VERSION-$REVISION\033[0m" 28 | 29 | $LUAROCKS --local make rockspec/lua-leveldb-$VERSION-$REVISION.rockspec 30 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | 24 | 25 | 26 | 27 | lua-leveldb 0.2 28 | 29 | 30 | 31 | 32 | 33 |

lua-leveldb 0.2

34 |

Lua binding for google's leveldb key/store database.

35 |

TODO: add documentation

36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /lua/examples/basic.lua: -------------------------------------------------------------------------------- 1 | leveldb = require 'lualeveldb' 2 | 3 | opt = leveldb.options() 4 | opt.createIfMissing = true 5 | opt.errorIfExists = false 6 | 7 | local db_file = 'basic.db' 8 | local test_key = 'key1' 9 | local test_val = 'val1' 10 | 11 | print ('opening ' .. db_file .. '...') 12 | local db = leveldb.open(opt, db_file) 13 | 14 | if leveldb.check(db) 15 | then 16 | if db:put(test_key, test_val) 17 | then 18 | print ('key1: '.. db:get(test_key)) 19 | end 20 | end 21 | 22 | leveldb.close(db) 23 | 24 | db = leveldb.open(opt, db_file) 25 | db:put('key2', '123456') 26 | 27 | print ('key2: ' .. db:get('key2')) 28 | 29 | leveldb.close(db) 30 | -------------------------------------------------------------------------------- /lua/examples/filter.lua: -------------------------------------------------------------------------------- 1 | leveldb = require 'lualeveldb' 2 | 3 | opt = leveldb.options() 4 | opt.createIfMissing = true 5 | opt.errorIfExists = false 6 | 7 | -- setting the bloom filter into the options 8 | leveldb.bloomFilterPolicy(opt, 10) 9 | 10 | print(opt) 11 | 12 | local test_key = 'key1' 13 | local test_val = 'value1' 14 | 15 | print ('opening test.db') 16 | testdb = leveldb.open(opt, 'filter.db') 17 | 18 | if leveldb.check(testdb) 19 | then 20 | if testdb:put(test_key, test_val) 21 | then 22 | print ('key1: '.. testdb:get(test_key)) 23 | end 24 | end 25 | 26 | leveldb.close(testdb) 27 | 28 | testdb = leveldb.open(opt, 'filter.db') 29 | testdb:put('key2', 123456) 30 | 31 | print ('key2: ' .. testdb:get('key2')) 32 | 33 | leveldb.close(testdb) 34 | -------------------------------------------------------------------------------- /lua/examples/iterator.lua: -------------------------------------------------------------------------------- 1 | leveldb = require 'lualeveldb' 2 | 3 | local opt = leveldb.options() 4 | opt.createIfMissing = true 5 | opt.errorIfExists = false 6 | 7 | -- db example 8 | local db = leveldb.open(opt, 'iterator.db') 9 | 10 | assert(db:put('key1s', 'value1')) 11 | assert(db:put('key1n', 1)) 12 | assert(db:put('key2s', 'value2')) 13 | assert(db:put('key2n', 2)) 14 | assert(db:put('key3s', 'value3')) 15 | assert(db:put('key3n', 3.14)) 16 | 17 | local iter = db:iterator() 18 | 19 | iter:seekToFirst() 20 | 21 | while(iter:valid()) 22 | do 23 | local key = iter:key() 24 | local value = iter:value(); 25 | print(iter:key() .. ' => ' .. '(' .. type(value) .. ') ' .. tostring(value)) 26 | 27 | iter:next() 28 | end 29 | 30 | iter:del() 31 | 32 | leveldb.close(db) 33 | -------------------------------------------------------------------------------- /lua/examples/rmdbs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf *.db 4 | -------------------------------------------------------------------------------- /lua/examples/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -eq 1 ] 4 | then 5 | INTR=$1 6 | else 7 | INTR=lua 8 | fi 9 | 10 | for f in *.lua; do 11 | echo -e "\nProcessing $f file.."; 12 | $INTR $f 13 | done 14 | 15 | echo "examples ran with:" 16 | $INTR -v 17 | -------------------------------------------------------------------------------- /lua/examples/serialize.lua: -------------------------------------------------------------------------------- 1 | leveldb = require 'lualeveldb' 2 | 3 | --[[ 4 | Lua >=5.3.3 extended the format option "%q" to work also with 5 | numbers (plus nil and Booleans), again writing them in a 6 | proper way to be read back by Lua. 7 | ]]-- 8 | function serialize(o) 9 | local t = type(o) 10 | if t == "number" 11 | or t == "string" 12 | or t == "boolean" 13 | or t == "nil" 14 | then 15 | return string.format("%q", o) 16 | else 17 | error("cannot serialize a: " .. type(o)) 18 | end 19 | end 20 | 21 | function deserialize(s) 22 | local n = tonumber(s) 23 | if n ~= nil then 24 | return n 25 | elseif s == 'true' then 26 | return true 27 | elseif s == 'false' then 28 | return false 29 | else 30 | return s 31 | end 32 | end 33 | 34 | local opt = leveldb.options() 35 | opt.createIfMissing = true 36 | opt.errorIfExists = false 37 | 38 | local db = leveldb.open(opt, 'types.db') 39 | 40 | -- serialization example: simple serialization can be used for storing values, tables too. 41 | 42 | assert(db:put("string", "Oh hai Mark!")) 43 | assert(db:put("number", serialize(123456))) 44 | assert(db:put("boolean", serialize(true))) 45 | 46 | local function check(val, expected) 47 | assert(type(deserialize(val)) == expected, "expected " .. expected .. ", found: " .. type(val)) 48 | end 49 | 50 | check(db:get("string"), "string") 51 | check(db:get("number"), "number") 52 | check(db:get("boolean"), "boolean") 53 | 54 | print("all type tests are fine!") 55 | 56 | leveldb.close(db) 57 | -------------------------------------------------------------------------------- /lua/examples/tostring.lua: -------------------------------------------------------------------------------- 1 | leveldb = require 'lualeveldb' 2 | 3 | local opt = leveldb.options() 4 | opt.createIfMissing = true 5 | opt.errorIfExists = false 6 | 7 | assert(type(tostring(opt)) == "string") 8 | print(opt) 9 | 10 | local db = leveldb.open (opt, 'tostring.db') 11 | 12 | assert(type(tostring(db)) == "string") 13 | print(db) 14 | -------------------------------------------------------------------------------- /rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./remove.sh 4 | 5 | ./build.sh git 1 /usr/bin/luarocks 6 | -------------------------------------------------------------------------------- /remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LUAROCKS="luarocks" 4 | 5 | $LUAROCKS --local remove lua-leveldb 6 | 7 | make clean 8 | -------------------------------------------------------------------------------- /rockspec/lua-leveldb-0.2-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-leveldb" 2 | version = "0.2-2" 3 | source = { 4 | url = "git://github.com/marcopompili/lua-leveldb.git", 5 | branch = "0.2", 6 | md5 = "fa05ed5865e02b7fd412c7ec43b20d85" 7 | } 8 | description = { 9 | summary = "LevelDB extension for Lua.", 10 | detailed = [[ 11 | LevelDB is a fast key-value storage library written 12 | at Google that provides an ordered mapping from string 13 | keys to string values. This is an extension to use 14 | LevelDB directly from Lua. It has been tested on Lua 5.1. 15 | ]], 16 | homepage = "https://github.com/marcopompili/lua-leveldb", 17 | license = "MIT/X11", 18 | maintainer = "Marco Pompili " 19 | } 20 | dependencies = { 21 | "lua >= 5.1" 22 | } 23 | external_dependencies = { 24 | LEVELDB_DB = { 25 | header = "leveldb/db.h" 26 | }, 27 | LEVELDB_STATUS = { 28 | header = "leveldb/status.h" 29 | }, 30 | LEVELDB_OPTIONS = { 31 | header = "leveldb/options.h" 32 | }, 33 | LEVELDB_WRITE_BATCH = { 34 | header = "leveldb/write_batch.h" 35 | }, 36 | LEVELDB_FILTER_POLICY = { 37 | header = "leveldb/filter_policy.h" 38 | } 39 | } 40 | build = { 41 | type = "make", 42 | install = { 43 | lib = { 44 | "leveldb.so" 45 | } 46 | }, 47 | modules = { 48 | leveldb = "src/lua-leveldb.cc", 49 | incdirs = { 50 | "$(LEVELDB_DB_INCDIR)", 51 | "$(LEVELDB_STATUS_INCDIR)", 52 | "$(LEVELDB_OPTIONS_INCDIR)", 53 | "$(LEVELDB_WRITE_BATCH_INCDIR)", 54 | "$(LEVELDB_FILTER_POLICY_INCDIR)" 55 | }, 56 | libdirs = { 57 | "$(LEVELDB_DB_LIBDIR)", 58 | "$(LEVELDB_STATUS_LIBDIR)", 59 | "$(LEVELDB_OPTIONS_LIBDIR)", 60 | "$(LEVELDB_WRITE_BATCH_LIBDIR)", 61 | "$(LEVELDB_FILTER_POLICY_LIBDIR)" 62 | } 63 | }, 64 | copy_directories = { "doc" } 65 | } -------------------------------------------------------------------------------- /rockspec/lua-leveldb-0.2-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-leveldb" 2 | version = "0.2-3" 3 | source = { 4 | url = "git://github.com/marcopompili/lua-leveldb.git", 5 | branch = "0.2", 6 | md5 = "fa05ed5865e02b7fd412c7ec43b20d85" 7 | } 8 | description = { 9 | summary = "LevelDB extension for Lua.", 10 | detailed = [[ 11 | LevelDB is a fast key-value storage library written 12 | at Google that provides an ordered mapping from string 13 | keys to string values. This is an extension to use 14 | LevelDB directly from Lua. It has been tested on Lua 5.2. 15 | ]], 16 | homepage = "https://github.com/marcopompili/lua-leveldb", 17 | license = "MIT/X11", 18 | maintainer = "Marco Pompili " 19 | } 20 | dependencies = { 21 | "lua >= 5.2" 22 | } 23 | external_dependencies = { 24 | LEVELDB_DB = { 25 | header = "leveldb/db.h" 26 | }, 27 | LEVELDB_STATUS = { 28 | header = "leveldb/status.h" 29 | }, 30 | LEVELDB_OPTIONS = { 31 | header = "leveldb/options.h" 32 | }, 33 | LEVELDB_WRITE_BATCH = { 34 | header = "leveldb/write_batch.h" 35 | }, 36 | LEVELDB_FILTER_POLICY = { 37 | header = "leveldb/filter_policy.h" 38 | } 39 | } 40 | build = { 41 | type = "make", 42 | install = { 43 | lib = { 44 | "leveldb.so" 45 | } 46 | }, 47 | modules = { 48 | leveldb = "src/lua-leveldb.cc", 49 | incdirs = { 50 | "$(LEVELDB_DB_INCDIR)", 51 | "$(LEVELDB_STATUS_INCDIR)", 52 | "$(LEVELDB_OPTIONS_INCDIR)", 53 | "$(LEVELDB_WRITE_BATCH_INCDIR)", 54 | "$(LEVELDB_FILTER_POLICY_INCDIR)" 55 | }, 56 | libdirs = { 57 | "$(LEVELDB_DB_LIBDIR)", 58 | "$(LEVELDB_STATUS_LIBDIR)", 59 | "$(LEVELDB_OPTIONS_LIBDIR)", 60 | "$(LEVELDB_WRITE_BATCH_LIBDIR)", 61 | "$(LEVELDB_FILTER_POLICY_LIBDIR)" 62 | } 63 | }, 64 | copy_directories = { "doc" } 65 | } -------------------------------------------------------------------------------- /rockspec/lua-leveldb-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-leveldb" 2 | version = "0.3-1" 3 | source = { 4 | url = "git://github.com/marcopompili/lua-leveldb.git", 5 | tag = "0.3" 6 | } 7 | description = { 8 | summary = "LevelDB extension for Lua.", 9 | detailed = [[ 10 | LevelDB is a fast key-value storage library written 11 | at Google that provides an ordered mapping from string 12 | keys to string values. This is an extension to use 13 | LevelDB directly from Lua. It has been tested on Lua 5.2. 14 | ]], 15 | homepage = "https://github.com/marcopompili/lua-leveldb", 16 | license = "MIT/X11", 17 | maintainer = "Marco Pompili " 18 | } 19 | dependencies = { 20 | "lua >= 5.2" 21 | } 22 | external_dependencies = { 23 | LEVELDB_DB = { 24 | header = "leveldb/db.h" 25 | }, 26 | LEVELDB_STATUS = { 27 | header = "leveldb/status.h" 28 | }, 29 | LEVELDB_OPTIONS = { 30 | header = "leveldb/options.h" 31 | }, 32 | LEVELDB_WRITE_BATCH = { 33 | header = "leveldb/write_batch.h" 34 | }, 35 | LEVELDB_FILTER_POLICY = { 36 | header = "leveldb/filter_policy.h" 37 | } 38 | } 39 | build = { 40 | type = "make", 41 | install = { 42 | lib = { 43 | "leveldb.so" 44 | } 45 | }, 46 | modules = { 47 | leveldb = "src/lua-leveldb.cc", 48 | incdirs = { 49 | "$(LEVELDB_DB_INCDIR)", 50 | "$(LEVELDB_STATUS_INCDIR)", 51 | "$(LEVELDB_OPTIONS_INCDIR)", 52 | "$(LEVELDB_WRITE_BATCH_INCDIR)", 53 | "$(LEVELDB_FILTER_POLICY_INCDIR)" 54 | }, 55 | libdirs = { 56 | "$(LEVELDB_DB_LIBDIR)", 57 | "$(LEVELDB_STATUS_LIBDIR)", 58 | "$(LEVELDB_OPTIONS_LIBDIR)", 59 | "$(LEVELDB_WRITE_BATCH_LIBDIR)", 60 | "$(LEVELDB_FILTER_POLICY_LIBDIR)" 61 | } 62 | }, 63 | copy_directories = { "doc" } 64 | } 65 | -------------------------------------------------------------------------------- /rockspec/lua-leveldb-0.4-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-leveldb" 2 | version = "0.4-1" 3 | source = { 4 | url = "git://github.com/marcopompili/lua-leveldb.git", 5 | tag = "0.4" 6 | } 7 | description = { 8 | summary = "LevelDB extension for Lua.", 9 | detailed = [[ 10 | LevelDB is a fast key-value storage library written 11 | at Google that provides an ordered mapping from string 12 | keys to string values. This is an extension to use 13 | LevelDB directly from Lua. It has been tested on Lua 5.1/5.2/5.3. 14 | ]], 15 | homepage = "https://github.com/marcopompili/lua-leveldb", 16 | license = "MIT/X11", 17 | maintainer = "Marco Pompili " 18 | } 19 | dependencies = { 20 | "lua >= 5.1" 21 | } 22 | external_dependencies = { 23 | LEVELDB_DB = { 24 | header = "leveldb/db.h" 25 | }, 26 | LEVELDB_STATUS = { 27 | header = "leveldb/status.h" 28 | }, 29 | LEVELDB_OPTIONS = { 30 | header = "leveldb/options.h" 31 | }, 32 | LEVELDB_WRITE_BATCH = { 33 | header = "leveldb/write_batch.h" 34 | }, 35 | LEVELDB_FILTER_POLICY = { 36 | header = "leveldb/filter_policy.h" 37 | } 38 | } 39 | build = { 40 | type = "make", 41 | install = { 42 | lib = { 43 | "lualeveldb.so" 44 | } 45 | }, 46 | modules = { 47 | leveldb = "src/lua-leveldb.cc", 48 | incdirs = { 49 | "$(LEVELDB_DB_INCDIR)", 50 | "$(LEVELDB_STATUS_INCDIR)", 51 | "$(LEVELDB_OPTIONS_INCDIR)", 52 | "$(LEVELDB_WRITE_BATCH_INCDIR)", 53 | "$(LEVELDB_FILTER_POLICY_INCDIR)" 54 | }, 55 | libdirs = { 56 | "$(LEVELDB_DB_LIBDIR)", 57 | "$(LEVELDB_STATUS_LIBDIR)", 58 | "$(LEVELDB_OPTIONS_LIBDIR)", 59 | "$(LEVELDB_WRITE_BATCH_LIBDIR)", 60 | "$(LEVELDB_FILTER_POLICY_LIBDIR)" 61 | } 62 | }, 63 | copy_directories = { "doc" } 64 | } -------------------------------------------------------------------------------- /rockspec/lua-leveldb-git-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-leveldb" 2 | version = "git-1" 3 | source = { 4 | url = "git://github.com/marcopompili/lua-leveldb.git", 5 | branch = "master" 6 | } 7 | description = { 8 | summary = "LevelDB extension for Lua.", 9 | detailed = [[ 10 | LevelDB is a fast key-value storage library written 11 | at Google that provides an ordered mapping from string 12 | keys to string values. This is an extension to use 13 | LevelDB directly from Lua. It has been tested on Lua 5.1/5.2/5.3. 14 | ]], 15 | homepage = "https://github.com/marcopompili/lua-leveldb", 16 | license = "MIT/X11", 17 | maintainer = "Marco Pompili " 18 | } 19 | dependencies = { 20 | "lua >= 5.1" 21 | } 22 | external_dependencies = { 23 | LEVELDB_DB = { 24 | header = "leveldb/db.h" 25 | }, 26 | LEVELDB_STATUS = { 27 | header = "leveldb/status.h" 28 | }, 29 | LEVELDB_OPTIONS = { 30 | header = "leveldb/options.h" 31 | }, 32 | LEVELDB_WRITE_BATCH = { 33 | header = "leveldb/write_batch.h" 34 | }, 35 | LEVELDB_FILTER_POLICY = { 36 | header = "leveldb/filter_policy.h" 37 | } 38 | } 39 | build = { 40 | type = "make", 41 | install = { 42 | lib = { 43 | "lualeveldb.so" 44 | } 45 | }, 46 | modules = { 47 | leveldb = "src/lua-leveldb.cc", 48 | incdirs = { 49 | "$(LEVELDB_DB_INCDIR)", 50 | "$(LEVELDB_STATUS_INCDIR)", 51 | "$(LEVELDB_OPTIONS_INCDIR)", 52 | "$(LEVELDB_WRITE_BATCH_INCDIR)", 53 | "$(LEVELDB_FILTER_POLICY_INCDIR)" 54 | }, 55 | libdirs = { 56 | "$(LEVELDB_DB_LIBDIR)", 57 | "$(LEVELDB_STATUS_LIBDIR)", 58 | "$(LEVELDB_OPTIONS_LIBDIR)", 59 | "$(LEVELDB_WRITE_BATCH_LIBDIR)", 60 | "$(LEVELDB_FILTER_POLICY_LIBDIR)" 61 | } 62 | }, 63 | copy_directories = { "doc" } 64 | } 65 | -------------------------------------------------------------------------------- /src/batch.cc: -------------------------------------------------------------------------------- 1 | #include "batch.hpp" 2 | 3 | /** 4 | * LevelDB atomic batch support 5 | * ---------------------------- 6 | */ 7 | 8 | /** 9 | * To string function for the WriteBatch object. 10 | */ 11 | int lvldb_batch_tostring(lua_State *L) { 12 | leveldb::WriteBatch batch = *(check_writebatch(L, 1)); 13 | 14 | std::ostringstream oss (std::ostringstream::out); 15 | oss << "Batch" << std::endl; 16 | 17 | lua_pushstring(L, oss.str().c_str()); 18 | 19 | return 1; 20 | } 21 | 22 | /** 23 | * Put a key,value into the batch. 24 | */ 25 | int lvldb_batch_put(lua_State *L) { 26 | leveldb::WriteBatch batch = *(check_writebatch(L, 1)); 27 | 28 | leveldb::Slice key = lua_to_slice(L, 2); 29 | leveldb::Slice value = lua_to_slice(L, 3); 30 | 31 | batch.Put(key, value); 32 | 33 | return 0; 34 | } 35 | 36 | /** 37 | * Delete a key from the batch. 38 | */ 39 | int lvldb_batch_del(lua_State *L) { 40 | leveldb::WriteBatch batch = *(check_writebatch(L, 1)); 41 | 42 | leveldb::Slice key = lua_to_slice(L, 2); 43 | 44 | batch.Delete(key); 45 | 46 | return 0; 47 | } 48 | 49 | /** 50 | * Clear the whole batch. 51 | */ 52 | int lvldb_batch_clear(lua_State *L) { 53 | leveldb::WriteBatch batch = *(check_writebatch(L, 1)); 54 | 55 | batch.Clear(); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/batch.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lua.hpp" 4 | #include "lib.hpp" 5 | #include "utils.hpp" 6 | 7 | int lvldb_batch_tostring(lua_State*); 8 | int lvldb_batch_put(lua_State*); 9 | int lvldb_batch_del(lua_State*); 10 | int lvldb_batch_clear(lua_State*); 11 | -------------------------------------------------------------------------------- /src/db.cc: -------------------------------------------------------------------------------- 1 | #include "db.hpp" 2 | 3 | /** 4 | * Check for a DB type. 5 | */ 6 | leveldb::DB *check_database(lua_State *L, int index) { 7 | luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); 8 | // UD-type: light meta @ lvldb_open() 9 | // LuaJIT doesn't support luaL_checkudata on light userdata 10 | // void *ud = luaL_checkudata(L, index, LVLDB_MT_DB); 11 | leveldb::DB *ud = (leveldb::DB*) lua_touserdata(L, 1); 12 | luaL_argcheck(L, ud != NULL, index, "'database' expected"); 13 | luaL_argcheck(L, lua_islightuserdata(L, index), index, "'database' expected"); 14 | 15 | return (leveldb::DB *) ud; 16 | } 17 | 18 | /** 19 | * Data Ops 20 | * --------------- 21 | * Data operations are binded to a DB instance, the first parameter 22 | * is always a DB but the notation used in Lua is db:put, db:get etc. 23 | */ 24 | 25 | /** 26 | * Method that put a key,value into a DB. 27 | * --------------------------------------$ 28 | * Inserts a key,value pair in the LevelDB Slice format. 29 | * This DB related method returns in Lua: 30 | * * True in case of correct insertion. 31 | * * False in case of error. 32 | */ 33 | int lvldb_database_put(lua_State *L) { 34 | leveldb::DB *db = check_database(L, 1); 35 | 36 | leveldb::Slice key = lua_to_slice(L, 2); 37 | leveldb::Slice value = lua_to_slice(L, 3); 38 | 39 | leveldb::Status s = db->Put(lvldb_wopt(L ,4), key, value); 40 | 41 | if (s.ok()) 42 | lua_pushboolean(L, true); 43 | else { 44 | std::cerr << "Error inserting key/value: " << s.ToString() << std::endl; 45 | lua_pushboolean(L, false); 46 | } 47 | 48 | return 1; 49 | } 50 | 51 | /** 52 | * Method that get a value with the given key from a DB. 53 | * -----------------------------------------------------$ 54 | * This DB related method returns in Lua: 55 | * * A string in case of success. 56 | * * False in case of error. 57 | */ 58 | int lvldb_database_get(lua_State *L) { 59 | leveldb::DB *db = check_database(L, 1); 60 | 61 | leveldb::Slice key = lua_to_slice(L, 2); 62 | std::string value; 63 | 64 | leveldb::Status s = db->Get(lvldb_ropt(L, 3), key, &value); 65 | 66 | if (s.ok()) { 67 | string_to_lua(L, value); 68 | } 69 | else { 70 | std::cerr << "Error getting value (get): " << s.ToString() << std::endl; 71 | lua_pushboolean(L, false); 72 | } 73 | 74 | return 1; 75 | } 76 | 77 | /** 78 | * Method that checks the given key's existence from a DB. 79 | * -----------------------------------------------------$ 80 | * This DB related method returns in Lua: 81 | * * True if key is in DB 82 | * * False in case of error, or key not exists. 83 | */ 84 | int lvldb_database_has(lua_State *L) { 85 | leveldb::DB *db = check_database(L, 1); 86 | 87 | leveldb::Slice key = lua_to_slice(L, 2); 88 | std::string value; 89 | 90 | leveldb::Status s = db->Get(lvldb_ropt(L, 3), key, &value); 91 | 92 | if (s.ok()) { 93 | lua_pushboolean(L, true); 94 | } 95 | else { 96 | lua_pushboolean(L, false); 97 | } 98 | 99 | return 1; 100 | } 101 | 102 | /** 103 | * 104 | */ 105 | int lvldb_database_set(lua_State *L) { 106 | leveldb::DB *db = check_database(L, 1); 107 | leveldb::Slice value = lua_to_slice(L, 2); 108 | 109 | // #ifdef __x86_64__ || __ppc64__ 110 | #ifdef __x86_64__ 111 | uint64_t i = 1; 112 | #else 113 | int i = 1; 114 | #endif 115 | 116 | bool found = false; 117 | 118 | leveldb::Iterator *it = db->NewIterator(lvldb_ropt(L, 3)); 119 | 120 | /* 121 | * initialization from the end, usually faster 122 | * on the long run. 123 | */ 124 | for(it->SeekToLast();it->Valid();it->Prev()) { 125 | if(value == it->value()) { 126 | found = true; 127 | break; 128 | } 129 | i++; 130 | } 131 | 132 | if(!found) { 133 | // char *id_str; 134 | // 135 | // long int m = 1000; 136 | // snprintf(id_str, m, "%i", i); 137 | // 138 | // Slice key = Slice(id_str); 139 | 140 | leveldb::Status s = db->Put(leveldb::WriteOptions(), "0", value); 141 | 142 | assert(s.ok()); 143 | } 144 | 145 | assert(it->status().ok()); 146 | 147 | delete it; 148 | 149 | return 0; 150 | } 151 | 152 | int lvldb_database_del(lua_State *L) { 153 | leveldb::DB *db = check_database(L, 1); 154 | 155 | leveldb::Slice key = lua_to_slice(L, 2); 156 | 157 | leveldb::Status s = db->Delete(lvldb_wopt(L, 3), key); 158 | 159 | if (s.ok()) 160 | lua_pushboolean(L, true); 161 | else { 162 | std::cerr << "Error deleting key/value entry: " << s.ToString() << std::endl; 163 | lua_pushboolean(L, false); 164 | } 165 | 166 | return 1; 167 | } 168 | 169 | /** 170 | * LevelDB iterator functions 171 | * -------------------------- 172 | */ 173 | 174 | /** 175 | * Method that creates an iterator. 176 | */ 177 | int lvldb_database_iterator(lua_State *L) { 178 | leveldb::DB *db = check_database(L, 1); 179 | 180 | leveldb::Iterator *it = db->NewIterator(lvldb_ropt(L, 2)); 181 | lua_pushlightuserdata(L, it); 182 | 183 | luaL_getmetatable(L, LVLDB_MT_ITER); 184 | lua_setmetatable(L, -2); 185 | 186 | return 1; 187 | } 188 | 189 | //TODO test it 190 | int lvldb_database_write(lua_State *L) { 191 | leveldb::DB *db = check_database(L, 1); 192 | 193 | leveldb::WriteBatch batch = *(check_writebatch(L, 2)); 194 | 195 | leveldb::Status s = db->Write(lvldb_wopt(L, 3), &batch); 196 | 197 | return 0; 198 | } 199 | 200 | /** 201 | * From the LevelDB documentation: 202 | * Snapshots provide consistent read-only views over the entire 203 | * state of the key-value store. ReadOptions::snapshot may be 204 | * non-NULL to indicate that a read should operate on a particular 205 | * version of the DB state. If ReadOptions::snapshot is NULL, 206 | * the read will operate on an implicit snapshot of the current state. 207 | */ 208 | int lvldb_database_snapshot(lua_State *L) { 209 | leveldb::DB *db = check_database(L, 1); 210 | 211 | const leveldb::Snapshot *snapshot = db->GetSnapshot(); 212 | 213 | lua_pushlightuserdata(L, (void*)snapshot); 214 | 215 | return 1; 216 | } 217 | 218 | /** 219 | * To string function for a DB. 220 | * ---------------------------- 221 | * Not to use in production environments. 222 | * Just prints the whole set of key,values from a DB. 223 | */ 224 | int lvldb_database_tostring(lua_State *L) { 225 | leveldb::DB *db = check_database(L, 1); 226 | std::ostringstream oss (std::ostringstream::out); 227 | 228 | leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); 229 | 230 | oss << "DB output:" << std::endl; 231 | it->SeekToFirst(); 232 | 233 | if(!it->Valid()) 234 | oss << "Database is empty." << std::endl; 235 | else { 236 | //for (it->SeekToFirst(); it->Valid(); it->Next()) { 237 | while(it->Valid()) { 238 | oss << it->key().ToString() << " -> " << it->value().ToString() << std::endl; 239 | 240 | #ifdef LUALEVELDB_LOGMODE 241 | //std::cout << "LOG: " << it->key().ToString() << " -> " << it->value().ToString() << std::endl; 242 | #endif 243 | 244 | it->Next(); 245 | } 246 | } 247 | 248 | assert(it->status().ok()); 249 | 250 | delete it; 251 | 252 | lua_pushstring(L, oss.str().c_str()); 253 | 254 | return 1; 255 | } 256 | -------------------------------------------------------------------------------- /src/db.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utils.hpp" 4 | 5 | leveldb::DB *check_database(lua_State*, int); 6 | 7 | int lvldb_database_put(lua_State*); 8 | int lvldb_database_get(lua_State*); 9 | int lvldb_database_has(lua_State*); 10 | int lvldb_database_set(lua_State*); 11 | int lvldb_database_del(lua_State*); 12 | int lvldb_database_iterator(lua_State*); 13 | int lvldb_database_write(lua_State*); 14 | int lvldb_database_snapshot(lua_State*); 15 | int lvldb_database_tostring(lua_State*); 16 | -------------------------------------------------------------------------------- /src/iter.cc: -------------------------------------------------------------------------------- 1 | #include "iter.hpp" 2 | 3 | /** 4 | * Check for an Iterator type. 5 | */ 6 | leveldb::Iterator *check_iter(lua_State *L) { 7 | luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); 8 | // UD-type: light meta @ lvldb_database_iterator() 9 | 10 | // LuaJIT doesn't support luaL_checkudata on light userdata 11 | //void *ud = luaL_checkudata(L, 1, LVLDB_MT_ITER); 12 | 13 | leveldb::Iterator *ud = (leveldb::Iterator*) lua_touserdata(L, 1); 14 | luaL_argcheck(L, ud != NULL, 1, "'iterator' expected"); 15 | luaL_argcheck(L, lua_islightuserdata(L, 1), 1, "'iterator' expected"); 16 | 17 | return ud; 18 | } 19 | 20 | int lvldb_iterator_delete(lua_State *L) { 21 | leveldb::Iterator *iter = check_iter(L); 22 | 23 | delete iter; 24 | 25 | return 0; 26 | } 27 | 28 | int lvldb_iterator_seek(lua_State *L) { 29 | leveldb::Iterator *iter = check_iter(L); 30 | 31 | std::string start = luaL_checkstring(L, 2); 32 | 33 | iter->Seek(start); 34 | 35 | return 0; 36 | } 37 | 38 | int lvldb_iterator_seek_to_first(lua_State *L) { 39 | leveldb::Iterator *iter = check_iter(L); 40 | 41 | iter->SeekToFirst(); 42 | 43 | return 0; 44 | } 45 | 46 | int lvldb_iterator_seek_to_last(lua_State *L) { 47 | leveldb::Iterator *iter = check_iter(L); 48 | 49 | iter->SeekToLast(); 50 | 51 | return 0; 52 | } 53 | 54 | int lvldb_iterator_valid(lua_State *L) { 55 | leveldb::Iterator *iter = check_iter(L); 56 | 57 | lua_pushboolean(L, iter->Valid()); 58 | 59 | return 1; 60 | } 61 | 62 | int lvldb_iterator_next(lua_State *L) { 63 | leveldb::Iterator *iter = check_iter(L); 64 | 65 | iter->Next(); 66 | 67 | return 0; 68 | } 69 | 70 | int lvldb_iterator_key(lua_State *L) { 71 | leveldb::Iterator *iter = check_iter(L); 72 | leveldb::Slice key = iter->key(); 73 | 74 | return string_to_lua(L, key.ToString()); 75 | } 76 | 77 | int lvldb_iterator_val(lua_State *L) { 78 | leveldb::Iterator *iter = check_iter(L); 79 | leveldb::Slice val = iter->value(); 80 | 81 | return string_to_lua(L, val.ToString()); 82 | } 83 | -------------------------------------------------------------------------------- /src/iter.hpp: -------------------------------------------------------------------------------- 1 | #include "lua.hpp" 2 | #include "lib.hpp" 3 | #include "utils.hpp" 4 | 5 | leveldb::Iterator *check_iter(lua_State*); 6 | 7 | int lvldb_iterator_delete(lua_State*); 8 | int lvldb_iterator_seek(lua_State*); 9 | int lvldb_iterator_seek_to_first(lua_State*); 10 | int lvldb_iterator_seek_to_last(lua_State*); 11 | int lvldb_iterator_valid(lua_State*); 12 | int lvldb_iterator_next(lua_State*); 13 | int lvldb_iterator_key(lua_State*); 14 | int lvldb_iterator_val(lua_State*); 15 | -------------------------------------------------------------------------------- /src/lib.hpp: -------------------------------------------------------------------------------- 1 | // LevelDB 2 | #include 3 | #include 4 | 5 | 6 | // LevelDB atomic ops 7 | #include 8 | 9 | // LevelDB filters 10 | #include 11 | -------------------------------------------------------------------------------- /src/lua-leveldb.cc: -------------------------------------------------------------------------------- 1 | #include "lua-leveldb.hpp" 2 | 3 | // Rock info 4 | #define LUALEVELDB_VERSION "Lua-LevelDB 0.4.0" 5 | #define LUALEVELDB_COPYRIGHT "Copyright (C) 2012-18, Lua-LevelDB by Marco Pompili (pompilimrc@gmail.com)." 6 | #define LUALEVELDB_DESCRIPTION "Lua bindings for Google's LevelDB library." 7 | #define LUALEVELDB_LOGMODE 0 8 | 9 | 10 | /** 11 | * Basic calls to LevelDB 12 | * ---------------------- 13 | */ 14 | 15 | /** 16 | * Opens a DB connection, based on the given options and filename. 17 | */ 18 | int lvldb_open(lua_State *L) { 19 | leveldb::DB *db; 20 | leveldb::Options *opt = check_options(L, 1); 21 | const char *filename = luaL_checkstring(L, 2); 22 | 23 | leveldb::Status s = leveldb::DB::Open(*(opt), filename, &db); 24 | 25 | if (!s.ok()) 26 | std::cerr << "lvldb_open: Error opening creating database: " << s.ToString() << std::endl; 27 | else { 28 | // Pushing pointer to the database in the stack 29 | lua_pushlightuserdata(L, db); 30 | 31 | luaL_getmetatable(L, LVLDB_MT_DB); 32 | lua_setmetatable(L, -2); 33 | } 34 | 35 | return 1; 36 | } 37 | 38 | /** 39 | * Close an open DB instance. 40 | */ 41 | int lvldb_close(lua_State *L) { 42 | leveldb::DB *db = (leveldb::DB*) lua_touserdata(L, 1); 43 | 44 | delete db; 45 | 46 | return 0; 47 | } 48 | 49 | /** 50 | * Create an options object with the defaults values. 51 | */ 52 | int lvldb_options(lua_State *L) { 53 | leveldb::Options *optp = (leveldb::Options*)lua_newuserdata(L, sizeof(leveldb::Options)); 54 | 55 | *(optp) = leveldb::Options(); // set default values 56 | 57 | luaL_getmetatable(L, LVLDB_MT_OPT); 58 | lua_setmetatable(L, -2); 59 | 60 | return 1; 61 | } 62 | 63 | /** 64 | * Create a WriteBatch object. 65 | */ 66 | int lvldb_batch(lua_State *L) { 67 | leveldb::WriteBatch batch; // initialization 68 | leveldb::WriteBatch *batchp = &batch; // store pointer 69 | 70 | lua_pushlightuserdata(L, batchp); 71 | luaL_getmetatable(L, LVLDB_MT_BATCH); 72 | lua_setmetatable(L, -2); 73 | 74 | return 1; 75 | } 76 | 77 | /** 78 | * Check for DB basic consistency. 79 | */ 80 | int lvldb_check(lua_State *L) { 81 | leveldb::DB *db = (leveldb::DB*) lua_touserdata(L, 1); 82 | 83 | lua_pushboolean(L, db != NULL ? true : false); 84 | 85 | return 1; 86 | } 87 | 88 | /** 89 | * Try repair the DB with the name in input. 90 | * ----------------------------------------- 91 | * From the LevelDB documentation: 92 | * If a database is corrupted (perhaps it cannot be opened when 93 | * paranoid checking is turned on), the leveldb::RepairDB function may 94 | * be used to recover as much of the data as possible. 95 | */ 96 | int lvldb_repair(lua_State *L) { 97 | std::string dbname = luaL_checkstring(L, 1); 98 | 99 | leveldb::Status s = leveldb::RepairDB(dbname, lvldb_opt(L, 2)); 100 | 101 | if(s.ok()) 102 | lua_pushboolean(L, true); 103 | else { 104 | std::cerr << "Error repairing database: " << s.ToString() << std::endl; 105 | lua_pushboolean(L, false); 106 | } 107 | 108 | return 1; 109 | } 110 | 111 | 112 | int lvldb_bloom_filter_policy(lua_State *L) { 113 | luaL_checktype(L, 1, LUA_TUSERDATA); 114 | leveldb::Options *opt = (leveldb::Options*)luaL_checkudata(L, 1, LVLDB_MT_OPT); 115 | int bits_per_key = lua_tonumber(L, 2); 116 | 117 | const leveldb::FilterPolicy *fp = leveldb::NewBloomFilterPolicy(bits_per_key); 118 | 119 | opt->filter_policy = fp; 120 | 121 | return 0; 122 | } 123 | 124 | /** 125 | * Wrapping up the library into Lua 126 | * -------------------------------- 127 | */ 128 | 129 | // empty 130 | static const struct luaL_Reg E[] = { { NULL, NULL } }; 131 | 132 | // main methods 133 | static const luaL_Reg lvldb_leveldb_m[] = { 134 | { "open", lvldb_open }, 135 | { "close", lvldb_close }, 136 | { "options", lvldb_options }, 137 | { "readOptions", lvldb_read_options }, 138 | { "writeOptions", lvldb_write_options }, 139 | { "repair ", lvldb_repair }, 140 | { "batch", lvldb_batch }, 141 | { "check", lvldb_check }, 142 | { "bloomFilterPolicy", lvldb_bloom_filter_policy }, 143 | { NULL, NULL } 144 | }; 145 | 146 | // options methods 147 | static const luaL_Reg lvldb_options_m[] = { 148 | { NULL, NULL } 149 | }; 150 | 151 | // options meta-methods 152 | static const luaL_Reg lvldb_options_meta[] = { 153 | { "__tostring", lvldb_options_tostring }, 154 | { NULL, NULL } 155 | }; 156 | 157 | // options getters 158 | static const Xet_reg_pre options_getters[] = { 159 | { "createIfMissing", get_bool, offsetof(leveldb::Options, create_if_missing) }, 160 | { "errorIfExists", get_bool, offsetof(leveldb::Options, error_if_exists) }, 161 | { "paranoidChecks", get_bool, offsetof(leveldb::Options, paranoid_checks) }, 162 | { "writeBufferSize", get_size, offsetof(leveldb::Options, write_buffer_size) }, 163 | { "maxOpenFiles", get_int, offsetof(leveldb::Options, max_open_files) }, 164 | { "blockSize", get_size, offsetof(leveldb::Options, block_size) }, 165 | { "blockRestartInterval", get_int, offsetof(leveldb::Options, block_restart_interval) }, 166 | { NULL, NULL } 167 | }; 168 | 169 | // options setters 170 | static const Xet_reg_pre options_setters[] = { 171 | { "createIfMissing", set_bool, offsetof(leveldb::Options, create_if_missing) }, 172 | { "errorIfExists", set_bool, offsetof(leveldb::Options, error_if_exists) }, 173 | { "paranoidChecks", set_bool, offsetof(leveldb::Options, paranoid_checks) }, 174 | { "writeBufferSize", set_size, offsetof(leveldb::Options, write_buffer_size) }, 175 | { "maxOpenFiles", set_int, offsetof(leveldb::Options, max_open_files) }, 176 | { "blockSize", set_size, offsetof(leveldb::Options, block_size) }, 177 | { "blockRestartInterval", set_int, offsetof(leveldb::Options, block_restart_interval) }, 178 | { NULL, NULL } 179 | }; 180 | 181 | // read options methods 182 | static const luaL_Reg lvldb_read_options_m[] = { 183 | { NULL, NULL } 184 | }; 185 | 186 | // read options meta-methods 187 | static const luaL_Reg lvldb_read_options_meta[] = { 188 | { "__tostring", lvldb_read_options_tostring }, 189 | { NULL, NULL } 190 | }; 191 | 192 | // read options getters 193 | static const Xet_reg_pre read_options_getters[] = { 194 | { "verifyChecksum", get_bool, offsetof(leveldb::ReadOptions, verify_checksums) }, 195 | { "fillCache", get_bool, offsetof(leveldb::ReadOptions, fill_cache) }, 196 | { NULL, NULL } 197 | }; 198 | 199 | // read options setters 200 | static const Xet_reg_pre read_options_setters[] = { 201 | { "verifyChecksum", set_bool, offsetof(leveldb::ReadOptions, verify_checksums) }, 202 | { "fillCache", set_bool, offsetof(leveldb::ReadOptions, fill_cache) }, 203 | { NULL, NULL } 204 | }; 205 | 206 | // write options methods 207 | static const luaL_Reg lvldb_write_options_m[] = { 208 | { NULL, NULL } 209 | }; 210 | 211 | // write options meta-methods 212 | static const luaL_Reg lvldb_write_options_meta[] = { 213 | { "__tostring", lvldb_write_options_tostring }, 214 | { NULL, NULL } 215 | }; 216 | 217 | // write options getters 218 | static const Xet_reg_pre write_options_getters[] = { 219 | { "sync", get_bool, offsetof(leveldb::WriteOptions, sync) }, 220 | { NULL, NULL } 221 | }; 222 | 223 | // write options setters 224 | static const Xet_reg_pre write_options_setters[] = { 225 | { "sync", set_bool, offsetof(leveldb::WriteOptions, sync) }, 226 | { NULL, NULL } 227 | }; 228 | 229 | // database methods 230 | static const luaL_Reg lvldb_database_m[] = { 231 | { "__tostring", lvldb_database_tostring }, 232 | { "put", lvldb_database_put }, 233 | { "set", lvldb_database_set }, 234 | { "get", lvldb_database_get }, 235 | { "has", lvldb_database_has }, 236 | { "delete", lvldb_database_del }, 237 | { "iterator", lvldb_database_iterator }, 238 | { "write", lvldb_database_write }, 239 | { "snapshot", lvldb_database_snapshot }, 240 | { NULL, NULL } 241 | }; 242 | 243 | // iterator methods 244 | static const struct luaL_Reg lvldb_iterator_m[] = { 245 | { "del", lvldb_iterator_delete }, 246 | { "seek", lvldb_iterator_seek }, 247 | { "seekToFirst", lvldb_iterator_seek_to_first }, 248 | { "seekToLast", lvldb_iterator_seek_to_last }, 249 | { "valid", lvldb_iterator_valid }, 250 | { "next", lvldb_iterator_next }, 251 | { "key", lvldb_iterator_key }, 252 | { "value", lvldb_iterator_val }, 253 | { NULL, NULL } 254 | }; 255 | 256 | // batch methods 257 | static const luaL_Reg lvldb_batch_m[] = { 258 | { "__tostring", lvldb_batch_tostring }, 259 | { "put", lvldb_batch_put }, 260 | { "delete", lvldb_batch_del }, 261 | { "clear", lvldb_batch_clear }, 262 | { NULL, NULL } 263 | }; 264 | 265 | extern "C" { 266 | 267 | // Initialization 268 | LUALIB_API int luaopen_lualeveldb(lua_State *L) { 269 | lua_newtable(L); 270 | 271 | // register module information 272 | lua_pushliteral(L, LUALEVELDB_VERSION); 273 | lua_setfield(L, -2, "_VERSION"); 274 | 275 | lua_pushliteral(L, LUALEVELDB_COPYRIGHT); 276 | lua_setfield(L, -2, "_COPYRIGHT"); 277 | 278 | lua_pushliteral(L, LUALEVELDB_DESCRIPTION); 279 | lua_setfield(L, -2, "_DESCRIPTION"); 280 | 281 | // LevelDB functions 282 | #if LUA_VERSION_NUM > 501 283 | luaL_setfuncs(L, lvldb_leveldb_m, 0); 284 | #else 285 | luaL_register(L, NULL, lvldb_leveldb_m); 286 | #endif 287 | 288 | // initialize meta-tables methods 289 | init_metatable(L, LVLDB_MT_DB, lvldb_database_m); 290 | init_complex_metatable(L, LVLDB_MT_OPT, lvldb_options_m, lvldb_options_meta, options_getters, options_setters); 291 | init_complex_metatable(L, LVLDB_MT_ROPT, lvldb_read_options_m, lvldb_read_options_meta, read_options_getters, read_options_setters); 292 | init_complex_metatable(L, LVLDB_MT_WOPT, lvldb_write_options_m, lvldb_write_options_meta, write_options_getters, write_options_setters); 293 | init_metatable(L, LVLDB_MT_ITER, lvldb_iterator_m); 294 | init_metatable(L, LVLDB_MT_BATCH, lvldb_batch_m); 295 | 296 | return 1; 297 | } 298 | 299 | } 300 | -------------------------------------------------------------------------------- /src/lua-leveldb.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | #include "lua.h" 6 | } 7 | 8 | #include "lib.hpp" 9 | 10 | #include "batch.hpp" 11 | #include "db.hpp" 12 | #include "iter.hpp" 13 | #include "opt.hpp" 14 | -------------------------------------------------------------------------------- /src/lua.c: -------------------------------------------------------------------------------- 1 | #include "lua.h" 2 | 3 | void Xet_add(lua_State *L, Xet_reg l) { 4 | for (; l->name; l++) { 5 | lua_pushstring(L, l->name); 6 | lua_pushlightuserdata(L, (void*) l); 7 | lua_settable(L, -3); 8 | } 9 | } 10 | 11 | int Xet_call(lua_State *L) { 12 | Xet_reg m = (Xet_reg) lua_touserdata(L, -1); 13 | lua_pop(L, 1); 14 | 15 | luaL_checktype(L, 1, LUA_TUSERDATA); 16 | 17 | return m->func(L, (void*) ((char*) lua_touserdata(L, 1) + m->offset)); 18 | } 19 | 20 | int index_handler(lua_State *L) { 21 | // stack has userdata, index 22 | lua_pushvalue(L, 2); // dup index 23 | lua_rawget(L, lua_upvalueindex(1)); // lookup member by name 24 | 25 | if (!lua_islightuserdata(L, -1)) { 26 | lua_pop(L, 1); // drop value 27 | lua_pushvalue(L, 2); // dup index 28 | lua_gettable(L, lua_upvalueindex(2)); // else try methods 29 | 30 | if (lua_isnil(L, -1)) // invalid member 31 | luaL_error(L, "cannot get member '%s'", lua_tostring(L, 2)); 32 | 33 | return 1; 34 | } 35 | 36 | return Xet_call(L); // call get function 37 | } 38 | 39 | int newindex_handler(lua_State *L) { 40 | // stack has userdata, index, value 41 | lua_pushvalue(L, 2); // dup index 42 | lua_rawget(L, lua_upvalueindex(1)); // lookup member by name 43 | 44 | if (!lua_islightuserdata(L, -1)) // invalid member 45 | luaL_error(L, "cannot set member '%s'", lua_tostring(L, 2)); 46 | 47 | return Xet_call(L); // call set function 48 | } 49 | 50 | /** 51 | * 52 | */ 53 | void init_complex_metatable(lua_State *L, const char *metatable_name, const luaL_Reg methods[], const luaL_Reg metamethods[], const Xet_reg_pre getters[], const Xet_reg_pre setters[]) { 54 | 55 | // create methods table, & add it to the table of globals 56 | lua_newtable(L); 57 | 58 | #if LUA_VERSION_NUM > 501 59 | luaL_setfuncs(L, methods, 0); 60 | #else 61 | luaL_register(L, NULL, methods); 62 | #endif 63 | 64 | int methods_stack = lua_gettop(L); 65 | 66 | // create meta-table for object, & add it to the registry 67 | luaL_newmetatable(L, metatable_name); 68 | 69 | // fill meta-table 70 | #if LUA_VERSION_NUM > 501 71 | luaL_setfuncs(L, metamethods, 0); 72 | #else 73 | luaL_register(L, NULL, metamethods); 74 | #endif 75 | 76 | int metatable_stack = lua_gettop(L); 77 | 78 | lua_pushliteral(L, "__metatable"); 79 | lua_pushvalue(L, methods_stack); // duplicate methods table 80 | lua_rawset(L, metatable_stack); // hide meta-table 81 | 82 | lua_pushliteral(L, "__index"); 83 | lua_pushvalue(L, metatable_stack); 84 | Xet_add(L, getters); 85 | lua_pushvalue(L, methods_stack); 86 | lua_pushcclosure(L, index_handler, 2); 87 | lua_rawset(L, metatable_stack); 88 | 89 | lua_pushliteral(L, "__newindex"); 90 | lua_newtable(L); 91 | Xet_add(L, setters); 92 | lua_pushcclosure(L, newindex_handler, 1); 93 | lua_rawset(L, metatable_stack); 94 | 95 | lua_settop(L, methods_stack-1); 96 | } 97 | 98 | /** 99 | * Procedure for adding a meta-table into the stack. 100 | */ 101 | void metatable_func(lua_State *L, const char *metatable, const struct luaL_Reg lib[]) { 102 | 103 | // let's build the function meta-table 104 | if (luaL_newmetatable(L, metatable) == 0) 105 | fprintf(stderr, "Warning: metatable %s is already set", metatable); 106 | 107 | lua_pushstring(L, "__index"); // meta-table already in the stack 108 | lua_pushvalue(L, -2); // push the meta-table 109 | lua_settable(L, -3); // meta-table.__index = meta-table 110 | 111 | // meta-table already on the stack 112 | #if LUA_VERSION_NUM > 501 113 | luaL_setfuncs(L, lib, 0); 114 | #else 115 | luaL_register(L, NULL, lib); 116 | #endif 117 | lua_pop(L, 1); 118 | } 119 | 120 | 121 | void init_metatable(lua_State *L, const char *metatable, const struct luaL_Reg lib[]) { 122 | 123 | // let's build the function meta-table 124 | if (luaL_newmetatable(L, metatable) == 0) 125 | fprintf(stderr, "Warning: metatable %s is already set", metatable); 126 | 127 | lua_pushstring(L, "__index"); // meta-table already in the stack 128 | lua_pushvalue(L, -2); // push the meta-table 129 | lua_settable(L, -3); // meta-table.__index = meta-table 130 | 131 | // meta-table already on the stack 132 | #if LUA_VERSION_NUM > 501 133 | luaL_setfuncs(L, lib, 0); 134 | #else 135 | luaL_register(L, NULL, lib); 136 | #endif 137 | lua_pop(L, 1); 138 | } 139 | -------------------------------------------------------------------------------- /src/lua.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lua.hpp" 4 | 5 | typedef int (*Xet_func)(lua_State *L, void *v); 6 | 7 | /* member info for get and set handlers */ 8 | typedef const struct { 9 | const char *name; // member name 10 | Xet_func func; // get or set function for type of member 11 | size_t offset; // offset of member within your_t 12 | } Xet_reg_pre; 13 | 14 | typedef Xet_reg_pre * Xet_reg; 15 | 16 | void Xet_add(lua_State *L, Xet_reg l); 17 | int Xet_call(lua_State *L); 18 | int index_handler(lua_State *L); 19 | int newindex_handler(lua_State *L); 20 | void init_complex_metatable(lua_State *L, const char *metatable_name, const luaL_Reg methods[], const luaL_Reg metamethods[], const Xet_reg_pre getters[], const Xet_reg_pre setters[]); 21 | void metatable_func(lua_State *L, const char *metatable, const struct luaL_Reg lib[]); 22 | void init_metatable(lua_State *L, const char *metatable, const struct luaL_Reg lib[]); 23 | -------------------------------------------------------------------------------- /src/lua.hpp: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | #include 3 | #else 4 | #include 5 | #include 6 | #include 7 | #endif 8 | -------------------------------------------------------------------------------- /src/opt.cc: -------------------------------------------------------------------------------- 1 | #include "opt.hpp" 2 | 3 | /** 4 | * Basic setters and getters 5 | * ------------------------- 6 | * Used to set values in the Options 7 | */ 8 | int get_int(lua_State *L, void *v) { 9 | lua_pushnumber(L, *(int*) v); 10 | return 1; 11 | } 12 | 13 | int set_int(lua_State *L, void *v) { 14 | #if LUA_VERSION_NUM < 503 15 | *(int*) v = luaL_checkint(L, 3); 16 | #else 17 | *(int*) v = luaL_checkinteger(L, 3); 18 | #endif 19 | return 0; 20 | } 21 | 22 | 23 | int get_number(lua_State *L, void *v) { 24 | lua_pushnumber(L, *(lua_Number*) v); 25 | return 1; 26 | } 27 | 28 | int set_number(lua_State *L, void *v) { 29 | *(lua_Number*) v = luaL_checknumber(L, 3); 30 | return 0; 31 | } 32 | 33 | //TODO test it 34 | int get_size(lua_State *L, void *v) { 35 | lua_pushinteger(L, *(lua_Integer*) v); 36 | return 1; 37 | } 38 | 39 | int set_size(lua_State *L, void *v) { 40 | *(lua_Integer*) v = luaL_checkinteger(L, 3); 41 | return 0; 42 | } 43 | 44 | int get_bool(lua_State *L, void *v) { 45 | lua_pushboolean(L, *(bool*) v); 46 | return 1; 47 | } 48 | 49 | int set_bool(lua_State *L, void *v) { 50 | *(bool*) v = lua_toboolean(L, 3); 51 | return 0; 52 | } 53 | 54 | //TODO test it 55 | int get_string(lua_State *L, void *v) { 56 | lua_pushstring(L, (char*) v); 57 | return 1; 58 | } 59 | 60 | //TODO test it 61 | int set_string(lua_State *L, void *v) { 62 | v = (char*)lua_tostring(L, 3); 63 | return 0; 64 | } 65 | 66 | /** 67 | * To string for the options type. 68 | */ 69 | int lvldb_options_tostring(lua_State *L) { 70 | leveldb::Options *opt = check_options(L, 1); 71 | 72 | std::ostringstream oss (std::ostringstream::out); 73 | oss << "Comparator: " << opt->comparator->Name() 74 | << "\nCreate if missing: " << bool_tostring(opt->create_if_missing) 75 | << "\nError if exists: " << bool_tostring(opt->error_if_exists) 76 | << "\nParanoid checks: " << bool_tostring(opt->paranoid_checks) 77 | << "\nEnvironment: " << pointer_tostring(opt->env) 78 | << "\nInfo log: " << pointer_tostring(opt->info_log) 79 | << "\nWrite buffer size: " << opt->write_buffer_size 80 | << "\nMax open files: " << opt->max_open_files 81 | << "\nBlock cache: " << pointer_tostring(opt->block_cache) 82 | << "\nBlock size: " << opt->block_size 83 | << "\nBlock restart interval: " << opt->block_restart_interval 84 | << "\nCompression: " << (opt->compression == 1 ? "Snappy Compression" : "No Compression") 85 | // Experimental 86 | // << "\nReuse logs: " << bool_tostring(opt->reuse_logs) 87 | << "\nFilter policy: " << filter_tostring(opt->filter_policy) << std::endl; 88 | 89 | lua_pushstring(L, oss.str().c_str()); 90 | 91 | return 1; 92 | } 93 | 94 | /** 95 | * Create a ReadOptions object. 96 | */ 97 | int lvldb_read_options(lua_State *L) { 98 | leveldb::ReadOptions *ropt = (leveldb::ReadOptions*)lua_newuserdata(L, sizeof(leveldb::ReadOptions)); 99 | 100 | *(ropt) = leveldb::ReadOptions(); // set default values 101 | 102 | luaL_getmetatable(L, LVLDB_MT_ROPT); 103 | lua_setmetatable(L, -2); 104 | 105 | return 1; 106 | } 107 | 108 | /** 109 | * To string function for the ReadOptions object. 110 | */ 111 | int lvldb_read_options_tostring(lua_State *L) { 112 | leveldb::ReadOptions *ropt = check_read_options(L, 1); 113 | 114 | std::ostringstream oss (std::ostringstream::out); 115 | oss << "Verify checksum: " << bool_tostring(ropt->verify_checksums) 116 | << "\nFill cache: " << bool_tostring(ropt->fill_cache) 117 | << "\nSnapshot: " << ropt->snapshot << std::endl; 118 | 119 | lua_pushstring(L, oss.str().c_str()); 120 | 121 | return 1; 122 | } 123 | 124 | /** 125 | * Create a WriteOptions object. 126 | */ 127 | int lvldb_write_options(lua_State *L) { 128 | leveldb::WriteOptions *wopt = (leveldb::WriteOptions*)lua_newuserdata(L, sizeof(leveldb::WriteOptions)); 129 | 130 | *(wopt) = leveldb::WriteOptions(); // set default values 131 | 132 | luaL_getmetatable(L, LVLDB_MT_WOPT); 133 | lua_setmetatable(L, -2); 134 | 135 | return 1; 136 | } 137 | 138 | /** 139 | * To string function for the WriteOptions object. 140 | */ 141 | int lvldb_write_options_tostring(lua_State *L) { 142 | leveldb::WriteOptions *wopt = check_write_options(L, 1); 143 | 144 | std::ostringstream oss (std::ostringstream::out); 145 | oss << "Sync: " << bool_tostring(wopt->sync) << std::endl; 146 | 147 | lua_pushstring(L, oss.str().c_str()); 148 | 149 | return 1; 150 | } 151 | -------------------------------------------------------------------------------- /src/opt.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lua.hpp" 4 | #include "lib.hpp" 5 | #include "utils.hpp" 6 | 7 | // Bitwise comparator impl 8 | #include 9 | 10 | int get_int(lua_State*, void*); 11 | int set_int(lua_State*, void*); 12 | int get_number(lua_State*, void*); 13 | int set_number(lua_State*, void*); 14 | int get_size(lua_State*, void*); 15 | int set_size(lua_State*, void*); 16 | int get_bool(lua_State*, void*); 17 | int set_bool(lua_State*, void*); 18 | int get_string(lua_State*, void*); 19 | int set_string(lua_State*, void*); 20 | 21 | int lvldb_options_tostring(lua_State*); 22 | int lvldb_read_options(lua_State*); 23 | int lvldb_read_options_tostring(lua_State*); 24 | int lvldb_write_options(lua_State*); 25 | int lvldb_write_options_tostring(lua_State*); 26 | -------------------------------------------------------------------------------- /src/utils.cc: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | /** 4 | * Converts a Lua parameter into a LevelDB's slice. 5 | * Every data stored from Lua is stored with this format. 6 | * This functions manage type conversion between Lua's 7 | * types and the LevelDB's Slice. 8 | */ 9 | leveldb::Slice lua_to_slice(lua_State *L, int i) { 10 | // Note: 11 | // http://leveldb.org/ says: 12 | // "Arbitrary byte arrays 13 | // Both keys and values are treated as simple arrays of bytes" 14 | const char *data = luaL_checkstring(L, i); 15 | 16 | return leveldb::Slice(data, strlen(data)); 17 | } 18 | 19 | /** 20 | * Converts a LevelDB's slice into a Lua value. 21 | * This the inverse operation of lua_to_slice. 22 | * It's used with the get method, the iterator 23 | * uses another function for conversion to Lua. 24 | */ 25 | int string_to_lua(lua_State *L, std::string value) { 26 | // Note: 27 | // http://leveldb.org/ says: 28 | // "Arbitrary byte arrays 29 | // Both keys and values are treated as simple arrays of bytes" 30 | lua_pushlstring(L, value.c_str(), value.length()); 31 | 32 | return 1; 33 | } 34 | 35 | /** 36 | * Stringify a boolean 37 | */ 38 | std::string bool_tostring(int boolean) { 39 | return boolean == 1 ? "true" : "false"; 40 | } 41 | 42 | /** 43 | * Stringify a pointer 44 | */ 45 | std::string pointer_tostring(void *p) { 46 | std::ostringstream oss (std::ostringstream::out); 47 | 48 | if (p != NULL) 49 | oss << &p; 50 | else 51 | oss << "NULL"; 52 | 53 | return oss.str().c_str(); 54 | } 55 | 56 | /** 57 | * Stringify a filter 58 | */ 59 | std::string filter_tostring(const leveldb::FilterPolicy *fp) { 60 | return fp == 0 ? "NULL" : fp->Name(); 61 | } 62 | 63 | /** 64 | * Check for an Options type. 65 | */ 66 | leveldb::Options *check_options(lua_State *L, int index) { 67 | leveldb::Options *opt; 68 | luaL_checktype(L, index, LUA_TUSERDATA); 69 | // UD-type: complex metatable @ luaopen_leveldb() 70 | opt = (leveldb::Options*)luaL_checkudata(L, index, LVLDB_MT_OPT); 71 | luaL_argcheck(L, opt != NULL, index, "'options' expected"); 72 | 73 | return opt; 74 | } 75 | 76 | /** 77 | * Check for a ReadOptions type. 78 | */ 79 | leveldb::ReadOptions *check_read_options(lua_State *L, int index) { 80 | luaL_checktype(L, index, LUA_TUSERDATA); 81 | // UD-type: complex metatable @ luaopen_leveldb() 82 | void *ud = luaL_checkudata(L, index, LVLDB_MT_ROPT); 83 | luaL_argcheck(L, ud != NULL, index, "'writeOptions' expected"); 84 | 85 | return (leveldb::ReadOptions *) ud; 86 | } 87 | 88 | /** 89 | * Check for a WriteOptions type. 90 | */ 91 | leveldb::WriteOptions *check_write_options(lua_State *L, int index) { 92 | luaL_checktype(L, index, LUA_TUSERDATA); 93 | // UD-type: complex metatable @ luaopen_leveldb() 94 | void *ud = luaL_checkudata(L, index, LVLDB_MT_WOPT); 95 | luaL_argcheck(L, ud != NULL, index, "'readOptions' expected"); 96 | 97 | return (leveldb::WriteOptions *) ud; 98 | } 99 | 100 | /** 101 | * Check for a WriteBatch type. 102 | */ 103 | leveldb::WriteBatch *check_writebatch(lua_State *L, int index) { 104 | luaL_checktype(L, index, LUA_TUSERDATA); 105 | // UD-type: light meta @ lvldb_batch() 106 | // LuaJIT doesn't support luaL_checkudata on light userdata 107 | // void *ud = luaL_checkudata(L, 1, LVLDB_MT_BATCH); 108 | leveldb::WriteBatch *ud = (leveldb::WriteBatch*) lua_touserdata(L, 1); 109 | luaL_argcheck(L, ud != NULL, index, "'batch' expected"); 110 | luaL_argcheck(L, lua_islightuserdata(L, index), index, "'iterator' expected"); 111 | 112 | return ud; 113 | } 114 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lua.hpp" 4 | #include "lib.hpp" 5 | 6 | // Lua Meta-tables names 7 | #define LVLDB_MOD_NAME "leveldb" 8 | #define LVLDB_MT_OPT "leveldb.opt" 9 | #define LVLDB_MT_ROPT "leveldb.ropt" 10 | #define LVLDB_MT_WOPT "leveldb.wopt" 11 | #define LVLDB_MT_DB "leveldb.db" 12 | #define LVLDB_MT_ITER "leveldb.iter" 13 | #define LVLDB_MT_BATCH "leveldb.btch" 14 | 15 | leveldb::Slice lua_to_slice(lua_State*, int); 16 | int string_to_lua(lua_State*, std::string); 17 | std::string bool_tostring(int); 18 | std::string pointer_tostring(void*); 19 | std::string filter_tostring(const leveldb::FilterPolicy*); 20 | 21 | leveldb::Options *check_options(lua_State*, int); 22 | leveldb::ReadOptions *check_read_options(lua_State*, int); 23 | leveldb::WriteOptions *check_write_options(lua_State*, int); 24 | 25 | leveldb::WriteBatch *check_writebatch(lua_State*, int); 26 | 27 | /** 28 | * Type checking macros. 29 | */ 30 | #define lvldb_opt(L, l) ( lua_gettop(L) >= l ? *(check_options(L, l)) : leveldb::Options() ) 31 | #define lvldb_ropt(L, l) ( lua_gettop(L) >= l ? *(check_read_options(L, l)) : leveldb::ReadOptions() ) 32 | #define lvldb_wopt(L, l) ( lua_gettop(L) >= l ? *(check_write_options(L, l)) : leveldb::WriteOptions() ) 33 | --------------------------------------------------------------------------------