├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── THANKS ├── c_src ├── build_deps.sh ├── hets_impl_drv.cc ├── hets_impl_drv.h ├── hets_impl_drv_lib.cc ├── hets_impl_drv_lib.h ├── hets_impl_nif.cc ├── hets_impl_nif.h ├── hets_impl_nif_lib.cc ├── hets_impl_nif_lib.h ├── lets_impl_drv.cc ├── lets_impl_drv.h ├── lets_impl_drv_lib.cc ├── lets_impl_drv_lib.h ├── lets_impl_nif.cc ├── lets_impl_nif.h ├── lets_impl_nif_lib.cc ├── lets_impl_nif_lib.h ├── rets_impl_drv.cc ├── rets_impl_drv.h ├── rets_impl_drv_lib.cc ├── rets_impl_drv_lib.h ├── rets_impl_nif.cc ├── rets_impl_nif.h ├── rets_impl_nif_lib.cc └── rets_impl_nif_lib.h ├── doc ├── README.md ├── edoc-info ├── hets_impl_drv.md ├── hets_impl_nif.md ├── lets.md ├── lets_impl_drv.md ├── lets_impl_nif.md ├── overview.edoc ├── rets_impl_drv.md └── rets_impl_nif.md ├── priv └── test │ ├── .gitignore │ ├── Makefile │ ├── qc_leveldb_issue44.c │ ├── qc_statemc_lets.c │ ├── qc_statemc_lets.h │ └── qc_statemc_leveldb_issue44.erl ├── rebar ├── rebar.config ├── rebar.config.doc ├── src ├── hets_impl_drv.erl ├── hets_impl_nif.erl ├── lets.app.src ├── lets.erl ├── lets.hrl ├── lets_impl_drv.erl ├── lets_impl_nif.erl ├── rets_impl_drv.erl └── rets_impl_nif.erl └── test └── qc ├── qc_lets_proxy.erl ├── qc_lets_raw.erl ├── qc_lets_slave_proxy.erl ├── qc_leveldb.erl ├── qc_statem_lets.erl └── qc_statemc_lets.erl /.gitignore: -------------------------------------------------------------------------------- 1 | .eqc-info 2 | .eunit/ 3 | .qc/ 4 | .rebar/ 5 | c_src/*.d 6 | c_src/*.o 7 | c_src/hyperleveldb-*/ 8 | c_src/hyperleveldb/ 9 | c_src/leveldb-*/ 10 | c_src/leveldb/ 11 | c_src/rocksdb-*/ 12 | c_src/rocksdb/ 13 | c_src/snappy-*/ 14 | c_src/snappy/ 15 | deps/ 16 | ebin/ 17 | erl_crash.dump 18 | priv/lib/ 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | script: "make clean compile xref test" 3 | otp_release: 4 | - 18.2.1 5 | - 17.5 6 | - R16B03-1 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | REBAR?=./rebar 3 | 4 | hets_erl_files := $(wildcard src/hets_*.erl) 5 | lets_erl_files := $(patsubst src/hets_%,src/lets_%,$(hets_erl_files)) 6 | rets_erl_files := $(patsubst src/hets_%,src/rets_%,$(hets_erl_files)) 7 | hets_cxx_files := $(wildcard c_src/hets_*.cc c_src/hets_*.h) 8 | lets_cxx_files := $(patsubst c_src/hets_%,c_src/lets_%,$(hets_cxx_files)) 9 | rets_cxx_files := $(patsubst c_src/hets_%,c_src/rets_%,$(hets_cxx_files)) 10 | 11 | .PHONY: all clean distclean deps compile xref doc test eunit eqc proper \ 12 | compile-for-eunit compile-for-eqc compile-for-proper \ 13 | realclean 14 | 15 | all: compile 16 | 17 | deps: 18 | $(REBAR) get-deps 19 | 20 | clean: 21 | $(REBAR) clean -r 22 | 23 | distclean: clean 24 | rm -rf $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 25 | 26 | compile: $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 27 | $(REBAR) compile 28 | 29 | xref: 30 | $(REBAR) xref skip_deps=true 31 | 32 | doc: 33 | @rm -rf README.md doc/edoc-info doc/*.md 34 | $(REBAR) -C rebar.config.doc get-deps compile 35 | $(REBAR) -C rebar.config.doc doc skip_deps=true 36 | 37 | test: eunit 38 | 39 | eunit: compile-for-eunit 40 | $(REBAR) eunit skip_deps=true 41 | 42 | eqc: compile-for-eqc 43 | $(REBAR) eqc skip_deps=true 44 | 45 | proper: compile-for-proper 46 | @echo "rebar does not implement a 'proper' command" && false 47 | 48 | compile-for-eunit: $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 49 | $(REBAR) compile eunit compile_only=true 50 | 51 | compile-for-eqc: $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 52 | $(REBAR) -D QC -D QC_EQC compile eqc compile_only=true 53 | 54 | compile-for-proper: $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 55 | $(REBAR) -D QC -D QC_PROPER compile qc compile_only=true 56 | 57 | realclean: clean 58 | rm -f $(lets_erl_files) $(lets_cxx_files) $(rets_erl_files) $(rets_cxx_files) 59 | 60 | $(lets_erl_files): $(hets_erl_files) 61 | cp -f $(patsubst src/lets_%,src/hets_%,$@) $@ 62 | @perl -i -pe 's/hets/lets/g;' $@ 63 | 64 | $(lets_cxx_files): $(hets_cxx_files) 65 | cp -f $(patsubst c_src/lets_%,c_src/hets_%,$@) $@ 66 | @perl -i -pe 's/hets/lets/g;' $@ 67 | @perl -i -pe 's/HETS/LETS/g;' $@ 68 | @perl -i -pe 's/hyperleveldb/leveldb/g;' $@ 69 | 70 | $(rets_erl_files): $(hets_erl_files) 71 | cp -f $(patsubst src/rets_%,src/hets_%,$@) $@ 72 | @perl -i -pe 's/hets/rets/g;' $@ 73 | 74 | $(rets_cxx_files): $(hets_cxx_files) 75 | cp -f $(patsubst c_src/rets_%,c_src/hets_%,$@) $@ 76 | @perl -i -pe 's/hets/rets/g;' $@ 77 | @perl -i -pe 's/HETS/RETS/g;' $@ 78 | @perl -i -pe 's/hyperleveldb/rocksdb/g;' $@ 79 | @perl -i -pe 's/leveldb/rocksdb/g;' $@ 80 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | The following people have contributed to lets: 2 | 3 | Joseph Wayne Norton 4 | Dmitry Groshev 5 | Tatsuya Kawano 6 | Alex (a.k.a. @lemo) 7 | Erwan Martin 8 | -------------------------------------------------------------------------------- /c_src/build_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # The MIT License 4 | # 5 | # Copyright (C) 2011-2016 by Joseph Wayne Norton 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | set -eo pipefail 26 | 27 | SNAPPY_VSN=HEAD 28 | LEVELDB_VSN=HEAD 29 | HYPERLEVELDB_VSN=HEAD 30 | ROCKSDB_VSN=HEAD 31 | 32 | if [ `basename $PWD` != "c_src" ]; then 33 | pushd c_src > /dev/null 2>&1 34 | fi 35 | 36 | BASEDIR="$PWD" 37 | 38 | case "$1" in 39 | clean) 40 | rm -f *.o ../priv/lib/*.so 41 | rm -rf snappy snappy-$SNAPPY_VSN 42 | rm -rf leveldb leveldb-$LEVELDB_VSN 43 | rm -rf hyperleveldb hyperleveldb-$HYPERLEVELDB_VSN 44 | rm -rf rocksdb rocksdb-$ROCKSDB_VSN 45 | ;; 46 | get_deps) 47 | ;; 48 | update_deps) 49 | ;; 50 | *) 51 | LIBTOOLIZE=libtoolize 52 | ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { 53 | LIBTOOLIZE=glibtoolize 54 | ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { 55 | echo 56 | echo "You must have libtool (& friends) installed to compile LETS." 57 | echo 58 | exit -1 59 | } 60 | } 61 | 62 | # snappy 63 | if [ ! -f $BASEDIR/snappy/lib/libsnappy.a ]; then 64 | (cd $REBAR_DEPS_DIR/snappy && git archive --format=tar --prefix=snappy-$SNAPPY_VSN/ $SNAPPY_VSN) \ 65 | | tar xf - 66 | (cd snappy-$SNAPPY_VSN && \ 67 | sed -ibak1 '/^AC_ARG_WITH.*$/, /^fi$/d' configure.ac && \ 68 | perl -ibak2 -pe 's/LT_INIT/AM_PROG_AR\nLT_INIT/' configure.ac 69 | ) 70 | (cd snappy-$SNAPPY_VSN && \ 71 | rm -rf autom4te.cache && \ 72 | $LIBTOOLIZE --copy && \ 73 | aclocal -I m4 && \ 74 | autoheader && \ 75 | automake --add-missing --copy && \ 76 | autoconf) 77 | (cd snappy-$SNAPPY_VSN && \ 78 | ./configure $CONFFLAGS \ 79 | --enable-static \ 80 | --disable-shared \ 81 | --with-pic \ 82 | --prefix=$BASEDIR/snappy && \ 83 | make install) 84 | rm -f $BASEDIR/snappy/lib/libsnappy.la 85 | fi 86 | # leveldb 87 | if [ ! -f $BASEDIR/leveldb/lib/libleveldb.a ]; then 88 | (cd $REBAR_DEPS_DIR/leveldb && git archive --format=tar --prefix=leveldb-$LEVELDB_VSN/ $LEVELDB_VSN) \ 89 | | tar xf - 90 | (cd leveldb-$LEVELDB_VSN && \ 91 | echo "echo \"PLATFORM_CFLAGS+=-fPIC -I$BASEDIR/snappy/include\" >> build_config.mk" >> build_detect_platform && 92 | echo "echo \"PLATFORM_CXXFLAGS+=-fPIC -I$BASEDIR/snappy/include\" >> build_config.mk" >> build_detect_platform && 93 | echo "echo \"PLATFORM_LDFLAGS+=-L $BASEDIR/snappy/lib -lsnappy\" >> build_config.mk" >> build_detect_platform && 94 | make SNAPPY=1 && \ 95 | mkdir -p $BASEDIR/leveldb/include/leveldb && \ 96 | install include/leveldb/*.h $BASEDIR/leveldb/include/leveldb && \ 97 | mkdir -p $BASEDIR/leveldb/lib && \ 98 | install out-static/libleveldb.a $BASEDIR/leveldb/lib) 99 | fi 100 | # hyperleveldb 101 | if [ ! -f $BASEDIR/hyperleveldb/lib/libhyperleveldb.a ]; then 102 | (cd $REBAR_DEPS_DIR/hyperleveldb && git archive --format=tar --prefix=hyperleveldb-$HYPERLEVELDB_VSN/ $HYPERLEVELDB_VSN) \ 103 | | tar xf - 104 | (cd hyperleveldb-$HYPERLEVELDB_VSN && \ 105 | perl -ibak1 -pe 's/\.la/.a/g;' Makefile.am && \ 106 | perl -ibak2 -pe 's/_la_/_a_/g;' Makefile.am && \ 107 | perl -ibak3 -pe 's/lib_LTLIBRARIES/lib_LIBRARIES/g;' Makefile.am && \ 108 | perl -ibak4 -pe 's/libhyperleveldb_a_LIBADD/#libhyperleveldb_a_LIBADD/g;' Makefile.am && \ 109 | perl -ibak5 -pe 's!.*_PROGRAMS.*!#!g;' Makefile.am) 110 | (cd hyperleveldb-$HYPERLEVELDB_VSN && \ 111 | rm -rf autom4te.cache && \ 112 | $LIBTOOLIZE --copy && \ 113 | aclocal -I m4 && \ 114 | autoheader && \ 115 | automake --add-missing --copy && \ 116 | autoconf) 117 | (cd hyperleveldb-$HYPERLEVELDB_VSN && \ 118 | env CPPFLAGS="-fPIC -I$BASEDIR/snappy/include $CPPFLAGS" \ 119 | CFLAGS="-fPIC -I$BASEDIR/snappy/include $CFLAGS" \ 120 | CXXFLAGS="-fPIC -I$BASEDIR/snappy/include $CXXFLAGS" \ 121 | LDFLAGS="-L$BASEDIR/snappy/lib -lsnappy $LDFLAGS" \ 122 | ./configure --enable-static --enable-snappy && \ 123 | make && \ 124 | mkdir -p $BASEDIR/hyperleveldb/include/hyperleveldb && \ 125 | install include/hyperleveldb/*.h $BASEDIR/hyperleveldb/include/hyperleveldb && \ 126 | mkdir -p $BASEDIR/hyperleveldb/lib && \ 127 | install libhyperleveldb.a $BASEDIR/hyperleveldb/lib) 128 | fi 129 | # rocksdb 130 | if [ ! -f $BASEDIR/rocksdb/lib/librocksdb.a ]; then 131 | (cd $REBAR_DEPS_DIR/rocksdb && git archive --format=tar --prefix=rocksdb-$ROCKSDB_VSN/ $ROCKSDB_VSN) \ 132 | | tar xf - 133 | (cd rocksdb-$ROCKSDB_VSN && \ 134 | echo "echo \"PLATFORM_CCFLAGS+=-fPIC -DSNAPPY -I$BASEDIR/snappy/include\" >> make_config.mk" >> build_tools/build_detect_platform && 135 | echo "echo \"PLATFORM_CXXFLAGS+=-fPIC -DSNAPPY -I$BASEDIR/snappy/include\" >> make_config.mk" >> build_tools/build_detect_platform && 136 | echo "echo \"PLATFORM_LDFLAGS+=-L $BASEDIR/snappy/lib -lsnappy\" >> make_config.mk" >> build_tools/build_detect_platform && 137 | make static_lib && \ 138 | mkdir -p $BASEDIR/rocksdb/include/rocksdb && \ 139 | install include/rocksdb/*.h $BASEDIR/rocksdb/include/rocksdb && \ 140 | mkdir -p $BASEDIR/rocksdb/lib && \ 141 | install librocksdb.a $BASEDIR/rocksdb/lib) 142 | fi 143 | ;; 144 | esac 145 | -------------------------------------------------------------------------------- /c_src/hets_impl_drv.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef HETS_DRV_H 24 | #define HETS_DRV_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | #include 32 | 33 | #if ERL_DRV_EXTENDED_MAJOR_VERSION<2 34 | typedef int ErlDrvSizeT; 35 | typedef int ErlDrvSSizeT; 36 | #endif 37 | 38 | // @doc driver init 39 | DRIVER_INIT(lib_lets_impl_drv); 40 | 41 | // @doc driver callbacks 42 | int drv_init(void); 43 | 44 | ErlDrvData drv_start(ErlDrvPort port, char* command); 45 | void drv_stop(ErlDrvData); 46 | void drv_output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len); 47 | void drv_ready_async(ErlDrvData, ErlDrvThreadData); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif /* HETS_DRV_H */ 54 | -------------------------------------------------------------------------------- /c_src/hets_impl_drv_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef HETS_DRV_LIB_H 24 | #define HETS_DRV_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "hyperleveldb/db.h" 30 | #include "hyperleveldb/cache.h" 31 | #include "hyperleveldb/slice.h" 32 | #include "hyperleveldb/write_batch.h" 33 | #include "hyperleveldb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "hets_impl_drv.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | leveldb::Options db_options; 74 | leveldb::ReadOptions db_read_options; 75 | leveldb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | leveldb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const leveldb::FilterPolicy* db_filter_policy; 83 | leveldb::DB* db; 84 | ErlDrvUInt64 db_memory; 85 | ErlDrvUInt64 db_size; 86 | std::vector > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | // prototypes 90 | extern bool lets_impl_drv_lib_init(); 91 | 92 | extern bool lets_init(lets_impl& impl, 93 | const char type, const char privacy, const char* name, const size_t namelen); 94 | extern bool lets_create(lets_impl& impl, 95 | const char op); 96 | 97 | extern bool lets_parse_options(lets_impl& impl, 98 | const char* buf, ErlDrvSizeT len); 99 | extern bool lets_parse_read_options(leveldb::ReadOptions& opts, 100 | const char* buf, ErlDrvSizeT len); 101 | extern bool lets_parse_write_options(leveldb::WriteOptions& opts, 102 | const char* buf, ErlDrvSizeT len); 103 | 104 | // helpers 105 | extern int ei_inspect_atom(const char *buf, int *index, char *p); 106 | extern int ei_inspect_binary(const char *buf, int *index, void **p, long *lenp); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* HETS_DRV_LIB_H */ 113 | -------------------------------------------------------------------------------- /c_src/hets_impl_nif.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef HETS_NIF_H 24 | #define HETS_NIF_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | 32 | // Prototypes 33 | ERL_NIF_TERM 34 | lets_impl_nif_open6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 35 | ERL_NIF_TERM 36 | lets_impl_nif_destroy6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 37 | ERL_NIF_TERM 38 | lets_impl_nif_repair6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 39 | ERL_NIF_TERM 40 | lets_impl_nif_insert3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 41 | ERL_NIF_TERM 42 | lets_impl_nif_insert4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 43 | ERL_NIF_TERM 44 | lets_impl_nif_insert_new3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 45 | ERL_NIF_TERM 46 | lets_impl_nif_insert_new4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 47 | ERL_NIF_TERM 48 | lets_impl_nif_delete2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 49 | ERL_NIF_TERM 50 | lets_impl_nif_delete3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 51 | ERL_NIF_TERM 52 | lets_impl_nif_delete_all_objects2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 53 | ERL_NIF_TERM 54 | lets_impl_nif_lookup3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 55 | ERL_NIF_TERM 56 | lets_impl_nif_member3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 57 | ERL_NIF_TERM 58 | lets_impl_nif_first3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 59 | ERL_NIF_TERM 60 | lets_impl_nif_first_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 61 | ERL_NIF_TERM 62 | lets_impl_nif_last3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 63 | ERL_NIF_TERM 64 | lets_impl_nif_last_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 65 | ERL_NIF_TERM 66 | lets_impl_nif_next4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 67 | ERL_NIF_TERM 68 | lets_impl_nif_next_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 69 | ERL_NIF_TERM 70 | lets_impl_nif_prev4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 71 | ERL_NIF_TERM 72 | lets_impl_nif_prev_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 73 | ERL_NIF_TERM 74 | lets_impl_nif_info_memory1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 75 | ERL_NIF_TERM 76 | lets_impl_nif_info_size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 77 | ERL_NIF_TERM 78 | lets_impl_nif_notify4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /* HETS_NIF_H */ 85 | -------------------------------------------------------------------------------- /c_src/hets_impl_nif_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef HETS_NIF_LIB_H 24 | #define HETS_NIF_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "hyperleveldb/db.h" 30 | #include "hyperleveldb/cache.h" 31 | #include "hyperleveldb/slice.h" 32 | #include "hyperleveldb/write_batch.h" 33 | #include "hyperleveldb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "erl_nif.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | leveldb::Options db_options; 74 | leveldb::ReadOptions db_read_options; 75 | leveldb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | leveldb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const leveldb::FilterPolicy* db_filter_policy; 83 | leveldb::DB* db; 84 | ErlNifUInt64 db_memory; 85 | ErlNifUInt64 db_size; 86 | std::vector > > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | extern ERL_NIF_TERM lets_atom_undefined; 90 | extern ERL_NIF_TERM lets_atom_true; 91 | extern ERL_NIF_TERM lets_atom_false; 92 | extern ERL_NIF_TERM lets_atom_set; 93 | extern ERL_NIF_TERM lets_atom_ordered_set; 94 | extern ERL_NIF_TERM lets_atom_private; 95 | extern ERL_NIF_TERM lets_atom_protected; 96 | extern ERL_NIF_TERM lets_atom_public; 97 | extern ERL_NIF_TERM lets_atom_create_if_missing; 98 | extern ERL_NIF_TERM lets_atom_error_if_exists; 99 | extern ERL_NIF_TERM lets_atom_paranoid_checks; 100 | extern ERL_NIF_TERM lets_atom_write_buffer_size; 101 | extern ERL_NIF_TERM lets_atom_max_open_files; 102 | extern ERL_NIF_TERM lets_atom_block_cache_size; 103 | extern ERL_NIF_TERM lets_atom_block_size; 104 | extern ERL_NIF_TERM lets_atom_block_restart_interval; 105 | extern ERL_NIF_TERM lets_atom_compression; 106 | extern ERL_NIF_TERM lets_atom_no; 107 | extern ERL_NIF_TERM lets_atom_snappy; 108 | extern ERL_NIF_TERM lets_atom_async; 109 | extern ERL_NIF_TERM lets_atom_filter_policy; 110 | extern ERL_NIF_TERM lets_atom_bloom; 111 | extern ERL_NIF_TERM lets_atom_verify_checksums; 112 | extern ERL_NIF_TERM lets_atom_fill_cache; 113 | extern ERL_NIF_TERM lets_atom_sync; 114 | extern ERL_NIF_TERM lets_atom_end_of_table; 115 | extern ERL_NIF_TERM lets_atom_when_destroyed; 116 | 117 | // prototypes 118 | extern bool lets_impl_nif_lib_init(ErlNifEnv* env); 119 | 120 | extern bool lets_init(lets_impl& impl, 121 | const char type, const char privacy, const char* name, const size_t namelen); 122 | extern bool lets_create(lets_impl& impl, 123 | const char op); 124 | 125 | extern bool lets_parse_options(ErlNifEnv* env, lets_impl& impl, 126 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 127 | extern bool lets_parse_read_options(ErlNifEnv* env, leveldb::ReadOptions& opts, 128 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 129 | extern bool lets_parse_write_options(ErlNifEnv* env, leveldb::WriteOptions& opts, 130 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | #endif /* HETS_NIF_LIB_H */ 137 | -------------------------------------------------------------------------------- /c_src/lets_impl_drv.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef LETS_DRV_H 24 | #define LETS_DRV_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | #include 32 | 33 | #if ERL_DRV_EXTENDED_MAJOR_VERSION<2 34 | typedef int ErlDrvSizeT; 35 | typedef int ErlDrvSSizeT; 36 | #endif 37 | 38 | // @doc driver init 39 | DRIVER_INIT(lib_lets_impl_drv); 40 | 41 | // @doc driver callbacks 42 | int drv_init(void); 43 | 44 | ErlDrvData drv_start(ErlDrvPort port, char* command); 45 | void drv_stop(ErlDrvData); 46 | void drv_output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len); 47 | void drv_ready_async(ErlDrvData, ErlDrvThreadData); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif /* LETS_DRV_H */ 54 | -------------------------------------------------------------------------------- /c_src/lets_impl_drv_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef LETS_DRV_LIB_H 24 | #define LETS_DRV_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "leveldb/db.h" 30 | #include "leveldb/cache.h" 31 | #include "leveldb/slice.h" 32 | #include "leveldb/write_batch.h" 33 | #include "leveldb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "lets_impl_drv.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | leveldb::Options db_options; 74 | leveldb::ReadOptions db_read_options; 75 | leveldb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | leveldb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const leveldb::FilterPolicy* db_filter_policy; 83 | leveldb::DB* db; 84 | ErlDrvUInt64 db_memory; 85 | ErlDrvUInt64 db_size; 86 | std::vector > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | // prototypes 90 | extern bool lets_impl_drv_lib_init(); 91 | 92 | extern bool lets_init(lets_impl& impl, 93 | const char type, const char privacy, const char* name, const size_t namelen); 94 | extern bool lets_create(lets_impl& impl, 95 | const char op); 96 | 97 | extern bool lets_parse_options(lets_impl& impl, 98 | const char* buf, ErlDrvSizeT len); 99 | extern bool lets_parse_read_options(leveldb::ReadOptions& opts, 100 | const char* buf, ErlDrvSizeT len); 101 | extern bool lets_parse_write_options(leveldb::WriteOptions& opts, 102 | const char* buf, ErlDrvSizeT len); 103 | 104 | // helpers 105 | extern int ei_inspect_atom(const char *buf, int *index, char *p); 106 | extern int ei_inspect_binary(const char *buf, int *index, void **p, long *lenp); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* LETS_DRV_LIB_H */ 113 | -------------------------------------------------------------------------------- /c_src/lets_impl_nif.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef LETS_NIF_H 24 | #define LETS_NIF_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | 32 | // Prototypes 33 | ERL_NIF_TERM 34 | lets_impl_nif_open6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 35 | ERL_NIF_TERM 36 | lets_impl_nif_destroy6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 37 | ERL_NIF_TERM 38 | lets_impl_nif_repair6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 39 | ERL_NIF_TERM 40 | lets_impl_nif_insert3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 41 | ERL_NIF_TERM 42 | lets_impl_nif_insert4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 43 | ERL_NIF_TERM 44 | lets_impl_nif_insert_new3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 45 | ERL_NIF_TERM 46 | lets_impl_nif_insert_new4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 47 | ERL_NIF_TERM 48 | lets_impl_nif_delete2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 49 | ERL_NIF_TERM 50 | lets_impl_nif_delete3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 51 | ERL_NIF_TERM 52 | lets_impl_nif_delete_all_objects2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 53 | ERL_NIF_TERM 54 | lets_impl_nif_lookup3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 55 | ERL_NIF_TERM 56 | lets_impl_nif_member3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 57 | ERL_NIF_TERM 58 | lets_impl_nif_first3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 59 | ERL_NIF_TERM 60 | lets_impl_nif_first_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 61 | ERL_NIF_TERM 62 | lets_impl_nif_last3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 63 | ERL_NIF_TERM 64 | lets_impl_nif_last_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 65 | ERL_NIF_TERM 66 | lets_impl_nif_next4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 67 | ERL_NIF_TERM 68 | lets_impl_nif_next_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 69 | ERL_NIF_TERM 70 | lets_impl_nif_prev4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 71 | ERL_NIF_TERM 72 | lets_impl_nif_prev_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 73 | ERL_NIF_TERM 74 | lets_impl_nif_info_memory1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 75 | ERL_NIF_TERM 76 | lets_impl_nif_info_size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 77 | ERL_NIF_TERM 78 | lets_impl_nif_notify4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /* LETS_NIF_H */ 85 | -------------------------------------------------------------------------------- /c_src/lets_impl_nif_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef LETS_NIF_LIB_H 24 | #define LETS_NIF_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "leveldb/db.h" 30 | #include "leveldb/cache.h" 31 | #include "leveldb/slice.h" 32 | #include "leveldb/write_batch.h" 33 | #include "leveldb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "erl_nif.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | leveldb::Options db_options; 74 | leveldb::ReadOptions db_read_options; 75 | leveldb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | leveldb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const leveldb::FilterPolicy* db_filter_policy; 83 | leveldb::DB* db; 84 | ErlNifUInt64 db_memory; 85 | ErlNifUInt64 db_size; 86 | std::vector > > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | extern ERL_NIF_TERM lets_atom_undefined; 90 | extern ERL_NIF_TERM lets_atom_true; 91 | extern ERL_NIF_TERM lets_atom_false; 92 | extern ERL_NIF_TERM lets_atom_set; 93 | extern ERL_NIF_TERM lets_atom_ordered_set; 94 | extern ERL_NIF_TERM lets_atom_private; 95 | extern ERL_NIF_TERM lets_atom_protected; 96 | extern ERL_NIF_TERM lets_atom_public; 97 | extern ERL_NIF_TERM lets_atom_create_if_missing; 98 | extern ERL_NIF_TERM lets_atom_error_if_exists; 99 | extern ERL_NIF_TERM lets_atom_paranoid_checks; 100 | extern ERL_NIF_TERM lets_atom_write_buffer_size; 101 | extern ERL_NIF_TERM lets_atom_max_open_files; 102 | extern ERL_NIF_TERM lets_atom_block_cache_size; 103 | extern ERL_NIF_TERM lets_atom_block_size; 104 | extern ERL_NIF_TERM lets_atom_block_restart_interval; 105 | extern ERL_NIF_TERM lets_atom_compression; 106 | extern ERL_NIF_TERM lets_atom_no; 107 | extern ERL_NIF_TERM lets_atom_snappy; 108 | extern ERL_NIF_TERM lets_atom_async; 109 | extern ERL_NIF_TERM lets_atom_filter_policy; 110 | extern ERL_NIF_TERM lets_atom_bloom; 111 | extern ERL_NIF_TERM lets_atom_verify_checksums; 112 | extern ERL_NIF_TERM lets_atom_fill_cache; 113 | extern ERL_NIF_TERM lets_atom_sync; 114 | extern ERL_NIF_TERM lets_atom_end_of_table; 115 | extern ERL_NIF_TERM lets_atom_when_destroyed; 116 | 117 | // prototypes 118 | extern bool lets_impl_nif_lib_init(ErlNifEnv* env); 119 | 120 | extern bool lets_init(lets_impl& impl, 121 | const char type, const char privacy, const char* name, const size_t namelen); 122 | extern bool lets_create(lets_impl& impl, 123 | const char op); 124 | 125 | extern bool lets_parse_options(ErlNifEnv* env, lets_impl& impl, 126 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 127 | extern bool lets_parse_read_options(ErlNifEnv* env, leveldb::ReadOptions& opts, 128 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 129 | extern bool lets_parse_write_options(ErlNifEnv* env, leveldb::WriteOptions& opts, 130 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | #endif /* LETS_NIF_LIB_H */ 137 | -------------------------------------------------------------------------------- /c_src/rets_impl_drv.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef RETS_DRV_H 24 | #define RETS_DRV_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | #include 32 | 33 | #if ERL_DRV_EXTENDED_MAJOR_VERSION<2 34 | typedef int ErlDrvSizeT; 35 | typedef int ErlDrvSSizeT; 36 | #endif 37 | 38 | // @doc driver init 39 | DRIVER_INIT(lib_lets_impl_drv); 40 | 41 | // @doc driver callbacks 42 | int drv_init(void); 43 | 44 | ErlDrvData drv_start(ErlDrvPort port, char* command); 45 | void drv_stop(ErlDrvData); 46 | void drv_output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len); 47 | void drv_ready_async(ErlDrvData, ErlDrvThreadData); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif /* RETS_DRV_H */ 54 | -------------------------------------------------------------------------------- /c_src/rets_impl_drv_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef RETS_DRV_LIB_H 24 | #define RETS_DRV_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "rocksdb/db.h" 30 | #include "rocksdb/cache.h" 31 | #include "rocksdb/slice.h" 32 | #include "rocksdb/write_batch.h" 33 | #include "rocksdb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "rets_impl_drv.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | rocksdb::Options db_options; 74 | rocksdb::ReadOptions db_read_options; 75 | rocksdb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | rocksdb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const rocksdb::FilterPolicy* db_filter_policy; 83 | rocksdb::DB* db; 84 | ErlDrvUInt64 db_memory; 85 | ErlDrvUInt64 db_size; 86 | std::vector > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | // prototypes 90 | extern bool lets_impl_drv_lib_init(); 91 | 92 | extern bool lets_init(lets_impl& impl, 93 | const char type, const char privacy, const char* name, const size_t namelen); 94 | extern bool lets_create(lets_impl& impl, 95 | const char op); 96 | 97 | extern bool lets_parse_options(lets_impl& impl, 98 | const char* buf, ErlDrvSizeT len); 99 | extern bool lets_parse_read_options(rocksdb::ReadOptions& opts, 100 | const char* buf, ErlDrvSizeT len); 101 | extern bool lets_parse_write_options(rocksdb::WriteOptions& opts, 102 | const char* buf, ErlDrvSizeT len); 103 | 104 | // helpers 105 | extern int ei_inspect_atom(const char *buf, int *index, char *p); 106 | extern int ei_inspect_binary(const char *buf, int *index, void **p, long *lenp); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* RETS_DRV_LIB_H */ 113 | -------------------------------------------------------------------------------- /c_src/rets_impl_nif.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef RETS_NIF_H 24 | #define RETS_NIF_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | 32 | // Prototypes 33 | ERL_NIF_TERM 34 | lets_impl_nif_open6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 35 | ERL_NIF_TERM 36 | lets_impl_nif_destroy6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 37 | ERL_NIF_TERM 38 | lets_impl_nif_repair6(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 39 | ERL_NIF_TERM 40 | lets_impl_nif_insert3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 41 | ERL_NIF_TERM 42 | lets_impl_nif_insert4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 43 | ERL_NIF_TERM 44 | lets_impl_nif_insert_new3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 45 | ERL_NIF_TERM 46 | lets_impl_nif_insert_new4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 47 | ERL_NIF_TERM 48 | lets_impl_nif_delete2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 49 | ERL_NIF_TERM 50 | lets_impl_nif_delete3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 51 | ERL_NIF_TERM 52 | lets_impl_nif_delete_all_objects2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 53 | ERL_NIF_TERM 54 | lets_impl_nif_lookup3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 55 | ERL_NIF_TERM 56 | lets_impl_nif_member3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 57 | ERL_NIF_TERM 58 | lets_impl_nif_first3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 59 | ERL_NIF_TERM 60 | lets_impl_nif_first_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 61 | ERL_NIF_TERM 62 | lets_impl_nif_last3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 63 | ERL_NIF_TERM 64 | lets_impl_nif_last_iter3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 65 | ERL_NIF_TERM 66 | lets_impl_nif_next4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 67 | ERL_NIF_TERM 68 | lets_impl_nif_next_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 69 | ERL_NIF_TERM 70 | lets_impl_nif_prev4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 71 | ERL_NIF_TERM 72 | lets_impl_nif_prev_iter4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 73 | ERL_NIF_TERM 74 | lets_impl_nif_info_memory1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 75 | ERL_NIF_TERM 76 | lets_impl_nif_info_size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 77 | ERL_NIF_TERM 78 | lets_impl_nif_notify4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif /* RETS_NIF_H */ 85 | -------------------------------------------------------------------------------- /c_src/rets_impl_nif_lib.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // 3 | // Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef RETS_NIF_LIB_H 24 | #define RETS_NIF_LIB_H 25 | 26 | #include 27 | #include 28 | 29 | #include "rocksdb/db.h" 30 | #include "rocksdb/cache.h" 31 | #include "rocksdb/slice.h" 32 | #include "rocksdb/write_batch.h" 33 | #include "rocksdb/filter_policy.h" 34 | #ifdef ROCKSDB 35 | #include "rocksdb/table.h" 36 | #endif 37 | 38 | #include "erl_nif.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | typedef struct { 45 | long buflen; 46 | char buf[1]; 47 | } Binary; 48 | 49 | enum Type { 50 | SET = 0x0, 51 | ORDERED_SET = 0x1 52 | }; 53 | 54 | enum PrivacyType { 55 | PRIVATE = 0x0, 56 | PROTECTED = 0x1, 57 | PUBLIC = 0x2 58 | }; 59 | 60 | enum DBOpType { 61 | OPEN = 0x0, 62 | DESTROY = 0x1, 63 | REPAIR = 0x2 64 | }; 65 | 66 | typedef struct 67 | { 68 | bool async; 69 | bool alive; 70 | char type; 71 | char privacy; 72 | std::string* name; 73 | rocksdb::Options db_options; 74 | rocksdb::ReadOptions db_read_options; 75 | rocksdb::WriteOptions db_write_options; 76 | #ifdef ROCKSDB 77 | rocksdb::BlockBasedTableOptions db_table_options; 78 | #endif 79 | size_t db_block_cache_size; 80 | rocksdb::Cache* db_block_cache; 81 | int db_filter_policy_bloom_bits_per_key; 82 | const rocksdb::FilterPolicy* db_filter_policy; 83 | rocksdb::DB* db; 84 | ErlNifUInt64 db_memory; 85 | ErlNifUInt64 db_size; 86 | std::vector > > notify_when_destroyed; 87 | } lets_impl; 88 | 89 | extern ERL_NIF_TERM lets_atom_undefined; 90 | extern ERL_NIF_TERM lets_atom_true; 91 | extern ERL_NIF_TERM lets_atom_false; 92 | extern ERL_NIF_TERM lets_atom_set; 93 | extern ERL_NIF_TERM lets_atom_ordered_set; 94 | extern ERL_NIF_TERM lets_atom_private; 95 | extern ERL_NIF_TERM lets_atom_protected; 96 | extern ERL_NIF_TERM lets_atom_public; 97 | extern ERL_NIF_TERM lets_atom_create_if_missing; 98 | extern ERL_NIF_TERM lets_atom_error_if_exists; 99 | extern ERL_NIF_TERM lets_atom_paranoid_checks; 100 | extern ERL_NIF_TERM lets_atom_write_buffer_size; 101 | extern ERL_NIF_TERM lets_atom_max_open_files; 102 | extern ERL_NIF_TERM lets_atom_block_cache_size; 103 | extern ERL_NIF_TERM lets_atom_block_size; 104 | extern ERL_NIF_TERM lets_atom_block_restart_interval; 105 | extern ERL_NIF_TERM lets_atom_compression; 106 | extern ERL_NIF_TERM lets_atom_no; 107 | extern ERL_NIF_TERM lets_atom_snappy; 108 | extern ERL_NIF_TERM lets_atom_async; 109 | extern ERL_NIF_TERM lets_atom_filter_policy; 110 | extern ERL_NIF_TERM lets_atom_bloom; 111 | extern ERL_NIF_TERM lets_atom_verify_checksums; 112 | extern ERL_NIF_TERM lets_atom_fill_cache; 113 | extern ERL_NIF_TERM lets_atom_sync; 114 | extern ERL_NIF_TERM lets_atom_end_of_table; 115 | extern ERL_NIF_TERM lets_atom_when_destroyed; 116 | 117 | // prototypes 118 | extern bool lets_impl_nif_lib_init(ErlNifEnv* env); 119 | 120 | extern bool lets_init(lets_impl& impl, 121 | const char type, const char privacy, const char* name, const size_t namelen); 122 | extern bool lets_create(lets_impl& impl, 123 | const char op); 124 | 125 | extern bool lets_parse_options(ErlNifEnv* env, lets_impl& impl, 126 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 127 | extern bool lets_parse_read_options(ErlNifEnv* env, rocksdb::ReadOptions& opts, 128 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 129 | extern bool lets_parse_write_options(ErlNifEnv* env, rocksdb::WriteOptions& opts, 130 | ERL_NIF_TERM& options, const ERL_NIF_TERM& options_len); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | #endif /* RETS_NIF_LIB_H */ 137 | -------------------------------------------------------------------------------- /doc/edoc-info: -------------------------------------------------------------------------------- 1 | %% encoding: UTF-8 2 | {application,lets}. 3 | {packages,[]}. 4 | {modules,[hets_impl_drv,hets_impl_nif,lets,lets_impl_drv,lets_impl_nif, 5 | rets_impl_drv,rets_impl_nif]}. 6 | -------------------------------------------------------------------------------- /doc/hets_impl_drv.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module hets_impl_drv # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false. Currently, the specified process must be same as 82 | calling process. If not, a badarg error is raised.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
83 | 84 | 85 | 86 | 87 | ## Function Details ## 88 | 89 | 90 | 91 | ### delete/1 ### 92 | 93 | 94 |

 95 | delete(Gen_tid::tid()) -> true
 96 | 
97 |
98 | 99 | __See also:__ [lets:delete/1](lets.md#delete-1). 100 | 101 | 102 | ### delete/2 ### 103 | 104 | 105 |

106 | delete(Gen_tid::tid(), Key::key()) -> true
107 | 
108 |
109 | 110 | __See also:__ [lets:delete/2](lets.md#delete-2). 111 | 112 | 113 | ### delete_all_objects/1 ### 114 | 115 | 116 |

117 | delete_all_objects(Gen_tid::tid()) -> true
118 | 
119 |
120 | 121 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 122 | 123 | 124 | ### destroy/2 ### 125 | 126 | 127 |

128 | destroy(Tid::tid(), Opts::opts()) -> true
129 | 
130 |
131 | 132 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 133 | 134 | 135 | ### first/1 ### 136 | 137 | 138 |

139 | first(Gen_tid::tid()) -> key() | '$end_of_table'
140 | 
141 |
142 | 143 | __See also:__ [lets:first/1](lets.md#first-1). 144 | 145 | 146 | ### first/2 ### 147 | 148 | 149 |

150 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
151 | 
152 |
153 | 154 | __See also:__ [lets:first/1](lets.md#first-1). 155 | 156 | 157 | ### first_iter/1 ### 158 | 159 | 160 |

161 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
162 | 
163 |
164 | 165 | __See also:__ [lets:first/1](lets.md#first-1). 166 | 167 | 168 | ### first_iter/2 ### 169 | 170 | 171 |

172 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
173 | 
174 |
175 | 176 | __See also:__ [lets:first/1](lets.md#first-1). 177 | 178 | 179 | ### info_memory/1 ### 180 | 181 | 182 |

183 | info_memory(Gen_tid::tid()) -> non_neg_integer()
184 | 
185 |
186 | 187 | __See also:__ [lets:info/1](lets.md#info-1). 188 | 189 | 190 | ### info_size/1 ### 191 | 192 | 193 |

194 | info_size(Gen_tid::tid()) -> non_neg_integer()
195 | 
196 |
197 | 198 | __See also:__ [lets:info/1](lets.md#info-1). 199 | 200 | 201 | ### insert/2 ### 202 | 203 | 204 |

205 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
206 | 
207 |
208 | 209 | __See also:__ [lets:insert/2](lets.md#insert-2). 210 | 211 | 212 | ### insert_new/2 ### 213 | 214 | 215 |

216 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
217 | 
218 |
219 | 220 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 221 | 222 | 223 | ### last/1 ### 224 | 225 | 226 |

227 | last(Gen_tid::tid()) -> key() | '$end_of_table'
228 | 
229 |
230 | 231 | __See also:__ [lets:last/1](lets.md#last-1). 232 | 233 | 234 | ### last/2 ### 235 | 236 | 237 |

238 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
239 | 
240 |
241 | 242 | __See also:__ [lets:last/1](lets.md#last-1). 243 | 244 | 245 | ### last_iter/1 ### 246 | 247 | 248 |

249 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
250 | 
251 |
252 | 253 | __See also:__ [lets:last/1](lets.md#last-1). 254 | 255 | 256 | ### last_iter/2 ### 257 | 258 | 259 |

260 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
261 | 
262 |
263 | 264 | __See also:__ [lets:last/1](lets.md#last-1). 265 | 266 | 267 | ### lookup/2 ### 268 | 269 | 270 |

271 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
272 | 
273 |
274 | 275 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 276 | 277 | 278 | ### lookup_element/3 ### 279 | 280 | 281 |

282 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
283 | 
284 |
285 | 286 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 287 | 288 | 289 | ### member/2 ### 290 | 291 | 292 |

293 | member(Gen_tid::tid(), Key::key()) -> true | false
294 | 
295 |
296 | 297 | __See also:__ [lets:member/2](lets.md#member-2). 298 | 299 | 300 | ### next/2 ### 301 | 302 | 303 |

304 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
305 | 
306 |
307 | 308 | __See also:__ [lets:next/2](lets.md#next-2). 309 | 310 | 311 | ### next/3 ### 312 | 313 | 314 |

315 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
316 | 
317 |
318 | 319 | __See also:__ [lets:next/2](lets.md#next-2). 320 | 321 | 322 | ### next_iter/2 ### 323 | 324 | 325 |

326 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
327 | 
328 |
329 | 330 | __See also:__ [lets:next/2](lets.md#next-2). 331 | 332 | 333 | ### next_iter/3 ### 334 | 335 | 336 |

337 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
338 | 
339 |
340 | 341 | __See also:__ [lets:next/2](lets.md#next-2). 342 | 343 | 344 | ### notify/4 ### 345 | 346 | 347 |

348 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
349 | 
350 |
351 | 352 |

Register the specified process to be sent the specified 353 | message when the table is destroyed and return true. Otherwise, 354 | return false. Currently, the specified process must be same as 355 | calling process. If not, a badarg error is raised.

356 | 357 | 358 | 359 | ### open/2 ### 360 | 361 | 362 |

363 | open(Tid::tid(), Opts::opts()) -> tid()
364 | 
365 |
366 | 367 | __See also:__ [lets:new/2](lets.md#new-2). 368 | 369 | 370 | ### prev/2 ### 371 | 372 | 373 |

374 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
375 | 
376 |
377 | 378 | __See also:__ [lets:prev/2](lets.md#prev-2). 379 | 380 | 381 | ### prev/3 ### 382 | 383 | 384 |

385 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
386 | 
387 |
388 | 389 | __See also:__ [lets:prev/2](lets.md#prev-2). 390 | 391 | 392 | ### prev_iter/2 ### 393 | 394 | 395 |

396 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
397 | 
398 |
399 | 400 | __See also:__ [lets:prev/2](lets.md#prev-2). 401 | 402 | 403 | ### prev_iter/3 ### 404 | 405 | 406 |

407 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
408 | 
409 |
410 | 411 | __See also:__ [lets:prev/2](lets.md#prev-2). 412 | 413 | 414 | ### repair/2 ### 415 | 416 | 417 |

418 | repair(Tid::tid(), Opts::opts()) -> true
419 | 
420 |
421 | 422 | __See also:__ [lets:repair/2](lets.md#repair-2). 423 | -------------------------------------------------------------------------------- /doc/hets_impl_nif.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module hets_impl_nif # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
82 | 83 | 84 | 85 | 86 | ## Function Details ## 87 | 88 | 89 | 90 | ### delete/1 ### 91 | 92 | 93 |

 94 | delete(Gen_tid::tid()) -> true
 95 | 
96 |
97 | 98 | __See also:__ [lets:delete/1](lets.md#delete-1). 99 | 100 | 101 | ### delete/2 ### 102 | 103 | 104 |

105 | delete(Gen_tid::tid(), Key::key()) -> true
106 | 
107 |
108 | 109 | __See also:__ [lets:delete/2](lets.md#delete-2). 110 | 111 | 112 | ### delete_all_objects/1 ### 113 | 114 | 115 |

116 | delete_all_objects(Gen_tid::tid()) -> true
117 | 
118 |
119 | 120 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 121 | 122 | 123 | ### destroy/2 ### 124 | 125 | 126 |

127 | destroy(Tid::tid(), Opts::opts()) -> true
128 | 
129 |
130 | 131 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 132 | 133 | 134 | ### first/1 ### 135 | 136 | 137 |

138 | first(Gen_tid::tid()) -> key() | '$end_of_table'
139 | 
140 |
141 | 142 | __See also:__ [lets:first/1](lets.md#first-1). 143 | 144 | 145 | ### first/2 ### 146 | 147 | 148 |

149 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
150 | 
151 |
152 | 153 | __See also:__ [lets:first/1](lets.md#first-1). 154 | 155 | 156 | ### first_iter/1 ### 157 | 158 | 159 |

160 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
161 | 
162 |
163 | 164 | __See also:__ [lets:first/1](lets.md#first-1). 165 | 166 | 167 | ### first_iter/2 ### 168 | 169 | 170 |

171 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
172 | 
173 |
174 | 175 | __See also:__ [lets:first/1](lets.md#first-1). 176 | 177 | 178 | ### info_memory/1 ### 179 | 180 | 181 |

182 | info_memory(Gen_tid::tid()) -> non_neg_integer()
183 | 
184 |
185 | 186 | __See also:__ [lets:info/1](lets.md#info-1). 187 | 188 | 189 | ### info_size/1 ### 190 | 191 | 192 |

193 | info_size(Gen_tid::tid()) -> non_neg_integer()
194 | 
195 |
196 | 197 | __See also:__ [lets:info/1](lets.md#info-1). 198 | 199 | 200 | ### insert/2 ### 201 | 202 | 203 |

204 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
205 | 
206 |
207 | 208 | __See also:__ [lets:insert/2](lets.md#insert-2). 209 | 210 | 211 | ### insert_new/2 ### 212 | 213 | 214 |

215 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
216 | 
217 |
218 | 219 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 220 | 221 | 222 | ### last/1 ### 223 | 224 | 225 |

226 | last(Gen_tid::tid()) -> key() | '$end_of_table'
227 | 
228 |
229 | 230 | __See also:__ [lets:last/1](lets.md#last-1). 231 | 232 | 233 | ### last/2 ### 234 | 235 | 236 |

237 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
238 | 
239 |
240 | 241 | __See also:__ [lets:last/1](lets.md#last-1). 242 | 243 | 244 | ### last_iter/1 ### 245 | 246 | 247 |

248 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
249 | 
250 |
251 | 252 | __See also:__ [lets:last/1](lets.md#last-1). 253 | 254 | 255 | ### last_iter/2 ### 256 | 257 | 258 |

259 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
260 | 
261 |
262 | 263 | __See also:__ [lets:last/1](lets.md#last-1). 264 | 265 | 266 | ### lookup/2 ### 267 | 268 | 269 |

270 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
271 | 
272 |
273 | 274 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 275 | 276 | 277 | ### lookup_element/3 ### 278 | 279 | 280 |

281 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
282 | 
283 |
284 | 285 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 286 | 287 | 288 | ### member/2 ### 289 | 290 | 291 |

292 | member(Gen_tid::tid(), Key::key()) -> true | false
293 | 
294 |
295 | 296 | __See also:__ [lets:member/2](lets.md#member-2). 297 | 298 | 299 | ### next/2 ### 300 | 301 | 302 |

303 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
304 | 
305 |
306 | 307 | __See also:__ [lets:next/2](lets.md#next-2). 308 | 309 | 310 | ### next/3 ### 311 | 312 | 313 |

314 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
315 | 
316 |
317 | 318 | __See also:__ [lets:next/2](lets.md#next-2). 319 | 320 | 321 | ### next_iter/2 ### 322 | 323 | 324 |

325 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
326 | 
327 |
328 | 329 | __See also:__ [lets:next/2](lets.md#next-2). 330 | 331 | 332 | ### next_iter/3 ### 333 | 334 | 335 |

336 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
337 | 
338 |
339 | 340 | __See also:__ [lets:next/2](lets.md#next-2). 341 | 342 | 343 | ### notify/4 ### 344 | 345 | 346 |

347 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
348 | 
349 |
350 | 351 |

Register the specified process to be sent the specified 352 | message when the table is destroyed and return true. Otherwise, 353 | return false.

354 | 355 | 356 | 357 | ### open/2 ### 358 | 359 | 360 |

361 | open(Tid::tid(), Opts::opts()) -> tid()
362 | 
363 |
364 | 365 | __See also:__ [lets:new/2](lets.md#new-2). 366 | 367 | 368 | ### prev/2 ### 369 | 370 | 371 |

372 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
373 | 
374 |
375 | 376 | __See also:__ [lets:prev/2](lets.md#prev-2). 377 | 378 | 379 | ### prev/3 ### 380 | 381 | 382 |

383 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
384 | 
385 |
386 | 387 | __See also:__ [lets:prev/2](lets.md#prev-2). 388 | 389 | 390 | ### prev_iter/2 ### 391 | 392 | 393 |

394 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
395 | 
396 |
397 | 398 | __See also:__ [lets:prev/2](lets.md#prev-2). 399 | 400 | 401 | ### prev_iter/3 ### 402 | 403 | 404 |

405 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
406 | 
407 |
408 | 409 | __See also:__ [lets:prev/2](lets.md#prev-2). 410 | 411 | 412 | ### repair/2 ### 413 | 414 | 415 |

416 | repair(Tid::tid(), Opts::opts()) -> true
417 | 
418 |
419 | 420 | __See also:__ [lets:repair/2](lets.md#repair-2). 421 | -------------------------------------------------------------------------------- /doc/lets_impl_drv.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module lets_impl_drv # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false. Currently, the specified process must be same as 82 | calling process. If not, a badarg error is raised.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
83 | 84 | 85 | 86 | 87 | ## Function Details ## 88 | 89 | 90 | 91 | ### delete/1 ### 92 | 93 | 94 |

 95 | delete(Gen_tid::tid()) -> true
 96 | 
97 |
98 | 99 | __See also:__ [lets:delete/1](lets.md#delete-1). 100 | 101 | 102 | ### delete/2 ### 103 | 104 | 105 |

106 | delete(Gen_tid::tid(), Key::key()) -> true
107 | 
108 |
109 | 110 | __See also:__ [lets:delete/2](lets.md#delete-2). 111 | 112 | 113 | ### delete_all_objects/1 ### 114 | 115 | 116 |

117 | delete_all_objects(Gen_tid::tid()) -> true
118 | 
119 |
120 | 121 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 122 | 123 | 124 | ### destroy/2 ### 125 | 126 | 127 |

128 | destroy(Tid::tid(), Opts::opts()) -> true
129 | 
130 |
131 | 132 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 133 | 134 | 135 | ### first/1 ### 136 | 137 | 138 |

139 | first(Gen_tid::tid()) -> key() | '$end_of_table'
140 | 
141 |
142 | 143 | __See also:__ [lets:first/1](lets.md#first-1). 144 | 145 | 146 | ### first/2 ### 147 | 148 | 149 |

150 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
151 | 
152 |
153 | 154 | __See also:__ [lets:first/1](lets.md#first-1). 155 | 156 | 157 | ### first_iter/1 ### 158 | 159 | 160 |

161 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
162 | 
163 |
164 | 165 | __See also:__ [lets:first/1](lets.md#first-1). 166 | 167 | 168 | ### first_iter/2 ### 169 | 170 | 171 |

172 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
173 | 
174 |
175 | 176 | __See also:__ [lets:first/1](lets.md#first-1). 177 | 178 | 179 | ### info_memory/1 ### 180 | 181 | 182 |

183 | info_memory(Gen_tid::tid()) -> non_neg_integer()
184 | 
185 |
186 | 187 | __See also:__ [lets:info/1](lets.md#info-1). 188 | 189 | 190 | ### info_size/1 ### 191 | 192 | 193 |

194 | info_size(Gen_tid::tid()) -> non_neg_integer()
195 | 
196 |
197 | 198 | __See also:__ [lets:info/1](lets.md#info-1). 199 | 200 | 201 | ### insert/2 ### 202 | 203 | 204 |

205 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
206 | 
207 |
208 | 209 | __See also:__ [lets:insert/2](lets.md#insert-2). 210 | 211 | 212 | ### insert_new/2 ### 213 | 214 | 215 |

216 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
217 | 
218 |
219 | 220 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 221 | 222 | 223 | ### last/1 ### 224 | 225 | 226 |

227 | last(Gen_tid::tid()) -> key() | '$end_of_table'
228 | 
229 |
230 | 231 | __See also:__ [lets:last/1](lets.md#last-1). 232 | 233 | 234 | ### last/2 ### 235 | 236 | 237 |

238 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
239 | 
240 |
241 | 242 | __See also:__ [lets:last/1](lets.md#last-1). 243 | 244 | 245 | ### last_iter/1 ### 246 | 247 | 248 |

249 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
250 | 
251 |
252 | 253 | __See also:__ [lets:last/1](lets.md#last-1). 254 | 255 | 256 | ### last_iter/2 ### 257 | 258 | 259 |

260 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
261 | 
262 |
263 | 264 | __See also:__ [lets:last/1](lets.md#last-1). 265 | 266 | 267 | ### lookup/2 ### 268 | 269 | 270 |

271 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
272 | 
273 |
274 | 275 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 276 | 277 | 278 | ### lookup_element/3 ### 279 | 280 | 281 |

282 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
283 | 
284 |
285 | 286 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 287 | 288 | 289 | ### member/2 ### 290 | 291 | 292 |

293 | member(Gen_tid::tid(), Key::key()) -> true | false
294 | 
295 |
296 | 297 | __See also:__ [lets:member/2](lets.md#member-2). 298 | 299 | 300 | ### next/2 ### 301 | 302 | 303 |

304 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
305 | 
306 |
307 | 308 | __See also:__ [lets:next/2](lets.md#next-2). 309 | 310 | 311 | ### next/3 ### 312 | 313 | 314 |

315 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
316 | 
317 |
318 | 319 | __See also:__ [lets:next/2](lets.md#next-2). 320 | 321 | 322 | ### next_iter/2 ### 323 | 324 | 325 |

326 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
327 | 
328 |
329 | 330 | __See also:__ [lets:next/2](lets.md#next-2). 331 | 332 | 333 | ### next_iter/3 ### 334 | 335 | 336 |

337 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
338 | 
339 |
340 | 341 | __See also:__ [lets:next/2](lets.md#next-2). 342 | 343 | 344 | ### notify/4 ### 345 | 346 | 347 |

348 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
349 | 
350 |
351 | 352 |

Register the specified process to be sent the specified 353 | message when the table is destroyed and return true. Otherwise, 354 | return false. Currently, the specified process must be same as 355 | calling process. If not, a badarg error is raised.

356 | 357 | 358 | 359 | ### open/2 ### 360 | 361 | 362 |

363 | open(Tid::tid(), Opts::opts()) -> tid()
364 | 
365 |
366 | 367 | __See also:__ [lets:new/2](lets.md#new-2). 368 | 369 | 370 | ### prev/2 ### 371 | 372 | 373 |

374 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
375 | 
376 |
377 | 378 | __See also:__ [lets:prev/2](lets.md#prev-2). 379 | 380 | 381 | ### prev/3 ### 382 | 383 | 384 |

385 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
386 | 
387 |
388 | 389 | __See also:__ [lets:prev/2](lets.md#prev-2). 390 | 391 | 392 | ### prev_iter/2 ### 393 | 394 | 395 |

396 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
397 | 
398 |
399 | 400 | __See also:__ [lets:prev/2](lets.md#prev-2). 401 | 402 | 403 | ### prev_iter/3 ### 404 | 405 | 406 |

407 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
408 | 
409 |
410 | 411 | __See also:__ [lets:prev/2](lets.md#prev-2). 412 | 413 | 414 | ### repair/2 ### 415 | 416 | 417 |

418 | repair(Tid::tid(), Opts::opts()) -> true
419 | 
420 |
421 | 422 | __See also:__ [lets:repair/2](lets.md#repair-2). 423 | -------------------------------------------------------------------------------- /doc/lets_impl_nif.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module lets_impl_nif # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
82 | 83 | 84 | 85 | 86 | ## Function Details ## 87 | 88 | 89 | 90 | ### delete/1 ### 91 | 92 | 93 |

 94 | delete(Gen_tid::tid()) -> true
 95 | 
96 |
97 | 98 | __See also:__ [lets:delete/1](lets.md#delete-1). 99 | 100 | 101 | ### delete/2 ### 102 | 103 | 104 |

105 | delete(Gen_tid::tid(), Key::key()) -> true
106 | 
107 |
108 | 109 | __See also:__ [lets:delete/2](lets.md#delete-2). 110 | 111 | 112 | ### delete_all_objects/1 ### 113 | 114 | 115 |

116 | delete_all_objects(Gen_tid::tid()) -> true
117 | 
118 |
119 | 120 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 121 | 122 | 123 | ### destroy/2 ### 124 | 125 | 126 |

127 | destroy(Tid::tid(), Opts::opts()) -> true
128 | 
129 |
130 | 131 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 132 | 133 | 134 | ### first/1 ### 135 | 136 | 137 |

138 | first(Gen_tid::tid()) -> key() | '$end_of_table'
139 | 
140 |
141 | 142 | __See also:__ [lets:first/1](lets.md#first-1). 143 | 144 | 145 | ### first/2 ### 146 | 147 | 148 |

149 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
150 | 
151 |
152 | 153 | __See also:__ [lets:first/1](lets.md#first-1). 154 | 155 | 156 | ### first_iter/1 ### 157 | 158 | 159 |

160 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
161 | 
162 |
163 | 164 | __See also:__ [lets:first/1](lets.md#first-1). 165 | 166 | 167 | ### first_iter/2 ### 168 | 169 | 170 |

171 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
172 | 
173 |
174 | 175 | __See also:__ [lets:first/1](lets.md#first-1). 176 | 177 | 178 | ### info_memory/1 ### 179 | 180 | 181 |

182 | info_memory(Gen_tid::tid()) -> non_neg_integer()
183 | 
184 |
185 | 186 | __See also:__ [lets:info/1](lets.md#info-1). 187 | 188 | 189 | ### info_size/1 ### 190 | 191 | 192 |

193 | info_size(Gen_tid::tid()) -> non_neg_integer()
194 | 
195 |
196 | 197 | __See also:__ [lets:info/1](lets.md#info-1). 198 | 199 | 200 | ### insert/2 ### 201 | 202 | 203 |

204 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
205 | 
206 |
207 | 208 | __See also:__ [lets:insert/2](lets.md#insert-2). 209 | 210 | 211 | ### insert_new/2 ### 212 | 213 | 214 |

215 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
216 | 
217 |
218 | 219 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 220 | 221 | 222 | ### last/1 ### 223 | 224 | 225 |

226 | last(Gen_tid::tid()) -> key() | '$end_of_table'
227 | 
228 |
229 | 230 | __See also:__ [lets:last/1](lets.md#last-1). 231 | 232 | 233 | ### last/2 ### 234 | 235 | 236 |

237 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
238 | 
239 |
240 | 241 | __See also:__ [lets:last/1](lets.md#last-1). 242 | 243 | 244 | ### last_iter/1 ### 245 | 246 | 247 |

248 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
249 | 
250 |
251 | 252 | __See also:__ [lets:last/1](lets.md#last-1). 253 | 254 | 255 | ### last_iter/2 ### 256 | 257 | 258 |

259 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
260 | 
261 |
262 | 263 | __See also:__ [lets:last/1](lets.md#last-1). 264 | 265 | 266 | ### lookup/2 ### 267 | 268 | 269 |

270 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
271 | 
272 |
273 | 274 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 275 | 276 | 277 | ### lookup_element/3 ### 278 | 279 | 280 |

281 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
282 | 
283 |
284 | 285 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 286 | 287 | 288 | ### member/2 ### 289 | 290 | 291 |

292 | member(Gen_tid::tid(), Key::key()) -> true | false
293 | 
294 |
295 | 296 | __See also:__ [lets:member/2](lets.md#member-2). 297 | 298 | 299 | ### next/2 ### 300 | 301 | 302 |

303 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
304 | 
305 |
306 | 307 | __See also:__ [lets:next/2](lets.md#next-2). 308 | 309 | 310 | ### next/3 ### 311 | 312 | 313 |

314 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
315 | 
316 |
317 | 318 | __See also:__ [lets:next/2](lets.md#next-2). 319 | 320 | 321 | ### next_iter/2 ### 322 | 323 | 324 |

325 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
326 | 
327 |
328 | 329 | __See also:__ [lets:next/2](lets.md#next-2). 330 | 331 | 332 | ### next_iter/3 ### 333 | 334 | 335 |

336 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
337 | 
338 |
339 | 340 | __See also:__ [lets:next/2](lets.md#next-2). 341 | 342 | 343 | ### notify/4 ### 344 | 345 | 346 |

347 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
348 | 
349 |
350 | 351 |

Register the specified process to be sent the specified 352 | message when the table is destroyed and return true. Otherwise, 353 | return false.

354 | 355 | 356 | 357 | ### open/2 ### 358 | 359 | 360 |

361 | open(Tid::tid(), Opts::opts()) -> tid()
362 | 
363 |
364 | 365 | __See also:__ [lets:new/2](lets.md#new-2). 366 | 367 | 368 | ### prev/2 ### 369 | 370 | 371 |

372 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
373 | 
374 |
375 | 376 | __See also:__ [lets:prev/2](lets.md#prev-2). 377 | 378 | 379 | ### prev/3 ### 380 | 381 | 382 |

383 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
384 | 
385 |
386 | 387 | __See also:__ [lets:prev/2](lets.md#prev-2). 388 | 389 | 390 | ### prev_iter/2 ### 391 | 392 | 393 |

394 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
395 | 
396 |
397 | 398 | __See also:__ [lets:prev/2](lets.md#prev-2). 399 | 400 | 401 | ### prev_iter/3 ### 402 | 403 | 404 |

405 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
406 | 
407 |
408 | 409 | __See also:__ [lets:prev/2](lets.md#prev-2). 410 | 411 | 412 | ### repair/2 ### 413 | 414 | 415 |

416 | repair(Tid::tid(), Opts::opts()) -> true
417 | 
418 |
419 | 420 | __See also:__ [lets:repair/2](lets.md#repair-2). 421 | -------------------------------------------------------------------------------- /doc/rets_impl_drv.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module rets_impl_drv # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false. Currently, the specified process must be same as 82 | calling process. If not, a badarg error is raised.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
83 | 84 | 85 | 86 | 87 | ## Function Details ## 88 | 89 | 90 | 91 | ### delete/1 ### 92 | 93 | 94 |

 95 | delete(Gen_tid::tid()) -> true
 96 | 
97 |
98 | 99 | __See also:__ [lets:delete/1](lets.md#delete-1). 100 | 101 | 102 | ### delete/2 ### 103 | 104 | 105 |

106 | delete(Gen_tid::tid(), Key::key()) -> true
107 | 
108 |
109 | 110 | __See also:__ [lets:delete/2](lets.md#delete-2). 111 | 112 | 113 | ### delete_all_objects/1 ### 114 | 115 | 116 |

117 | delete_all_objects(Gen_tid::tid()) -> true
118 | 
119 |
120 | 121 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 122 | 123 | 124 | ### destroy/2 ### 125 | 126 | 127 |

128 | destroy(Tid::tid(), Opts::opts()) -> true
129 | 
130 |
131 | 132 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 133 | 134 | 135 | ### first/1 ### 136 | 137 | 138 |

139 | first(Gen_tid::tid()) -> key() | '$end_of_table'
140 | 
141 |
142 | 143 | __See also:__ [lets:first/1](lets.md#first-1). 144 | 145 | 146 | ### first/2 ### 147 | 148 | 149 |

150 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
151 | 
152 |
153 | 154 | __See also:__ [lets:first/1](lets.md#first-1). 155 | 156 | 157 | ### first_iter/1 ### 158 | 159 | 160 |

161 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
162 | 
163 |
164 | 165 | __See also:__ [lets:first/1](lets.md#first-1). 166 | 167 | 168 | ### first_iter/2 ### 169 | 170 | 171 |

172 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
173 | 
174 |
175 | 176 | __See also:__ [lets:first/1](lets.md#first-1). 177 | 178 | 179 | ### info_memory/1 ### 180 | 181 | 182 |

183 | info_memory(Gen_tid::tid()) -> non_neg_integer()
184 | 
185 |
186 | 187 | __See also:__ [lets:info/1](lets.md#info-1). 188 | 189 | 190 | ### info_size/1 ### 191 | 192 | 193 |

194 | info_size(Gen_tid::tid()) -> non_neg_integer()
195 | 
196 |
197 | 198 | __See also:__ [lets:info/1](lets.md#info-1). 199 | 200 | 201 | ### insert/2 ### 202 | 203 | 204 |

205 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
206 | 
207 |
208 | 209 | __See also:__ [lets:insert/2](lets.md#insert-2). 210 | 211 | 212 | ### insert_new/2 ### 213 | 214 | 215 |

216 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
217 | 
218 |
219 | 220 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 221 | 222 | 223 | ### last/1 ### 224 | 225 | 226 |

227 | last(Gen_tid::tid()) -> key() | '$end_of_table'
228 | 
229 |
230 | 231 | __See also:__ [lets:last/1](lets.md#last-1). 232 | 233 | 234 | ### last/2 ### 235 | 236 | 237 |

238 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
239 | 
240 |
241 | 242 | __See also:__ [lets:last/1](lets.md#last-1). 243 | 244 | 245 | ### last_iter/1 ### 246 | 247 | 248 |

249 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
250 | 
251 |
252 | 253 | __See also:__ [lets:last/1](lets.md#last-1). 254 | 255 | 256 | ### last_iter/2 ### 257 | 258 | 259 |

260 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
261 | 
262 |
263 | 264 | __See also:__ [lets:last/1](lets.md#last-1). 265 | 266 | 267 | ### lookup/2 ### 268 | 269 | 270 |

271 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
272 | 
273 |
274 | 275 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 276 | 277 | 278 | ### lookup_element/3 ### 279 | 280 | 281 |

282 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
283 | 
284 |
285 | 286 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 287 | 288 | 289 | ### member/2 ### 290 | 291 | 292 |

293 | member(Gen_tid::tid(), Key::key()) -> true | false
294 | 
295 |
296 | 297 | __See also:__ [lets:member/2](lets.md#member-2). 298 | 299 | 300 | ### next/2 ### 301 | 302 | 303 |

304 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
305 | 
306 |
307 | 308 | __See also:__ [lets:next/2](lets.md#next-2). 309 | 310 | 311 | ### next/3 ### 312 | 313 | 314 |

315 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
316 | 
317 |
318 | 319 | __See also:__ [lets:next/2](lets.md#next-2). 320 | 321 | 322 | ### next_iter/2 ### 323 | 324 | 325 |

326 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
327 | 
328 |
329 | 330 | __See also:__ [lets:next/2](lets.md#next-2). 331 | 332 | 333 | ### next_iter/3 ### 334 | 335 | 336 |

337 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
338 | 
339 |
340 | 341 | __See also:__ [lets:next/2](lets.md#next-2). 342 | 343 | 344 | ### notify/4 ### 345 | 346 | 347 |

348 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
349 | 
350 |
351 | 352 |

Register the specified process to be sent the specified 353 | message when the table is destroyed and return true. Otherwise, 354 | return false. Currently, the specified process must be same as 355 | calling process. If not, a badarg error is raised.

356 | 357 | 358 | 359 | ### open/2 ### 360 | 361 | 362 |

363 | open(Tid::tid(), Opts::opts()) -> tid()
364 | 
365 |
366 | 367 | __See also:__ [lets:new/2](lets.md#new-2). 368 | 369 | 370 | ### prev/2 ### 371 | 372 | 373 |

374 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
375 | 
376 |
377 | 378 | __See also:__ [lets:prev/2](lets.md#prev-2). 379 | 380 | 381 | ### prev/3 ### 382 | 383 | 384 |

385 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
386 | 
387 |
388 | 389 | __See also:__ [lets:prev/2](lets.md#prev-2). 390 | 391 | 392 | ### prev_iter/2 ### 393 | 394 | 395 |

396 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
397 | 
398 |
399 | 400 | __See also:__ [lets:prev/2](lets.md#prev-2). 401 | 402 | 403 | ### prev_iter/3 ### 404 | 405 | 406 |

407 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
408 | 
409 |
410 | 411 | __See also:__ [lets:prev/2](lets.md#prev-2). 412 | 413 | 414 | ### repair/2 ### 415 | 416 | 417 |

418 | repair(Tid::tid(), Opts::opts()) -> true
419 | 
420 |
421 | 422 | __See also:__ [lets:repair/2](lets.md#repair-2). 423 | -------------------------------------------------------------------------------- /doc/rets_impl_nif.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Module rets_impl_nif # 4 | * [Data Types](#types) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | __Behaviours:__ [`gen_ets_ns`](gen_ets_ns.md). 9 | 10 | 11 | 12 | ## Data Types ## 13 | 14 | 15 | 16 | 17 | ### key() ### 18 | 19 | 20 | 21 |

 22 | key() = lets:key()
 23 | 
24 | 25 | 26 | 27 | 28 | 29 | ### object() ### 30 | 31 | 32 | 33 |

 34 | object() = lets:object()
 35 | 
36 | 37 | 38 | 39 | 40 | 41 | ### opts() ### 42 | 43 | 44 | 45 |

 46 | opts() = lets:opts()
 47 | 
48 | 49 | 50 | 51 | 52 | 53 | ### pos() ### 54 | 55 | 56 | 57 |

 58 | pos() = lets:pos()
 59 | 
60 | 61 | 62 | 63 | 64 | 65 | ### tid() ### 66 | 67 | 68 | 69 |

 70 | tid() = lets:lets_tid()
 71 | 
72 | 73 | 74 | 75 | 76 | ## Function Index ## 77 | 78 | 79 |
delete/1
delete/2
delete_all_objects/1
destroy/2
first/1
first/2
first_iter/1
first_iter/2
info_memory/1
info_size/1
insert/2
insert_new/2
last/1
last/2
last_iter/1
last_iter/2
lookup/2
lookup_element/3
member/2
next/2
next/3
next_iter/2
next_iter/3
notify/4

Register the specified process to be sent the specified 80 | message when the table is destroyed and return true. Otherwise, 81 | return false.

.
open/2
prev/2
prev/3
prev_iter/2
prev_iter/3
repair/2
82 | 83 | 84 | 85 | 86 | ## Function Details ## 87 | 88 | 89 | 90 | ### delete/1 ### 91 | 92 | 93 |

 94 | delete(Gen_tid::tid()) -> true
 95 | 
96 |
97 | 98 | __See also:__ [lets:delete/1](lets.md#delete-1). 99 | 100 | 101 | ### delete/2 ### 102 | 103 | 104 |

105 | delete(Gen_tid::tid(), Key::key()) -> true
106 | 
107 |
108 | 109 | __See also:__ [lets:delete/2](lets.md#delete-2). 110 | 111 | 112 | ### delete_all_objects/1 ### 113 | 114 | 115 |

116 | delete_all_objects(Gen_tid::tid()) -> true
117 | 
118 |
119 | 120 | __See also:__ [lets:delete_all_objects/1](lets.md#delete_all_objects-1). 121 | 122 | 123 | ### destroy/2 ### 124 | 125 | 126 |

127 | destroy(Tid::tid(), Opts::opts()) -> true
128 | 
129 |
130 | 131 | __See also:__ [lets:destroy/2](lets.md#destroy-2). 132 | 133 | 134 | ### first/1 ### 135 | 136 | 137 |

138 | first(Gen_tid::tid()) -> key() | '$end_of_table'
139 | 
140 |
141 | 142 | __See also:__ [lets:first/1](lets.md#first-1). 143 | 144 | 145 | ### first/2 ### 146 | 147 | 148 |

149 | first(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
150 | 
151 |
152 | 153 | __See also:__ [lets:first/1](lets.md#first-1). 154 | 155 | 156 | ### first_iter/1 ### 157 | 158 | 159 |

160 | first_iter(Gen_tid::tid()) -> object() | '$end_of_table'
161 | 
162 |
163 | 164 | __See also:__ [lets:first/1](lets.md#first-1). 165 | 166 | 167 | ### first_iter/2 ### 168 | 169 | 170 |

171 | first_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
172 | 
173 |
174 | 175 | __See also:__ [lets:first/1](lets.md#first-1). 176 | 177 | 178 | ### info_memory/1 ### 179 | 180 | 181 |

182 | info_memory(Gen_tid::tid()) -> non_neg_integer()
183 | 
184 |
185 | 186 | __See also:__ [lets:info/1](lets.md#info-1). 187 | 188 | 189 | ### info_size/1 ### 190 | 191 | 192 |

193 | info_size(Gen_tid::tid()) -> non_neg_integer()
194 | 
195 |
196 | 197 | __See also:__ [lets:info/1](lets.md#info-1). 198 | 199 | 200 | ### insert/2 ### 201 | 202 | 203 |

204 | insert(Gen_tid::tid(), Object::object() | [object()]) -> true
205 | 
206 |
207 | 208 | __See also:__ [lets:insert/2](lets.md#insert-2). 209 | 210 | 211 | ### insert_new/2 ### 212 | 213 | 214 |

215 | insert_new(Gen_tid::tid(), Object::object() | [object()]) -> true
216 | 
217 |
218 | 219 | __See also:__ [lets:insert_new/2](lets.md#insert_new-2). 220 | 221 | 222 | ### last/1 ### 223 | 224 | 225 |

226 | last(Gen_tid::tid()) -> key() | '$end_of_table'
227 | 
228 |
229 | 230 | __See also:__ [lets:last/1](lets.md#last-1). 231 | 232 | 233 | ### last/2 ### 234 | 235 | 236 |

237 | last(Gen_tid::tid(), N::pos_integer()) -> [key()] | '$end_of_table'
238 | 
239 |
240 | 241 | __See also:__ [lets:last/1](lets.md#last-1). 242 | 243 | 244 | ### last_iter/1 ### 245 | 246 | 247 |

248 | last_iter(Gen_tid::tid()) -> object() | '$end_of_table'
249 | 
250 |
251 | 252 | __See also:__ [lets:last/1](lets.md#last-1). 253 | 254 | 255 | ### last_iter/2 ### 256 | 257 | 258 |

259 | last_iter(Gen_tid::tid(), N::pos_integer()) -> [object()] | '$end_of_table'
260 | 
261 |
262 | 263 | __See also:__ [lets:last/1](lets.md#last-1). 264 | 265 | 266 | ### lookup/2 ### 267 | 268 | 269 |

270 | lookup(Gen_tid::tid(), Key::key()) -> [object()]
271 | 
272 |
273 | 274 | __See also:__ [lets:lookup/2](lets.md#lookup-2). 275 | 276 | 277 | ### lookup_element/3 ### 278 | 279 | 280 |

281 | lookup_element(Gen_tid::tid(), Key::key(), Pos::pos()) -> term()
282 | 
283 |
284 | 285 | __See also:__ [lets:lookup_element/3](lets.md#lookup_element-3). 286 | 287 | 288 | ### member/2 ### 289 | 290 | 291 |

292 | member(Gen_tid::tid(), Key::key()) -> true | false
293 | 
294 |
295 | 296 | __See also:__ [lets:member/2](lets.md#member-2). 297 | 298 | 299 | ### next/2 ### 300 | 301 | 302 |

303 | next(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
304 | 
305 |
306 | 307 | __See also:__ [lets:next/2](lets.md#next-2). 308 | 309 | 310 | ### next/3 ### 311 | 312 | 313 |

314 | next(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
315 | 
316 |
317 | 318 | __See also:__ [lets:next/2](lets.md#next-2). 319 | 320 | 321 | ### next_iter/2 ### 322 | 323 | 324 |

325 | next_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
326 | 
327 |
328 | 329 | __See also:__ [lets:next/2](lets.md#next-2). 330 | 331 | 332 | ### next_iter/3 ### 333 | 334 | 335 |

336 | next_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
337 | 
338 |
339 | 340 | __See also:__ [lets:next/2](lets.md#next-2). 341 | 342 | 343 | ### notify/4 ### 344 | 345 | 346 |

347 | notify(Gen_tid::tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false
348 | 
349 |
350 | 351 |

Register the specified process to be sent the specified 352 | message when the table is destroyed and return true. Otherwise, 353 | return false.

354 | 355 | 356 | 357 | ### open/2 ### 358 | 359 | 360 |

361 | open(Tid::tid(), Opts::opts()) -> tid()
362 | 
363 |
364 | 365 | __See also:__ [lets:new/2](lets.md#new-2). 366 | 367 | 368 | ### prev/2 ### 369 | 370 | 371 |

372 | prev(Gen_tid::#gen_tid{}, Key::key()) -> key() | '$end_of_table'
373 | 
374 |
375 | 376 | __See also:__ [lets:prev/2](lets.md#prev-2). 377 | 378 | 379 | ### prev/3 ### 380 | 381 | 382 |

383 | prev(Gen_tid::#gen_tid{}, Key::key(), N::pos_integer()) -> [key()] | '$end_of_table'
384 | 
385 |
386 | 387 | __See also:__ [lets:prev/2](lets.md#prev-2). 388 | 389 | 390 | ### prev_iter/2 ### 391 | 392 | 393 |

394 | prev_iter(Gen_tid::tid(), Key::key()) -> object() | '$end_of_table'
395 | 
396 |
397 | 398 | __See also:__ [lets:prev/2](lets.md#prev-2). 399 | 400 | 401 | ### prev_iter/3 ### 402 | 403 | 404 |

405 | prev_iter(Gen_tid::tid(), Key::key(), N::pos_integer()) -> [object()] | '$end_of_table'
406 | 
407 |
408 | 409 | __See also:__ [lets:prev/2](lets.md#prev-2). 410 | 411 | 412 | ### repair/2 ### 413 | 414 | 415 |

416 | repair(Tid::tid(), Opts::opts()) -> true
417 | 
418 |
419 | 420 | __See also:__ [lets:repair/2](lets.md#repair-2). 421 | -------------------------------------------------------------------------------- /priv/test/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | qc_leveldb_issue44 3 | qc_leveldb/ 4 | -------------------------------------------------------------------------------- /priv/test/Makefile: -------------------------------------------------------------------------------- 1 | 2 | LEVELDB_DIR=../../c_src/leveldb 3 | SNAPPY_DIR=../../c_src/snappy 4 | 5 | CC=gcc 6 | CFLAGS=-Wall -I $(LEVELDB_DIR)/include 7 | LDFLAGS=$(LEVELDB_DIR)/lib/libleveldb.a $(SNAPPY_DIR)/lib/libsnappy.a -lstdc++ -lpthread 8 | 9 | TEST=qc_leveldb_issue44 10 | 11 | HEADERS=qc_statemc_lets.h 12 | SOURCES=qc_statemc_lets.c $(TEST:=.c) 13 | OBJECTS=$(SOURCES:.c=.o) 14 | 15 | .PHONY: clean 16 | 17 | all: $(SOURCES) $(TEST) 18 | 19 | $(TEST): $(OBJECTS) $(HEADERS) 20 | $(CC) $(OBJECTS) $(LDFLAGS) -o $@ 21 | 22 | .c.o: 23 | $(CC) -c $(CFLAGS) $< -o $@ 24 | 25 | clean: 26 | rm -rf *.o $(EXECUTABLE) qc_leveldb 27 | -------------------------------------------------------------------------------- /priv/test/qc_leveldb_issue44.c: -------------------------------------------------------------------------------- 1 | // %%% The MIT License 2 | // %%% 3 | // %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // %%% all 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 21 | // %%% THE SOFTWARE. 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "qc_statemc_lets.h" 30 | 31 | 32 | int main() { 33 | leveldb_t* Db; 34 | char g[1] = {'g'}; 35 | size_t glen = 1; 36 | char nil[0] = {}; 37 | size_t nillen = 0; 38 | 39 | // #1 40 | Db = open0(); 41 | 42 | // #2 43 | close1(Db); 44 | 45 | // #3 46 | Db = reopen0(); 47 | 48 | // #4 49 | put2(Db, g, glen, nil, nillen); 50 | 51 | // #5 52 | close1(Db); 53 | 54 | // #6 55 | Db = reopen0(); 56 | 57 | // #7 58 | delete2(Db, g, glen); 59 | 60 | // #8 61 | delete2(Db, nil, nillen); 62 | 63 | // #9 64 | close1(Db); 65 | 66 | // #10 67 | Db = reopen0(); 68 | 69 | // #11 70 | delete2(Db, nil, nillen); 71 | 72 | // #12 73 | close1(Db); 74 | 75 | // #13 76 | Db = reopen0(); 77 | 78 | // #14 79 | put2(Db, nil, nillen, nil, nillen); 80 | 81 | // #15 82 | close1(Db); 83 | 84 | // #16 85 | Db = reopen0(); 86 | 87 | // #17 88 | close1(Db); 89 | 90 | // #18 91 | Db = reopen0(); 92 | 93 | // #19a 94 | char* bug = NULL; 95 | size_t buglen = 0; 96 | bug = last1(Db, &buglen); 97 | 98 | if (buglen == nillen && memcmp(bug, nil, nillen) == 0) { 99 | fprintf(stderr, "\n\n!!! NO - reappearing ghost key 'g' !!!\n\n"); 100 | } 101 | assert(buglen == nillen); 102 | assert(memcmp(bug, nil, nillen) == 0); 103 | 104 | fprintf(stderr, "KEY POINT => sleep for background compaction to finish it's work"); 105 | sleep(1); 106 | 107 | // #19a 108 | bug = NULL; 109 | buglen = 0; 110 | bug = last1(Db, &buglen); 111 | 112 | if (buglen == glen && memcmp(bug, g, glen) == 0) { 113 | fprintf(stderr, "\n\n!!! YES - reappearing ghost key 'g' !!!\n\n"); 114 | } 115 | assert(buglen == nillen); 116 | assert(memcmp(bug, nil, nillen) == 0); 117 | 118 | return 0; 119 | } 120 | 121 | /* 122 | Failed! 123 | [{init,{state,qc_statemc_lets,{state,false,false,undefined,[]}}}, 124 | {set,{var,1},{call,qc_leveldb,open,[]}}, 125 | {set,{var,4},{call,qc_leveldb,close,[{var,1}]}}, 126 | {set,{var,5},{call,qc_leveldb,reopen,[]}}, 127 | {set,{var,6},{call,qc_leveldb,put,[{var,5},{obj,<<"a">>,<<>>}]}}, 128 | {set,{var,9},{call,qc_leveldb,close,[{var,5}]}}, 129 | {set,{var,10},{call,qc_leveldb,reopen,[]}}, 130 | {set,{var,11},{call,qc_leveldb,delete,[{var,10},<<"a">>]}}, 131 | {set,{var,14},{call,qc_leveldb,delete,[{var,10},<<>>]}}, 132 | {set,{var,15},{call,qc_leveldb,close,[{var,10}]}}, 133 | {set,{var,19},{call,qc_leveldb,reopen,[]}}, 134 | {set,{var,22},{call,qc_leveldb,delete,[{var,19},<<>>]}}, 135 | {set,{var,26},{call,qc_leveldb,close,[{var,19}]}}, 136 | {set,{var,27},{call,qc_leveldb,reopen,[]}}, 137 | {set,{var,31},{call,qc_leveldb,put,[{var,27},{obj,<<>>,<<>>}]}}, 138 | {set,{var,33},{call,qc_leveldb,close,[{var,27}]}}, 139 | {set,{var,34},{call,qc_leveldb,reopen,[]}}, 140 | {set,{var,36},{call,qc_leveldb,close,[{var,34}]}}, 141 | {set,{var,37},{call,qc_leveldb,reopen,[]}}, 142 | {set,{var,40},{call,qc_leveldb,last,[{var,37}]}}] 143 | 144 | COMMANDS: 145 | "qc_statem-20111029-191936.erl" 146 | 147 | HISTORY: 148 | #1: 149 | Cmd: {set,{var,1},{call,qc_leveldb,open,[]}} 150 | Reply: {ptr,{struct,leveldb_t},16833504} 151 | State: {state,qc_statemc_lets,{state,false,false,undefined,[]}} 152 | 153 | #2: 154 | Cmd: {set,{var,4},{call,qc_leveldb,close,[{var,1}]}} 155 | Reply: true 156 | State: {state,qc_statemc_lets, 157 | {state,false,true,{ptr,{struct,leveldb_t},16833504},[]}} 158 | 159 | #3: 160 | Cmd: {set,{var,5},{call,qc_leveldb,reopen,[]}} 161 | Reply: {ptr,{struct,leveldb_t},16833616} 162 | State: {state,qc_statemc_lets,{state,false,true,undefined,[]}} 163 | 164 | #4: 165 | Cmd: {set,{var,6},{call,qc_leveldb,put,[{var,5},{obj,<<"a">>,<<>>}]}} 166 | Reply: true 167 | State: {state,qc_statemc_lets, 168 | {state,false,true,{ptr,{struct,leveldb_t},16833616},[]}} 169 | 170 | #5: 171 | Cmd: {set,{var,9},{call,qc_leveldb,close,[{var,5}]}} 172 | Reply: true 173 | State: {state,qc_statemc_lets, 174 | {state,false,true, 175 | {ptr,{struct,leveldb_t},16833616}, 176 | [{obj,<<"a">>,<<>>}]}} 177 | 178 | #6: 179 | Cmd: {set,{var,10},{call,qc_leveldb,reopen,[]}} 180 | Reply: {ptr,{struct,leveldb_t},16831264} 181 | State: {state,qc_statemc_lets, 182 | {state,false,true,undefined,[{obj,<<"a">>,<<>>}]}} 183 | 184 | #7: 185 | Cmd: {set,{var,11},{call,qc_leveldb,delete,[{var,10},<<"a">>]}} 186 | Reply: true 187 | State: {state,qc_statemc_lets, 188 | {state,false,true, 189 | {ptr,{struct,leveldb_t},16831264}, 190 | [{obj,<<"a">>,<<>>}]}} 191 | 192 | #8: 193 | Cmd: {set,{var,14},{call,qc_leveldb,delete,[{var,10},<<>>]}} 194 | Reply: true 195 | State: {state,qc_statemc_lets, 196 | {state,false,true,{ptr,{struct,leveldb_t},16831264},[]}} 197 | 198 | #9: 199 | Cmd: {set,{var,15},{call,qc_leveldb,close,[{var,10}]}} 200 | Reply: true 201 | State: {state,qc_statemc_lets, 202 | {state,false,true,{ptr,{struct,leveldb_t},16831264},[]}} 203 | 204 | #10: 205 | Cmd: {set,{var,19},{call,qc_leveldb,reopen,[]}} 206 | Reply: {ptr,{struct,leveldb_t},16831776} 207 | State: {state,qc_statemc_lets,{state,false,true,undefined,[]}} 208 | 209 | #11: 210 | Cmd: {set,{var,22},{call,qc_leveldb,delete,[{var,19},<<>>]}} 211 | Reply: true 212 | State: {state,qc_statemc_lets, 213 | {state,false,true,{ptr,{struct,leveldb_t},16831776},[]}} 214 | 215 | #12: 216 | Cmd: {set,{var,26},{call,qc_leveldb,close,[{var,19}]}} 217 | Reply: true 218 | State: {state,qc_statemc_lets, 219 | {state,false,true,{ptr,{struct,leveldb_t},16831776},[]}} 220 | 221 | #13: 222 | Cmd: {set,{var,27},{call,qc_leveldb,reopen,[]}} 223 | Reply: {ptr,{struct,leveldb_t},16831712} 224 | State: {state,qc_statemc_lets,{state,false,true,undefined,[]}} 225 | 226 | #14: 227 | Cmd: {set,{var,31},{call,qc_leveldb,put,[{var,27},{obj,<<>>,<<>>}]}} 228 | Reply: true 229 | State: {state,qc_statemc_lets, 230 | {state,false,true,{ptr,{struct,leveldb_t},16831712},[]}} 231 | 232 | #15: 233 | Cmd: {set,{var,33},{call,qc_leveldb,close,[{var,27}]}} 234 | Reply: true 235 | State: {state,qc_statemc_lets, 236 | {state,false,true, 237 | {ptr,{struct,leveldb_t},16831712}, 238 | [{obj,<<>>,<<>>}]}} 239 | 240 | #16: 241 | Cmd: {set,{var,34},{call,qc_leveldb,reopen,[]}} 242 | Reply: {ptr,{struct,leveldb_t},16832720} 243 | State: {state,qc_statemc_lets, 244 | {state,false,true,undefined,[{obj,<<>>,<<>>}]}} 245 | 246 | #17: 247 | Cmd: {set,{var,36},{call,qc_leveldb,close,[{var,34}]}} 248 | Reply: true 249 | State: {state,qc_statemc_lets, 250 | {state,false,true, 251 | {ptr,{struct,leveldb_t},16832720}, 252 | [{obj,<<>>,<<>>}]}} 253 | 254 | #18: 255 | Cmd: {set,{var,37},{call,qc_leveldb,reopen,[]}} 256 | Reply: {ptr,{struct,leveldb_t},16828000} 257 | State: {state,qc_statemc_lets, 258 | {state,false,true,undefined,[{obj,<<>>,<<>>}]}} 259 | 260 | #19: 261 | Cmd: {set,{var,40},{call,qc_leveldb,last,[{var,37}]}} 262 | Reply: <<"a">> 263 | State: {state,qc_statemc_lets, 264 | {state,false,true, 265 | {ptr,{struct,leveldb_t},16828000}, 266 | [{obj,<<>>,<<>>}]}} 267 | 268 | RESULT: 269 | {postcondition,false} 270 | 271 | STATE: 272 | {state,qc_statemc_lets, 273 | {state,false,true, 274 | {ptr,{struct,leveldb_t},16828000}, 275 | [{obj,<<>>,<<>>}]}} 276 | 277 | STATE IS SANE: 278 | true 279 | false 280 | */ 281 | -------------------------------------------------------------------------------- /priv/test/qc_statemc_lets.h: -------------------------------------------------------------------------------- 1 | // %%% The MIT License 2 | // %%% 3 | // %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | // %%% all 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 21 | // %%% THE SOFTWARE. 22 | 23 | #ifndef QC_STATEMC_LETS_H 24 | #define QC_STATEMC_LETS_H 25 | 26 | #include "leveldb/c.h" 27 | 28 | // -module(qc_leveldb). 29 | // 30 | // %% API 31 | // -export([%% test 32 | // setup/0 33 | // , teardown/0 34 | // , is_db/1 35 | // %% lets 36 | // , open/0, open/1 37 | // , reopen/0, reopen/1 38 | // , close/1 39 | // , put/2, put/3 40 | // , delete/2, delete/3 41 | // , get/2, get/3 42 | // , first/1, first/2 43 | // , last/1, last/2 44 | // , next/2, next/3 45 | // ]). 46 | 47 | extern leveldb_t* open0(); 48 | extern leveldb_t* open1(leveldb_options_t* Options); 49 | 50 | extern leveldb_t* reopen0(); 51 | extern leveldb_t* reopen1(leveldb_options_t* Options); 52 | 53 | extern void close1(leveldb_t* Db); 54 | 55 | extern void put2(leveldb_t* Db, char* Key, size_t KeyLen, char* Val, size_t ValLen); 56 | extern void put3(leveldb_t* Db, char* Key, size_t KeyLen, char* Val, size_t ValLen, const leveldb_writeoptions_t* Options); 57 | 58 | extern void delete2(leveldb_t* Db, char* Key, size_t KeyLen); 59 | extern void delete3(leveldb_t* Db, char* Key, size_t KeyLen, const leveldb_writeoptions_t* Options); 60 | 61 | extern char* get2(leveldb_t* Db, char* Key, size_t KeyLen, size_t* ValLen); 62 | extern char* get3(leveldb_t* Db, char* Key, size_t KeyLen, size_t* ValLen, const leveldb_readoptions_t* Options); 63 | 64 | extern char* first1(leveldb_t* Db, size_t *KeyLen); 65 | extern char* first2(leveldb_t* Db, size_t* KeyLen, const leveldb_readoptions_t* Options); 66 | 67 | extern char* last1(leveldb_t* Db, size_t *KeyLen); 68 | extern char* last2(leveldb_t* Db, size_t* KeyLen, const leveldb_readoptions_t* Options); 69 | 70 | extern char* next2(leveldb_t* Db, char* Key, size_t KeyLen, size_t* NextKeyLen); 71 | extern char* next3(leveldb_t* Db, char* Key, size_t KeyLen, size_t* NextKeyLen, const leveldb_readoptions_t* Options); 72 | 73 | extern char* read_binary(const char* B, size_t* BLen); 74 | extern int compare_binary(const char* A, size_t ALen, const char* B, size_t BLen); 75 | 76 | #endif /* QC_STATEMC_LETS_H */ 77 | -------------------------------------------------------------------------------- /priv/test/qc_statemc_leveldb_issue44.erl: -------------------------------------------------------------------------------- 1 | [{init,{state,qc_statemc_lets,{state,false,false,undefined,[]}}}, 2 | {set,{var,1},{call,qc_leveldb,open,[]}}, 3 | {set,{var,4},{call,qc_leveldb,close,[{var,1}]}}, 4 | {set,{var,5},{call,qc_leveldb,reopen,[]}}, 5 | {set,{var,6},{call,qc_leveldb,put,[{var,5},{obj,<<"a">>,<<>>}]}}, 6 | {set,{var,9},{call,qc_leveldb,close,[{var,5}]}}, 7 | {set,{var,10},{call,qc_leveldb,reopen,[]}}, 8 | {set,{var,11},{call,qc_leveldb,delete,[{var,10},<<"a">>]}}, 9 | {set,{var,14},{call,qc_leveldb,delete,[{var,10},<<>>]}}, 10 | {set,{var,15},{call,qc_leveldb,close,[{var,10}]}}, 11 | {set,{var,19},{call,qc_leveldb,reopen,[]}}, 12 | {set,{var,22},{call,qc_leveldb,delete,[{var,19},<<>>]}}, 13 | {set,{var,26},{call,qc_leveldb,close,[{var,19}]}}, 14 | {set,{var,27},{call,qc_leveldb,reopen,[]}}, 15 | {set,{var,31},{call,qc_leveldb,put,[{var,27},{obj,<<>>,<<>>}]}}, 16 | {set,{var,33},{call,qc_leveldb,close,[{var,27}]}}, 17 | {set,{var,34},{call,qc_leveldb,reopen,[]}}, 18 | {set,{var,36},{call,qc_leveldb,close,[{var,34}]}}, 19 | {set,{var,37},{call,qc_leveldb,reopen,[]}}, 20 | {set,{var,40},{call,qc_leveldb,last,[{var,37}]}} 21 | ]. 22 | -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/norton-archive/lets/1af72f76431f265d8fa2e8c6b41ca4f8a983fc59/rebar -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | %%% -*- mode: erlang -*- 2 | 3 | {require_min_otp_vsn, "R16"}. 4 | 5 | {pre_hooks, [{clean, "c_src/build_deps.sh clean"} 6 | , {'get-deps', "c_src/build_deps.sh get_deps"} 7 | , {compile, "c_src/build_deps.sh"} 8 | ]}. 9 | 10 | {port_env, [{"DRV_CFLAGS", "$DRV_CFLAGS -fPIC -O3 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers"} 11 | , {"x86_64-apple-darwin*", "DRV_CFLAGS", "$DRV_CFLAGS -Qunused-arguments"} 12 | ]}. 13 | {port_specs, [{".*", "priv/lib/lets_impl_drv.so", ["c_src/lets_impl_drv_lib.cc", "c_src/lets_impl_drv.cc"], 14 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -I c_src/leveldb/include"} 15 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/leveldb/lib/libleveldb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 16 | ]}]} 17 | , {".*", "priv/lib/lets_impl_nif.so", ["c_src/lets_impl_nif_lib.cc", "c_src/lets_impl_nif.cc"], 18 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -I c_src/leveldb/include"} 19 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/leveldb/lib/libleveldb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 20 | ]}]} 21 | , {".*", "priv/lib/hets_impl_drv.so", ["c_src/hets_impl_drv_lib.cc", "c_src/hets_impl_drv.cc"], 22 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -I c_src/hyperleveldb/include"} 23 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/hyperleveldb/lib/libhyperleveldb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 24 | ]}]} 25 | , {".*", "priv/lib/hets_impl_nif.so", ["c_src/hets_impl_nif_lib.cc", "c_src/hets_impl_nif.cc"], 26 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -I c_src/hyperleveldb/include"} 27 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/hyperleveldb/lib/libhyperleveldb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 28 | ]}]} 29 | , {".*", "priv/lib/rets_impl_drv.so", ["c_src/rets_impl_drv_lib.cc", "c_src/rets_impl_drv.cc"], 30 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -DROCKSDB -std=c++11 -I c_src/rocksdb/include"} 31 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/rocksdb/lib/librocksdb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 32 | ]}]} 33 | , {".*", "priv/lib/rets_impl_nif.so", ["c_src/rets_impl_nif_lib.cc", "c_src/rets_impl_nif.cc"], 34 | [{env, [{"DRV_CFLAGS", "$DRV_CFLAGS -DROCKSDB -std=c++11 -I c_src/rocksdb/include"} 35 | , {"DRV_LDFLAGS", "$DRV_LDFLAGS c_src/rocksdb/lib/librocksdb.a c_src/snappy/lib/libsnappy.a -lstdc++"} 36 | ]}]} 37 | ]}. 38 | 39 | {erl_opts, [warnings_as_errors, warn_shadow_vars, warn_obsolete_guard]}. 40 | 41 | {xref_checks, [undefined_function_calls, undefined_functions, 42 | deprecated_function_calls, deprecated_functions]}. 43 | 44 | {qc_opts, [{qc_mod, qc}]}. 45 | 46 | {deps, [{qc, "", {git, "git://github.com/norton/qc.git", {branch, "master"}}} 47 | , {gen_ets, "", {git, "git://github.com/norton/gen-ets.git", {branch, "master"}}} 48 | , {snappy, "", {git, "git://github.com/norton/snappy.git", {branch, "master"}}, [raw]} 49 | , {leveldb, "", {git, "git://github.com/norton/leveldb.git", {branch, "master"}}, [raw]} 50 | , {hyperleveldb, "", {git, "git://github.com/norton/HyperLevelDB.git", {branch, "master"}}, [raw]} 51 | , {rocksdb, "", {git, "git://github.com/norton/rocksdb.git", {branch, "master"}}, [raw]} 52 | , {sext, "", {git, "git://github.com/norton/sext.git", {branch, "master"}}} 53 | , {edown, "", {git, "git://github.com/norton/edown.git", {branch, "master"}}} 54 | ]}. 55 | -------------------------------------------------------------------------------- /rebar.config.doc: -------------------------------------------------------------------------------- 1 | %%% -*- mode: erlang -*- 2 | 3 | {edoc_opts, [{doclet, asciiedown_doclet} 4 | , {app_default, "http://www.erlang.org/doc/man"} 5 | , {new, true} 6 | , {packages, false} 7 | , {stylesheet, ""} % don't copy stylesheet.css 8 | , {image, ""} % don't copy erlang.png 9 | , {top_level_readme, {"./README.md", "https://github.com/norton/lets", "master"}} 10 | ]}. 11 | 12 | {deps, [{meck, "", {git, "git://github.com/norton/meck.git"}} 13 | , {edown, "", {git, "git://github.com/norton/edown.git"}} 14 | , {asciiedoc, "", {git, "git://github.com/norton/asciiedoc.git"}} 15 | ]}. 16 | -------------------------------------------------------------------------------- /src/hets_impl_nif.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(hets_impl_nif). 24 | -behaviour(gen_ets_ns). 25 | 26 | -include("lets.hrl"). 27 | 28 | %% External exports 29 | -export([open/2 30 | , destroy/2 31 | , repair/2 32 | , delete/1 33 | , delete/2 34 | , delete_all_objects/1 35 | , first/1 36 | , first_iter/1 37 | , info_memory/1 38 | , info_size/1 39 | , insert/2 40 | , insert_new/2 41 | , last/1 42 | , last_iter/1 43 | , lookup/2 44 | , lookup_element/3 45 | , member/2 46 | , next/2 47 | , next_iter/2 48 | , prev/2 49 | , prev_iter/2 50 | , notify/4 51 | , first/2 52 | , first_iter/2 53 | , last/2 54 | , last_iter/2 55 | , next/3 56 | , next_iter/3 57 | , prev/3 58 | , prev_iter/3 59 | ]). 60 | 61 | -export_type([tid/0, opts/0, key/0, pos/0, object/0]). 62 | 63 | -on_load(init/0). 64 | 65 | %%%---------------------------------------------------------------------- 66 | %%% Types/Specs/Records 67 | %%%---------------------------------------------------------------------- 68 | 69 | -type tid() :: lets:lets_tid(). 70 | -type opts() :: lets:opts(). 71 | -type key() :: lets:key(). 72 | -type pos() :: lets:pos(). 73 | -type object() :: lets:object(). 74 | 75 | -define(NIF_STUB, nif_stub_error(?LINE)). 76 | 77 | %%%---------------------------------------------------------------------- 78 | %%% API 79 | %%%---------------------------------------------------------------------- 80 | 81 | %% @see lets:new/2 82 | -spec open(tid(), opts()) -> tid(). 83 | open(Tid, Opts) -> 84 | Tid#gen_tid{impl=create(fun impl_open/6, Tid, Opts)}. 85 | 86 | %% @see lets:destroy/2 87 | -spec destroy(tid(), opts()) -> true. 88 | destroy(Tid, Opts) -> 89 | create(fun impl_destroy/6, Tid, Opts). 90 | 91 | %% @see lets:repair/2 92 | -spec repair(tid(), opts()) -> true. 93 | repair(Tid, Opts) -> 94 | create(fun impl_repair/6, Tid, Opts). 95 | 96 | %% @see lets:delete/1 97 | -spec delete(tid()) -> true. 98 | delete(#gen_tid{impl=Impl, impl_opts=Opts}) -> 99 | impl_delete(Impl, opts(db_write, Opts)). 100 | 101 | %% @see lets:delete/2 102 | -spec delete(tid(), key()) -> true. 103 | delete(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 104 | impl_delete(Impl, opts(db_write, Opts), encode(Type, Key)). 105 | 106 | %% @see lets:delete_all_objects/1 107 | -spec delete_all_objects(tid()) -> true. 108 | delete_all_objects(#gen_tid{impl=Impl, impl_opts=Opts}) -> 109 | impl_delete_all_objects(Impl, opts(db_write, Opts)). 110 | 111 | %% @see lets:first/1 112 | -spec first(tid()) -> key() | '$end_of_table'. 113 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 114 | decode(Type, impl_first(Impl, opts(db_read, Opts), undefined)). 115 | 116 | %% @see lets:first/1 117 | -spec first_iter(tid()) -> object() | '$end_of_table'. 118 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 119 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), undefined)). 120 | 121 | %% @see lets:last/1 122 | -spec last(tid()) -> key() | '$end_of_table'. 123 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 124 | decode(Type, impl_last(Impl, opts(db_read, Opts), undefined)). 125 | 126 | %% @see lets:last/1 127 | -spec last_iter(tid()) -> object() | '$end_of_table'. 128 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 129 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), undefined)). 130 | 131 | %% @see lets:info/1 132 | -spec info_memory(tid()) -> non_neg_integer(). 133 | info_memory(#gen_tid{impl=Impl}) -> 134 | case impl_info_memory(Impl) of 135 | Memory when is_integer(Memory) -> 136 | erlang:round(Memory / erlang:system_info(wordsize)); 137 | Else -> 138 | Else 139 | end. 140 | 141 | %% @see lets:info/1 142 | -spec info_size(tid()) -> non_neg_integer(). 143 | info_size(#gen_tid{impl=Impl}) -> 144 | impl_info_size(Impl). 145 | 146 | %% @see lets:insert/2 147 | -spec insert(tid(), object() | [object()]) -> true. 148 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 149 | Key = element(KeyPos, Object), 150 | Val = Object, 151 | impl_insert(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 152 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 153 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 154 | impl_insert(Impl, opts(db_write, Opts), List). 155 | 156 | %% @see lets:insert_new/2 157 | -spec insert_new(tid(), object() | [object()]) -> true. 158 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 159 | Key = element(KeyPos, Object), 160 | Val = Object, 161 | impl_insert_new(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 162 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 163 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 164 | impl_insert_new(Impl, opts(db_write, Opts), List). 165 | 166 | %% @see lets:lookup/2 167 | -spec lookup(tid(), key()) -> [object()]. 168 | lookup(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 169 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 170 | '$end_of_table' -> 171 | []; 172 | Object when is_binary(Object) -> 173 | [decode(Type, Object)] 174 | end. 175 | 176 | %% @see lets:lookup_element/3 177 | -spec lookup_element(tid(), key(), pos()) -> term(). 178 | lookup_element(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, Pos) -> 179 | Element = 180 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 181 | '$end_of_table' -> 182 | '$end_of_table'; 183 | Object when is_binary(Object) -> 184 | decode(Type, Object) 185 | end, 186 | element(Pos, Element). 187 | 188 | %% @see lets:member/2 189 | -spec member(tid(), key()) -> true | false. 190 | member(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 191 | impl_member(Impl, opts(db_read, Opts), encode(Type, Key)). 192 | 193 | %% @see lets:next/2 194 | -spec next(#gen_tid{}, key()) -> key() | '$end_of_table'. 195 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 196 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 197 | 198 | %% @see lets:next/2 199 | -spec next_iter(tid(), key()) -> object() | '$end_of_table'. 200 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 201 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 202 | 203 | %% @see lets:prev/2 204 | -spec prev(#gen_tid{}, key()) -> key() | '$end_of_table'. 205 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 206 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 207 | 208 | %% @see lets:prev/2 209 | -spec prev_iter(tid(), key()) -> object() | '$end_of_table'. 210 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 211 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 212 | 213 | %% @doc Register the specified process to be sent the specified 214 | %% message when the table is destroyed and return true. Otherwise, 215 | %% return false. 216 | -spec notify(tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false. 217 | notify(#gen_tid{impl=Impl}, Event, Pid, Msg) -> 218 | impl_notify(Impl, Event, Pid, Msg). 219 | 220 | 221 | %% @see lets:first/1 222 | -spec first(tid(), pos_integer()) -> [key()] | '$end_of_table'. 223 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 224 | decode(Type, impl_first(Impl, opts(db_read, Opts), N)). 225 | 226 | %% @see lets:first/1 227 | -spec first_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 228 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 229 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), N)). 230 | 231 | %% @see lets:last/1 232 | -spec last(tid(), pos_integer()) -> [key()] | '$end_of_table'. 233 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 234 | decode(Type, impl_last(Impl, opts(db_read, Opts), N)). 235 | 236 | %% @see lets:last/1 237 | -spec last_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 238 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 239 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), N)). 240 | 241 | %% @see lets:next/2 242 | -spec next(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 243 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 244 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), N)). 245 | 246 | %% @see lets:next/2 247 | -spec next_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 248 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 249 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 250 | 251 | %% @see lets:prev/2 252 | -spec prev(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 253 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 254 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), N)). 255 | 256 | %% @see lets:prev/2 257 | -spec prev_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 258 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 259 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 260 | 261 | %%%---------------------------------------------------------------------- 262 | %%% Internal functions 263 | %%%---------------------------------------------------------------------- 264 | 265 | init() -> 266 | Path = 267 | case code:priv_dir(lets) of 268 | {error, bad_name} -> 269 | "../priv/lib"; 270 | Dir -> 271 | filename:join([Dir, "lib"]) 272 | end, 273 | erlang:load_nif(filename:join(Path, ?MODULE_STRING), 0). 274 | 275 | create(Fun, #gen_tid{type=Type, protection=Protection}, Opts) -> 276 | DbOpts = opts(db, Opts), 277 | ReadOpts = opts(db_read, Opts), 278 | WriteOpts = opts(db_write, Opts), 279 | {value, {path,Path}, NewDbOpts} = lists:keytake(path, 1, DbOpts), 280 | Fun(Type, Protection, Path, NewDbOpts, ReadOpts, WriteOpts). 281 | 282 | opts(_Opt, undefined) -> 283 | undefined; 284 | opts(Key, Opts) -> 285 | proplists:get_value(Key, Opts, []). 286 | 287 | encode(set, Term) -> 288 | term_to_binary(Term); 289 | encode(ordered_set, Term) -> 290 | sext:encode(Term). 291 | 292 | decode(_, '$end_of_table') -> 293 | '$end_of_table'; 294 | decode(set, List) when is_list(List) -> 295 | [ binary_to_term(Term) || Term <- List ]; 296 | decode(ordered_set, List) when is_list(List) -> 297 | [ sext:decode(Term) || Term <- List ]; 298 | decode(set, Term) -> 299 | binary_to_term(Term); 300 | decode(ordered_set, Term) -> 301 | sext:decode(Term). 302 | 303 | nif_stub_error(Line) -> 304 | erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). 305 | 306 | impl_open(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 307 | ?NIF_STUB. 308 | 309 | impl_destroy(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 310 | ?NIF_STUB. 311 | 312 | impl_repair(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 313 | ?NIF_STUB. 314 | 315 | impl_delete(_Impl, _Opts) -> 316 | ?NIF_STUB. 317 | 318 | impl_delete(_Impl, _Opts, _Key) -> 319 | ?NIF_STUB. 320 | 321 | impl_delete_all_objects(_Impl, _Opts) -> 322 | ?NIF_STUB. 323 | 324 | impl_first(_Impl, _Opts, _N) -> 325 | ?NIF_STUB. 326 | 327 | impl_first_iter(_Impl, _Opts, _N) -> 328 | ?NIF_STUB. 329 | 330 | impl_last(_Impl, _Opts, _N) -> 331 | ?NIF_STUB. 332 | 333 | impl_last_iter(_Impl, _Opts, _N) -> 334 | ?NIF_STUB. 335 | 336 | impl_info_memory(_Impl) -> 337 | ?NIF_STUB. 338 | 339 | impl_info_size(_Impl) -> 340 | ?NIF_STUB. 341 | 342 | impl_insert(_Impl, _Opts, _Key, _Object) -> 343 | ?NIF_STUB. 344 | 345 | impl_insert(_Impl, _Opts, _List) -> 346 | ?NIF_STUB. 347 | 348 | impl_insert_new(_Impl, _Opts, _Key, _Object) -> 349 | ?NIF_STUB. 350 | 351 | impl_insert_new(_Impl, _Opts, _List) -> 352 | ?NIF_STUB. 353 | 354 | impl_lookup(_Impl, _Opts, _Key) -> 355 | ?NIF_STUB. 356 | 357 | impl_member(_Impl, _Opts, _Key) -> 358 | ?NIF_STUB. 359 | 360 | impl_next(_Impl, _Opts, _Key, _N) -> 361 | ?NIF_STUB. 362 | 363 | impl_next_iter(_Impl, _Opts, _Key, _N) -> 364 | ?NIF_STUB. 365 | 366 | impl_prev(_Impl, _Opts, _Key, _N) -> 367 | ?NIF_STUB. 368 | 369 | impl_prev_iter(_Impl, _Opts, _Key, _N) -> 370 | ?NIF_STUB. 371 | 372 | impl_notify(_Impl, _Event, _Pid, _Msg) -> 373 | ?NIF_STUB. 374 | -------------------------------------------------------------------------------- /src/lets.app.src: -------------------------------------------------------------------------------- 1 | %%% -*- mode: erlang -*- 2 | 3 | %%% The MIT License 4 | %%% 5 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 6 | %%% 7 | %%% Permission is hereby granted, free of charge, to any person obtaining a copy 8 | %%% of this software and associated documentation files (the "Software"), to deal 9 | %%% in the Software without restriction, including without limitation the rights 10 | %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | %%% copies of the Software, and to permit persons to whom the Software is 12 | %%% furnished to do so, subject to the following conditions: 13 | %%% 14 | %%% The above copyright notice and this permission notice shall be included in 15 | %%% all copies or substantial portions of the Software. 16 | %%% 17 | %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | %%% THE SOFTWARE. 24 | 25 | {application, lets, 26 | [ 27 | {description, "LevelDB ETS"}, 28 | {vsn, git}, 29 | {registered, []}, 30 | {applications, [kernel, stdlib, sasl]}, 31 | {modules, [lets, lets_impl_drv, lets_impl_nif, hets_impl_drv, hets_impl_nif]} 32 | ] 33 | }. 34 | -------------------------------------------------------------------------------- /src/lets.hrl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -ifndef(lets). 24 | -define(lets, true). 25 | 26 | -include_lib("gen_ets/include/gen_ets.hrl"). 27 | 28 | -endif. % -ifndef(lets). 29 | -------------------------------------------------------------------------------- /src/lets_impl_nif.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(lets_impl_nif). 24 | -behaviour(gen_ets_ns). 25 | 26 | -include("lets.hrl"). 27 | 28 | %% External exports 29 | -export([open/2 30 | , destroy/2 31 | , repair/2 32 | , delete/1 33 | , delete/2 34 | , delete_all_objects/1 35 | , first/1 36 | , first_iter/1 37 | , info_memory/1 38 | , info_size/1 39 | , insert/2 40 | , insert_new/2 41 | , last/1 42 | , last_iter/1 43 | , lookup/2 44 | , lookup_element/3 45 | , member/2 46 | , next/2 47 | , next_iter/2 48 | , prev/2 49 | , prev_iter/2 50 | , notify/4 51 | , first/2 52 | , first_iter/2 53 | , last/2 54 | , last_iter/2 55 | , next/3 56 | , next_iter/3 57 | , prev/3 58 | , prev_iter/3 59 | ]). 60 | 61 | -export_type([tid/0, opts/0, key/0, pos/0, object/0]). 62 | 63 | -on_load(init/0). 64 | 65 | %%%---------------------------------------------------------------------- 66 | %%% Types/Specs/Records 67 | %%%---------------------------------------------------------------------- 68 | 69 | -type tid() :: lets:lets_tid(). 70 | -type opts() :: lets:opts(). 71 | -type key() :: lets:key(). 72 | -type pos() :: lets:pos(). 73 | -type object() :: lets:object(). 74 | 75 | -define(NIF_STUB, nif_stub_error(?LINE)). 76 | 77 | %%%---------------------------------------------------------------------- 78 | %%% API 79 | %%%---------------------------------------------------------------------- 80 | 81 | %% @see lets:new/2 82 | -spec open(tid(), opts()) -> tid(). 83 | open(Tid, Opts) -> 84 | Tid#gen_tid{impl=create(fun impl_open/6, Tid, Opts)}. 85 | 86 | %% @see lets:destroy/2 87 | -spec destroy(tid(), opts()) -> true. 88 | destroy(Tid, Opts) -> 89 | create(fun impl_destroy/6, Tid, Opts). 90 | 91 | %% @see lets:repair/2 92 | -spec repair(tid(), opts()) -> true. 93 | repair(Tid, Opts) -> 94 | create(fun impl_repair/6, Tid, Opts). 95 | 96 | %% @see lets:delete/1 97 | -spec delete(tid()) -> true. 98 | delete(#gen_tid{impl=Impl, impl_opts=Opts}) -> 99 | impl_delete(Impl, opts(db_write, Opts)). 100 | 101 | %% @see lets:delete/2 102 | -spec delete(tid(), key()) -> true. 103 | delete(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 104 | impl_delete(Impl, opts(db_write, Opts), encode(Type, Key)). 105 | 106 | %% @see lets:delete_all_objects/1 107 | -spec delete_all_objects(tid()) -> true. 108 | delete_all_objects(#gen_tid{impl=Impl, impl_opts=Opts}) -> 109 | impl_delete_all_objects(Impl, opts(db_write, Opts)). 110 | 111 | %% @see lets:first/1 112 | -spec first(tid()) -> key() | '$end_of_table'. 113 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 114 | decode(Type, impl_first(Impl, opts(db_read, Opts), undefined)). 115 | 116 | %% @see lets:first/1 117 | -spec first_iter(tid()) -> object() | '$end_of_table'. 118 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 119 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), undefined)). 120 | 121 | %% @see lets:last/1 122 | -spec last(tid()) -> key() | '$end_of_table'. 123 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 124 | decode(Type, impl_last(Impl, opts(db_read, Opts), undefined)). 125 | 126 | %% @see lets:last/1 127 | -spec last_iter(tid()) -> object() | '$end_of_table'. 128 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 129 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), undefined)). 130 | 131 | %% @see lets:info/1 132 | -spec info_memory(tid()) -> non_neg_integer(). 133 | info_memory(#gen_tid{impl=Impl}) -> 134 | case impl_info_memory(Impl) of 135 | Memory when is_integer(Memory) -> 136 | erlang:round(Memory / erlang:system_info(wordsize)); 137 | Else -> 138 | Else 139 | end. 140 | 141 | %% @see lets:info/1 142 | -spec info_size(tid()) -> non_neg_integer(). 143 | info_size(#gen_tid{impl=Impl}) -> 144 | impl_info_size(Impl). 145 | 146 | %% @see lets:insert/2 147 | -spec insert(tid(), object() | [object()]) -> true. 148 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 149 | Key = element(KeyPos, Object), 150 | Val = Object, 151 | impl_insert(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 152 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 153 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 154 | impl_insert(Impl, opts(db_write, Opts), List). 155 | 156 | %% @see lets:insert_new/2 157 | -spec insert_new(tid(), object() | [object()]) -> true. 158 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 159 | Key = element(KeyPos, Object), 160 | Val = Object, 161 | impl_insert_new(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 162 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 163 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 164 | impl_insert_new(Impl, opts(db_write, Opts), List). 165 | 166 | %% @see lets:lookup/2 167 | -spec lookup(tid(), key()) -> [object()]. 168 | lookup(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 169 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 170 | '$end_of_table' -> 171 | []; 172 | Object when is_binary(Object) -> 173 | [decode(Type, Object)] 174 | end. 175 | 176 | %% @see lets:lookup_element/3 177 | -spec lookup_element(tid(), key(), pos()) -> term(). 178 | lookup_element(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, Pos) -> 179 | Element = 180 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 181 | '$end_of_table' -> 182 | '$end_of_table'; 183 | Object when is_binary(Object) -> 184 | decode(Type, Object) 185 | end, 186 | element(Pos, Element). 187 | 188 | %% @see lets:member/2 189 | -spec member(tid(), key()) -> true | false. 190 | member(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 191 | impl_member(Impl, opts(db_read, Opts), encode(Type, Key)). 192 | 193 | %% @see lets:next/2 194 | -spec next(#gen_tid{}, key()) -> key() | '$end_of_table'. 195 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 196 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 197 | 198 | %% @see lets:next/2 199 | -spec next_iter(tid(), key()) -> object() | '$end_of_table'. 200 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 201 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 202 | 203 | %% @see lets:prev/2 204 | -spec prev(#gen_tid{}, key()) -> key() | '$end_of_table'. 205 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 206 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 207 | 208 | %% @see lets:prev/2 209 | -spec prev_iter(tid(), key()) -> object() | '$end_of_table'. 210 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 211 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 212 | 213 | %% @doc Register the specified process to be sent the specified 214 | %% message when the table is destroyed and return true. Otherwise, 215 | %% return false. 216 | -spec notify(tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false. 217 | notify(#gen_tid{impl=Impl}, Event, Pid, Msg) -> 218 | impl_notify(Impl, Event, Pid, Msg). 219 | 220 | 221 | %% @see lets:first/1 222 | -spec first(tid(), pos_integer()) -> [key()] | '$end_of_table'. 223 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 224 | decode(Type, impl_first(Impl, opts(db_read, Opts), N)). 225 | 226 | %% @see lets:first/1 227 | -spec first_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 228 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 229 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), N)). 230 | 231 | %% @see lets:last/1 232 | -spec last(tid(), pos_integer()) -> [key()] | '$end_of_table'. 233 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 234 | decode(Type, impl_last(Impl, opts(db_read, Opts), N)). 235 | 236 | %% @see lets:last/1 237 | -spec last_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 238 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 239 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), N)). 240 | 241 | %% @see lets:next/2 242 | -spec next(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 243 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 244 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), N)). 245 | 246 | %% @see lets:next/2 247 | -spec next_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 248 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 249 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 250 | 251 | %% @see lets:prev/2 252 | -spec prev(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 253 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 254 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), N)). 255 | 256 | %% @see lets:prev/2 257 | -spec prev_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 258 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 259 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 260 | 261 | %%%---------------------------------------------------------------------- 262 | %%% Internal functions 263 | %%%---------------------------------------------------------------------- 264 | 265 | init() -> 266 | Path = 267 | case code:priv_dir(lets) of 268 | {error, bad_name} -> 269 | "../priv/lib"; 270 | Dir -> 271 | filename:join([Dir, "lib"]) 272 | end, 273 | erlang:load_nif(filename:join(Path, ?MODULE_STRING), 0). 274 | 275 | create(Fun, #gen_tid{type=Type, protection=Protection}, Opts) -> 276 | DbOpts = opts(db, Opts), 277 | ReadOpts = opts(db_read, Opts), 278 | WriteOpts = opts(db_write, Opts), 279 | {value, {path,Path}, NewDbOpts} = lists:keytake(path, 1, DbOpts), 280 | Fun(Type, Protection, Path, NewDbOpts, ReadOpts, WriteOpts). 281 | 282 | opts(_Opt, undefined) -> 283 | undefined; 284 | opts(Key, Opts) -> 285 | proplists:get_value(Key, Opts, []). 286 | 287 | encode(set, Term) -> 288 | term_to_binary(Term); 289 | encode(ordered_set, Term) -> 290 | sext:encode(Term). 291 | 292 | decode(_, '$end_of_table') -> 293 | '$end_of_table'; 294 | decode(set, List) when is_list(List) -> 295 | [ binary_to_term(Term) || Term <- List ]; 296 | decode(ordered_set, List) when is_list(List) -> 297 | [ sext:decode(Term) || Term <- List ]; 298 | decode(set, Term) -> 299 | binary_to_term(Term); 300 | decode(ordered_set, Term) -> 301 | sext:decode(Term). 302 | 303 | nif_stub_error(Line) -> 304 | erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). 305 | 306 | impl_open(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 307 | ?NIF_STUB. 308 | 309 | impl_destroy(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 310 | ?NIF_STUB. 311 | 312 | impl_repair(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 313 | ?NIF_STUB. 314 | 315 | impl_delete(_Impl, _Opts) -> 316 | ?NIF_STUB. 317 | 318 | impl_delete(_Impl, _Opts, _Key) -> 319 | ?NIF_STUB. 320 | 321 | impl_delete_all_objects(_Impl, _Opts) -> 322 | ?NIF_STUB. 323 | 324 | impl_first(_Impl, _Opts, _N) -> 325 | ?NIF_STUB. 326 | 327 | impl_first_iter(_Impl, _Opts, _N) -> 328 | ?NIF_STUB. 329 | 330 | impl_last(_Impl, _Opts, _N) -> 331 | ?NIF_STUB. 332 | 333 | impl_last_iter(_Impl, _Opts, _N) -> 334 | ?NIF_STUB. 335 | 336 | impl_info_memory(_Impl) -> 337 | ?NIF_STUB. 338 | 339 | impl_info_size(_Impl) -> 340 | ?NIF_STUB. 341 | 342 | impl_insert(_Impl, _Opts, _Key, _Object) -> 343 | ?NIF_STUB. 344 | 345 | impl_insert(_Impl, _Opts, _List) -> 346 | ?NIF_STUB. 347 | 348 | impl_insert_new(_Impl, _Opts, _Key, _Object) -> 349 | ?NIF_STUB. 350 | 351 | impl_insert_new(_Impl, _Opts, _List) -> 352 | ?NIF_STUB. 353 | 354 | impl_lookup(_Impl, _Opts, _Key) -> 355 | ?NIF_STUB. 356 | 357 | impl_member(_Impl, _Opts, _Key) -> 358 | ?NIF_STUB. 359 | 360 | impl_next(_Impl, _Opts, _Key, _N) -> 361 | ?NIF_STUB. 362 | 363 | impl_next_iter(_Impl, _Opts, _Key, _N) -> 364 | ?NIF_STUB. 365 | 366 | impl_prev(_Impl, _Opts, _Key, _N) -> 367 | ?NIF_STUB. 368 | 369 | impl_prev_iter(_Impl, _Opts, _Key, _N) -> 370 | ?NIF_STUB. 371 | 372 | impl_notify(_Impl, _Event, _Pid, _Msg) -> 373 | ?NIF_STUB. 374 | -------------------------------------------------------------------------------- /src/rets_impl_nif.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(rets_impl_nif). 24 | -behaviour(gen_ets_ns). 25 | 26 | -include("lets.hrl"). 27 | 28 | %% External exports 29 | -export([open/2 30 | , destroy/2 31 | , repair/2 32 | , delete/1 33 | , delete/2 34 | , delete_all_objects/1 35 | , first/1 36 | , first_iter/1 37 | , info_memory/1 38 | , info_size/1 39 | , insert/2 40 | , insert_new/2 41 | , last/1 42 | , last_iter/1 43 | , lookup/2 44 | , lookup_element/3 45 | , member/2 46 | , next/2 47 | , next_iter/2 48 | , prev/2 49 | , prev_iter/2 50 | , notify/4 51 | , first/2 52 | , first_iter/2 53 | , last/2 54 | , last_iter/2 55 | , next/3 56 | , next_iter/3 57 | , prev/3 58 | , prev_iter/3 59 | ]). 60 | 61 | -export_type([tid/0, opts/0, key/0, pos/0, object/0]). 62 | 63 | -on_load(init/0). 64 | 65 | %%%---------------------------------------------------------------------- 66 | %%% Types/Specs/Records 67 | %%%---------------------------------------------------------------------- 68 | 69 | -type tid() :: lets:lets_tid(). 70 | -type opts() :: lets:opts(). 71 | -type key() :: lets:key(). 72 | -type pos() :: lets:pos(). 73 | -type object() :: lets:object(). 74 | 75 | -define(NIF_STUB, nif_stub_error(?LINE)). 76 | 77 | %%%---------------------------------------------------------------------- 78 | %%% API 79 | %%%---------------------------------------------------------------------- 80 | 81 | %% @see lets:new/2 82 | -spec open(tid(), opts()) -> tid(). 83 | open(Tid, Opts) -> 84 | Tid#gen_tid{impl=create(fun impl_open/6, Tid, Opts)}. 85 | 86 | %% @see lets:destroy/2 87 | -spec destroy(tid(), opts()) -> true. 88 | destroy(Tid, Opts) -> 89 | create(fun impl_destroy/6, Tid, Opts). 90 | 91 | %% @see lets:repair/2 92 | -spec repair(tid(), opts()) -> true. 93 | repair(Tid, Opts) -> 94 | create(fun impl_repair/6, Tid, Opts). 95 | 96 | %% @see lets:delete/1 97 | -spec delete(tid()) -> true. 98 | delete(#gen_tid{impl=Impl, impl_opts=Opts}) -> 99 | impl_delete(Impl, opts(db_write, Opts)). 100 | 101 | %% @see lets:delete/2 102 | -spec delete(tid(), key()) -> true. 103 | delete(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 104 | impl_delete(Impl, opts(db_write, Opts), encode(Type, Key)). 105 | 106 | %% @see lets:delete_all_objects/1 107 | -spec delete_all_objects(tid()) -> true. 108 | delete_all_objects(#gen_tid{impl=Impl, impl_opts=Opts}) -> 109 | impl_delete_all_objects(Impl, opts(db_write, Opts)). 110 | 111 | %% @see lets:first/1 112 | -spec first(tid()) -> key() | '$end_of_table'. 113 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 114 | decode(Type, impl_first(Impl, opts(db_read, Opts), undefined)). 115 | 116 | %% @see lets:first/1 117 | -spec first_iter(tid()) -> object() | '$end_of_table'. 118 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 119 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), undefined)). 120 | 121 | %% @see lets:last/1 122 | -spec last(tid()) -> key() | '$end_of_table'. 123 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 124 | decode(Type, impl_last(Impl, opts(db_read, Opts), undefined)). 125 | 126 | %% @see lets:last/1 127 | -spec last_iter(tid()) -> object() | '$end_of_table'. 128 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}) -> 129 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), undefined)). 130 | 131 | %% @see lets:info/1 132 | -spec info_memory(tid()) -> non_neg_integer(). 133 | info_memory(#gen_tid{impl=Impl}) -> 134 | case impl_info_memory(Impl) of 135 | Memory when is_integer(Memory) -> 136 | erlang:round(Memory / erlang:system_info(wordsize)); 137 | Else -> 138 | Else 139 | end. 140 | 141 | %% @see lets:info/1 142 | -spec info_size(tid()) -> non_neg_integer(). 143 | info_size(#gen_tid{impl=Impl}) -> 144 | impl_info_size(Impl). 145 | 146 | %% @see lets:insert/2 147 | -spec insert(tid(), object() | [object()]) -> true. 148 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 149 | Key = element(KeyPos, Object), 150 | Val = Object, 151 | impl_insert(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 152 | insert(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 153 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 154 | impl_insert(Impl, opts(db_write, Opts), List). 155 | 156 | %% @see lets:insert_new/2 157 | -spec insert_new(tid(), object() | [object()]) -> true. 158 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Object) when is_tuple(Object) -> 159 | Key = element(KeyPos, Object), 160 | Val = Object, 161 | impl_insert_new(Impl, opts(db_write, Opts), encode(Type, Key), encode(Type, Val)); 162 | insert_new(#gen_tid{keypos=KeyPos, type=Type, impl=Impl, impl_opts=Opts}, Objects) when is_list(Objects) -> 163 | List = [{encode(Type, element(KeyPos, Object)), encode(Type, Object)} || Object <- Objects ], 164 | impl_insert_new(Impl, opts(db_write, Opts), List). 165 | 166 | %% @see lets:lookup/2 167 | -spec lookup(tid(), key()) -> [object()]. 168 | lookup(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 169 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 170 | '$end_of_table' -> 171 | []; 172 | Object when is_binary(Object) -> 173 | [decode(Type, Object)] 174 | end. 175 | 176 | %% @see lets:lookup_element/3 177 | -spec lookup_element(tid(), key(), pos()) -> term(). 178 | lookup_element(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, Pos) -> 179 | Element = 180 | case impl_lookup(Impl, opts(db_read, Opts), encode(Type, Key)) of 181 | '$end_of_table' -> 182 | '$end_of_table'; 183 | Object when is_binary(Object) -> 184 | decode(Type, Object) 185 | end, 186 | element(Pos, Element). 187 | 188 | %% @see lets:member/2 189 | -spec member(tid(), key()) -> true | false. 190 | member(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 191 | impl_member(Impl, opts(db_read, Opts), encode(Type, Key)). 192 | 193 | %% @see lets:next/2 194 | -spec next(#gen_tid{}, key()) -> key() | '$end_of_table'. 195 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 196 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 197 | 198 | %% @see lets:next/2 199 | -spec next_iter(tid(), key()) -> object() | '$end_of_table'. 200 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 201 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 202 | 203 | %% @see lets:prev/2 204 | -spec prev(#gen_tid{}, key()) -> key() | '$end_of_table'. 205 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 206 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 207 | 208 | %% @see lets:prev/2 209 | -spec prev_iter(tid(), key()) -> object() | '$end_of_table'. 210 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key) -> 211 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), undefined)). 212 | 213 | %% @doc Register the specified process to be sent the specified 214 | %% message when the table is destroyed and return true. Otherwise, 215 | %% return false. 216 | -spec notify(tid(), Event::when_destroyed, Pid::pid(), Msg::term()) -> true | false. 217 | notify(#gen_tid{impl=Impl}, Event, Pid, Msg) -> 218 | impl_notify(Impl, Event, Pid, Msg). 219 | 220 | 221 | %% @see lets:first/1 222 | -spec first(tid(), pos_integer()) -> [key()] | '$end_of_table'. 223 | first(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 224 | decode(Type, impl_first(Impl, opts(db_read, Opts), N)). 225 | 226 | %% @see lets:first/1 227 | -spec first_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 228 | first_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 229 | decode(Type, impl_first_iter(Impl, opts(db_read, Opts), N)). 230 | 231 | %% @see lets:last/1 232 | -spec last(tid(), pos_integer()) -> [key()] | '$end_of_table'. 233 | last(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 234 | decode(Type, impl_last(Impl, opts(db_read, Opts), N)). 235 | 236 | %% @see lets:last/1 237 | -spec last_iter(tid(), pos_integer()) -> [object()] | '$end_of_table'. 238 | last_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, N) -> 239 | decode(Type, impl_last_iter(Impl, opts(db_read, Opts), N)). 240 | 241 | %% @see lets:next/2 242 | -spec next(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 243 | next(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 244 | decode(Type, impl_next(Impl, opts(db_read, Opts), encode(Type, Key), N)). 245 | 246 | %% @see lets:next/2 247 | -spec next_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 248 | next_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 249 | decode(Type, impl_next_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 250 | 251 | %% @see lets:prev/2 252 | -spec prev(#gen_tid{}, key(), pos_integer()) -> [key()] | '$end_of_table'. 253 | prev(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 254 | decode(Type, impl_prev(Impl, opts(db_read, Opts), encode(Type, Key), N)). 255 | 256 | %% @see lets:prev/2 257 | -spec prev_iter(tid(), key(), pos_integer()) -> [object()] | '$end_of_table'. 258 | prev_iter(#gen_tid{type=Type, impl=Impl, impl_opts=Opts}, Key, N) -> 259 | decode(Type, impl_prev_iter(Impl, opts(db_read, Opts), encode(Type, Key), N)). 260 | 261 | %%%---------------------------------------------------------------------- 262 | %%% Internal functions 263 | %%%---------------------------------------------------------------------- 264 | 265 | init() -> 266 | Path = 267 | case code:priv_dir(lets) of 268 | {error, bad_name} -> 269 | "../priv/lib"; 270 | Dir -> 271 | filename:join([Dir, "lib"]) 272 | end, 273 | erlang:load_nif(filename:join(Path, ?MODULE_STRING), 0). 274 | 275 | create(Fun, #gen_tid{type=Type, protection=Protection}, Opts) -> 276 | DbOpts = opts(db, Opts), 277 | ReadOpts = opts(db_read, Opts), 278 | WriteOpts = opts(db_write, Opts), 279 | {value, {path,Path}, NewDbOpts} = lists:keytake(path, 1, DbOpts), 280 | Fun(Type, Protection, Path, NewDbOpts, ReadOpts, WriteOpts). 281 | 282 | opts(_Opt, undefined) -> 283 | undefined; 284 | opts(Key, Opts) -> 285 | proplists:get_value(Key, Opts, []). 286 | 287 | encode(set, Term) -> 288 | term_to_binary(Term); 289 | encode(ordered_set, Term) -> 290 | sext:encode(Term). 291 | 292 | decode(_, '$end_of_table') -> 293 | '$end_of_table'; 294 | decode(set, List) when is_list(List) -> 295 | [ binary_to_term(Term) || Term <- List ]; 296 | decode(ordered_set, List) when is_list(List) -> 297 | [ sext:decode(Term) || Term <- List ]; 298 | decode(set, Term) -> 299 | binary_to_term(Term); 300 | decode(ordered_set, Term) -> 301 | sext:decode(Term). 302 | 303 | nif_stub_error(Line) -> 304 | erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). 305 | 306 | impl_open(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 307 | ?NIF_STUB. 308 | 309 | impl_destroy(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 310 | ?NIF_STUB. 311 | 312 | impl_repair(_Type, _Protection, _Path, _Opts, _ReadOpts, _WriteOpts) -> 313 | ?NIF_STUB. 314 | 315 | impl_delete(_Impl, _Opts) -> 316 | ?NIF_STUB. 317 | 318 | impl_delete(_Impl, _Opts, _Key) -> 319 | ?NIF_STUB. 320 | 321 | impl_delete_all_objects(_Impl, _Opts) -> 322 | ?NIF_STUB. 323 | 324 | impl_first(_Impl, _Opts, _N) -> 325 | ?NIF_STUB. 326 | 327 | impl_first_iter(_Impl, _Opts, _N) -> 328 | ?NIF_STUB. 329 | 330 | impl_last(_Impl, _Opts, _N) -> 331 | ?NIF_STUB. 332 | 333 | impl_last_iter(_Impl, _Opts, _N) -> 334 | ?NIF_STUB. 335 | 336 | impl_info_memory(_Impl) -> 337 | ?NIF_STUB. 338 | 339 | impl_info_size(_Impl) -> 340 | ?NIF_STUB. 341 | 342 | impl_insert(_Impl, _Opts, _Key, _Object) -> 343 | ?NIF_STUB. 344 | 345 | impl_insert(_Impl, _Opts, _List) -> 346 | ?NIF_STUB. 347 | 348 | impl_insert_new(_Impl, _Opts, _Key, _Object) -> 349 | ?NIF_STUB. 350 | 351 | impl_insert_new(_Impl, _Opts, _List) -> 352 | ?NIF_STUB. 353 | 354 | impl_lookup(_Impl, _Opts, _Key) -> 355 | ?NIF_STUB. 356 | 357 | impl_member(_Impl, _Opts, _Key) -> 358 | ?NIF_STUB. 359 | 360 | impl_next(_Impl, _Opts, _Key, _N) -> 361 | ?NIF_STUB. 362 | 363 | impl_next_iter(_Impl, _Opts, _Key, _N) -> 364 | ?NIF_STUB. 365 | 366 | impl_prev(_Impl, _Opts, _Key, _N) -> 367 | ?NIF_STUB. 368 | 369 | impl_prev_iter(_Impl, _Opts, _Key, _N) -> 370 | ?NIF_STUB. 371 | 372 | impl_notify(_Impl, _Event, _Pid, _Msg) -> 373 | ?NIF_STUB. 374 | -------------------------------------------------------------------------------- /test/qc/qc_lets_raw.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(qc_lets_raw). 24 | 25 | -include("../../src/lets.hrl"). 26 | 27 | %% API 28 | -export([%% test 29 | teardown/1 30 | , is_table/1 31 | %% lets 32 | , all/1 33 | , tid/1 34 | , tid/2 35 | , new/2 36 | , new/3 37 | , destroy/3 38 | , repair/3 39 | , delete/1 40 | , delete/2 41 | , delete_all_objects/1 42 | , first/1 43 | , foldl/3 44 | , foldr/3 45 | , info/1 46 | , info/2 47 | , insert/2 48 | , insert_new/2 49 | , last/1 50 | , lookup/2 51 | , lookup_element/3 52 | , match/2 53 | , match/3 54 | , match/1 55 | , match_delete/2 56 | , match_object/2 57 | , match_object/3 58 | , match_object/1 59 | , member/2 60 | , next/2 61 | , prev/2 62 | , select/2 63 | , select/3 64 | , select/1 65 | , select_count/2 66 | , select_delete/2 67 | , select_reverse/2 68 | , select_reverse/3 69 | , select_reverse/1 70 | , tab2list/1 71 | ]). 72 | 73 | 74 | %%%=================================================================== 75 | %%% API 76 | %%%=================================================================== 77 | 78 | teardown(Name) -> 79 | %% @TODO make this more robust 80 | _ = [ true=lets:delete(Tab) || Tab <- lets:all() ], 81 | catch exit(whereis(Name), kill), 82 | _ = os:cmd("find . -name '" ++ ?MODULE_STRING ++ ".*' -exec rm -rf {} \;"), 83 | _ = os:cmd("rm -rf " ++ ?MODULE_STRING). 84 | 85 | is_table(Res) -> 86 | is_record(Res, gen_tid). 87 | 88 | all(_Tab) -> 89 | catch lets:all(). 90 | 91 | tid(Tab) -> 92 | catch lets:tid(Tab). 93 | 94 | tid(Tab, Options) -> 95 | catch lets:tid(Tab, Options). 96 | 97 | new(Name, Options) -> 98 | ok = filelib:ensure_dir(?MODULE_STRING), 99 | catch lets:new(Name, filter_options(Options)). 100 | 101 | new(_Tab, Name, Options) -> 102 | %% _Tab is to help control generators and shrinking 103 | new(Name, Options). 104 | 105 | destroy(_Tab, Name, Options) -> 106 | %% _Tab is to help control generators and shrinking 107 | catch lets:destroy(Name, filter_options(Options)). 108 | 109 | repair(_Tab, Name, Options) -> 110 | %% _Tab is to help control generators and shrinking 111 | catch lets:repair(Name, filter_options(Options)). 112 | 113 | delete(Tab) -> 114 | catch lets:delete(Tab). 115 | 116 | delete(Tab, Key) -> 117 | catch lets:delete(Tab, Key). 118 | 119 | delete_all_objects(Tab) -> 120 | catch lets:delete_all_objects(Tab). 121 | 122 | first(Tab) -> 123 | catch lets:first(Tab). 124 | 125 | foldl(Function, Acc0, Tab) -> 126 | catch lets:foldl(Function, Acc0, Tab). 127 | 128 | foldr(Function, Acc0, Tab) -> 129 | catch lets:foldr(Function, Acc0, Tab). 130 | 131 | info(Tab) -> 132 | catch lets:info(Tab). 133 | 134 | info(Tab, Item) -> 135 | catch lets:info(Tab, Item). 136 | 137 | insert(Tab, ObjOrObjs) -> 138 | catch lets:insert(Tab, ObjOrObjs). 139 | 140 | insert_new(Tab, ObjOrObjs) -> 141 | catch lets:insert_new(Tab, ObjOrObjs). 142 | 143 | last(Tab) -> 144 | catch lets:last(Tab). 145 | 146 | lookup(Tab, Key) -> 147 | catch lets:lookup(Tab, Key). 148 | 149 | lookup_element(Tab, Key, Pos) -> 150 | catch lets:lookup_element(Tab, Key, Pos). 151 | 152 | match(Tab, Pattern) -> 153 | catch lets:match(Tab, Pattern). 154 | 155 | match(Tab, Pattern, Limit) -> 156 | catch lets:match(Tab, Pattern, Limit). 157 | 158 | match(Cont) -> 159 | catch lets:match(Cont). 160 | 161 | match_delete(Tab, Pattern) -> 162 | catch lets:match_delete(Tab, Pattern). 163 | 164 | match_object(Tab, Pattern) -> 165 | catch lets:match_object(Tab, Pattern). 166 | 167 | match_object(Tab, Pattern, Limit) -> 168 | catch lets:match_object(Tab, Pattern, Limit). 169 | 170 | match_object(Cont) -> 171 | catch lets:match_object(Cont). 172 | 173 | member(Tab, Key) -> 174 | catch lets:member(Tab, Key). 175 | 176 | next(Tab, Key) -> 177 | catch lets:next(Tab, Key). 178 | 179 | prev(Tab, Key) -> 180 | catch lets:prev(Tab, Key). 181 | 182 | select(Tab, Spec) -> 183 | catch lets:select(Tab, Spec). 184 | 185 | select(Tab, Spec, Limit) -> 186 | catch lets:select(Tab, Spec, Limit). 187 | 188 | select(Cont) -> 189 | catch lets:select(Cont). 190 | 191 | select_count(Tab, Spec) -> 192 | catch lets:select_count(Tab, Spec). 193 | 194 | select_delete(Tab, Spec) -> 195 | catch lets:select_delete(Tab, Spec). 196 | 197 | select_reverse(Tab, Spec) -> 198 | catch lets:select_reverse(Tab, Spec). 199 | 200 | select_reverse(Tab, Spec, Limit) -> 201 | catch lets:select_reverse(Tab, Spec, Limit). 202 | 203 | select_reverse(Cont) -> 204 | catch lets:select_reverse(Cont). 205 | 206 | tab2list(Tab) -> 207 | catch lets:tab2list(Tab). 208 | 209 | 210 | %%%=================================================================== 211 | %%% Internal 212 | %%%=================================================================== 213 | 214 | filter_options(Options) -> 215 | X = proplists:get_value(db, Options, []), 216 | Y = [{path, ?MODULE_STRING}|proplists:delete(path, X)], 217 | [{db, Y}|proplists:delete(db, Options)]. 218 | -------------------------------------------------------------------------------- /test/qc/qc_lets_slave_proxy.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(qc_lets_slave_proxy). 24 | 25 | %% API 26 | -export([%% test 27 | teardown/1 28 | , is_table/1 29 | %% lets 30 | , all/1 31 | , tid/1 32 | , tid/2 33 | , new/2 34 | , new/3 35 | , destroy/3 36 | , repair/3 37 | , delete/1 38 | , delete/2 39 | , delete_all_objects/1 40 | , first/1 41 | , foldl/3 42 | , foldr/3 43 | , info/1 44 | , info/2 45 | , insert/2 46 | , insert_new/2 47 | , last/1 48 | , lookup/2 49 | , lookup_element/3 50 | , match/2 51 | , match/3 52 | , match/1 53 | , match_delete/2 54 | , match_object/2 55 | , match_object/3 56 | , match_object/1 57 | , member/2 58 | , next/2 59 | , prev/2 60 | , select/2 61 | , select/3 62 | , select/1 63 | , select_count/2 64 | , select_delete/2 65 | , select_reverse/2 66 | , select_reverse/3 67 | , select_reverse/1 68 | , tab2list/1 69 | ]). 70 | 71 | 72 | %%%=================================================================== 73 | %%% API 74 | %%%=================================================================== 75 | 76 | teardown(Name) -> 77 | stop_slave(), 78 | qc_lets_proxy:teardown(Name). 79 | 80 | is_table(Tab) -> 81 | qc_lets_proxy:is_table(Tab). 82 | 83 | all(Tab) -> 84 | qc_lets_proxy:all(Tab). 85 | 86 | tid(Tab) -> 87 | qc_lets_proxy:tid(Tab). 88 | 89 | tid(Tab, Options) -> 90 | qc_lets_proxy:tid(Tab, Options). 91 | 92 | new(Name, Options) -> 93 | call_slave(new, [Name, Options]). 94 | 95 | new(_Tab, Name, Options) -> 96 | %% _Tab is to help control generators and shrinking 97 | new(Name, Options). 98 | 99 | destroy(Tab, Name, Options) -> 100 | qc_lets_raw:destroy(Tab, Name, Options). 101 | 102 | repair(Tab, Name, Options) -> 103 | qc_lets_raw:repair(Tab, Name, Options). 104 | 105 | delete(Tab) -> 106 | qc_lets_proxy:delete(Tab). 107 | 108 | delete(Tab, Key) -> 109 | qc_lets_proxy:delete(Tab, Key). 110 | 111 | delete_all_objects(Tab) -> 112 | qc_lets_proxy:delete_all_objects(Tab). 113 | 114 | first(Tab) -> 115 | qc_lets_proxy:first(Tab). 116 | 117 | foldl(Function, Acc0, Tab) -> 118 | qc_lets_proxy:foldl(Function, Acc0, Tab). 119 | 120 | foldr(Function, Acc0, Tab) -> 121 | qc_lets_proxy:foldr(Function, Acc0, Tab). 122 | 123 | info(Tab) -> 124 | qc_lets_proxy:info(Tab). 125 | 126 | info(Tab, Item) -> 127 | qc_lets_proxy:info(Tab, Item). 128 | 129 | insert(Tab, ObjOrObjs) -> 130 | qc_lets_proxy:insert(Tab, ObjOrObjs). 131 | 132 | insert_new(Tab, ObjOrObjs) -> 133 | qc_lets_proxy:insert_new(Tab, ObjOrObjs). 134 | 135 | last(Tab) -> 136 | qc_lets_proxy:last(Tab). 137 | 138 | lookup(Tab, Key) -> 139 | qc_lets_proxy:lookup(Tab, Key). 140 | 141 | lookup_element(Tab, Key, Pos) -> 142 | qc_lets_proxy:lookup_element(Tab, Key, Pos). 143 | 144 | match(Tab, Pattern) -> 145 | qc_lets_proxy:match(Tab, Pattern). 146 | 147 | match(Tab, Pattern, Limit) -> 148 | qc_lets_proxy:match(Tab, Pattern, Limit). 149 | 150 | match(Cont) -> 151 | qc_lets_proxy:match(Cont). 152 | 153 | match_delete(Tab, Pattern) -> 154 | qc_lets_proxy:match_delete(Tab, Pattern). 155 | 156 | match_object(Tab, Pattern) -> 157 | qc_lets_proxy:match_object(Tab, Pattern). 158 | 159 | match_object(Tab, Pattern, Limit) -> 160 | qc_lets_proxy:match_object(Tab, Pattern, Limit). 161 | 162 | match_object(Cont) -> 163 | qc_lets_proxy:match_object(Cont). 164 | 165 | member(Tab, Key) -> 166 | qc_lets_proxy:member(Tab, Key). 167 | 168 | next(Tab, Key) -> 169 | qc_lets_proxy:next(Tab, Key). 170 | 171 | prev(Tab, Key) -> 172 | qc_lets_proxy:prev(Tab, Key). 173 | 174 | select(Tab, Spec) -> 175 | qc_lets_proxy:select(Tab, Spec). 176 | 177 | select(Tab, Spec, Limit) -> 178 | qc_lets_proxy:select(Tab, Spec, Limit). 179 | 180 | select(Cont) -> 181 | qc_lets_proxy:select(Cont). 182 | 183 | select_count(Tab, Spec) -> 184 | qc_lets_proxy:select_count(Tab, Spec). 185 | 186 | select_delete(Tab, Spec) -> 187 | qc_lets_proxy:select_delete(Tab, Spec). 188 | 189 | select_reverse(Tab, Spec) -> 190 | qc_lets_proxy:select_reverse(Tab, Spec). 191 | 192 | select_reverse(Tab, Spec, Limit) -> 193 | qc_lets_proxy:select_reverse(Tab, Spec, Limit). 194 | 195 | select_reverse(Cont) -> 196 | qc_lets_proxy:select_reverse(Cont). 197 | 198 | tab2list(Tab) -> 199 | qc_lets_proxy:tab2list(Tab). 200 | 201 | 202 | %%%=================================================================== 203 | %%% Internal 204 | %%%=================================================================== 205 | 206 | stop_slave() -> 207 | qc_slave:stop_slave(?MODULE). 208 | 209 | call_slave(Function, Args) -> 210 | Slave = qc_slave:restart_slave(?MODULE), 211 | case rpc:call(Slave, qc_lets_proxy, Function, Args) of 212 | {badrpc, {'EXIT', _}=Exit} -> 213 | Exit; 214 | {badrpc, _}=BadRpc -> 215 | BadRpc; 216 | Res -> 217 | Res 218 | end. 219 | -------------------------------------------------------------------------------- /test/qc/qc_statemc_lets.erl: -------------------------------------------------------------------------------- 1 | %%% The MIT License 2 | %%% 3 | %%% Copyright (C) 2011-2016 by Joseph Wayne Norton 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 13 | %%% all 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 21 | %%% THE SOFTWARE. 22 | 23 | -module(qc_statemc_lets). 24 | 25 | -ifdef(QC). 26 | -ifdef(QC_EQC). 27 | 28 | -include_lib("eqc/include/eqc_c.hrl"). 29 | -include_lib("qc/include/qc_statem.hrl"). 30 | 31 | -ifdef(QC_STATEM). 32 | 33 | %% API 34 | -export([qc_run/0, qc_run/1, qc_run/2]). 35 | -export([qc_sample/0, qc_sample/1]). 36 | -export([qc_prop/1]). 37 | -export([qc_check/0, qc_check/1, qc_check/2]). 38 | -export([qc_check_file/2]). 39 | 40 | %% qc_statem Callbacks 41 | -behaviour(qc_statem). 42 | -export([command/1]). 43 | -export([initial_state/0, initial_state/1, next_state/3, invariant/1, precondition/2, postcondition/3]). 44 | -export([init/0, init/1, stop/2, aggregate/1]). 45 | 46 | %% DEBUG -compile(export_all). 47 | 48 | 49 | %%%---------------------------------------------------------------------- 50 | %%% defines, types, records 51 | %%%---------------------------------------------------------------------- 52 | 53 | -define(IMPL, qc_leveldb). 54 | 55 | -record(obj, {key :: binary(), val :: binary()}). 56 | 57 | -type obj() :: #obj{}. 58 | -type proplist() :: proplists:proplist(). 59 | 60 | -record(state, { 61 | parallel=false :: boolean(), 62 | exists=false :: boolean(), 63 | options=[] :: proplists:proplist(), 64 | db=undefined :: undefined | term(), 65 | objs=[] :: [obj()] 66 | }). 67 | 68 | 69 | %%%---------------------------------------------------------------------- 70 | %%% API 71 | %%%---------------------------------------------------------------------- 72 | 73 | qc_run() -> 74 | qc_run(100). 75 | 76 | qc_run(NumTests) -> 77 | qc_run(NumTests, []). 78 | 79 | qc_run(NumTests, Options) -> 80 | qc_statem:qc_run(?MODULE, NumTests, Options). 81 | 82 | qc_sample() -> 83 | qc_sample([]). 84 | 85 | qc_sample(Options) -> 86 | qc_statem:qc_sample(?MODULE, Options). 87 | 88 | qc_prop(Options) -> 89 | qc_statem:qc_prop(?MODULE, Options). 90 | 91 | qc_check() -> 92 | qc_check([]). 93 | 94 | qc_check(Options) -> 95 | qc_check(Options, ?QC:counterexample()). 96 | 97 | qc_check(Options, CounterExample) -> 98 | qc_statem:qc_check(?MODULE, Options, CounterExample). 99 | 100 | qc_check_file(Options, FileName) -> 101 | qc_statem:qc_check_file(?MODULE, Options, FileName). 102 | 103 | 104 | %%%---------------------------------------------------------------------- 105 | %%% qc_statem Callbacks 106 | %%%---------------------------------------------------------------------- 107 | command(#state{parallel=false}=S) -> 108 | serial_command_gen(S); 109 | command(#state{parallel=true}=S) -> 110 | parallel_command_gen(S). 111 | 112 | serial_command_gen(#state{db=undefined, exists=false}) -> 113 | {call,?IMPL,open,[ulist(gen_db_options())]}; 114 | serial_command_gen(#state{db=undefined, exists=true}) -> 115 | oneof([{call,?IMPL,reopen,[ulist(gen_db_options())]} 116 | %% @TODO {call,?IMPL,destroy,[ulist(gen_db_options())]} 117 | %% @TODO {call,?IMPL,repair[ulist(gen_db_options())]} 118 | ]); 119 | serial_command_gen(#state{db=Db}=S) -> 120 | oneof([{call,?IMPL,close,[Db]}, 121 | {call,?IMPL,put,[Db,gen_obj(S),ulist(gen_db_write_options())]}, 122 | {call,?IMPL,delete,[Db,gen_key(S),ulist(gen_db_write_options())]}, 123 | {call,?IMPL,get,[Db,gen_key(S),ulist(gen_db_read_options())]}, 124 | {call,?IMPL,first,[Db,ulist(gen_db_read_options())]}, 125 | {call,?IMPL,last,[Db,ulist(gen_db_read_options())]}, 126 | {call,?IMPL,next,[Db,gen_key(S),ulist(gen_db_read_options())]}, 127 | {call,?IMPL,prev,[Db,gen_key(S),ulist(gen_db_read_options())]} 128 | ]). 129 | 130 | parallel_command_gen(#state{db=undefined, exists=false}) -> 131 | {call,?IMPL,open,[ulist(gen_db_options())]}; 132 | parallel_command_gen(#state{db=Db}=S) -> 133 | oneof([{call,?IMPL,put,[Db,gen_obj(S),ulist(gen_db_write_options())]}, 134 | {call,?IMPL,delete,[Db,gen_key(S),ulist(gen_db_write_options())]}, 135 | {call,?IMPL,get,[Db,gen_key(S),ulist(gen_db_read_options())]} 136 | ]). 137 | 138 | -spec initial_state() -> #state{}. 139 | initial_state() -> 140 | initial_state([]). 141 | 142 | -spec initial_state(proplist()) -> #state{}. 143 | initial_state(Opts) -> 144 | #state{parallel=proplists:get_value(parallel, Opts, false)}. 145 | 146 | -spec next_state(#state{}, term(), tuple()) -> #state{}. 147 | next_state(#state{db=undefined, exists=false}=S, V, {call,_,open,[Opts]}) -> 148 | S#state{options=Opts, db=V, exists=true}; 149 | next_state(#state{db=undefined, exists=true}=S, V, {call,_,reopen,[Opts]}) -> 150 | S#state{options=Opts, db=V, exists=true}; 151 | next_state(#state{db=undefined, exists=true}=S, V, {call,_,destroy,[Opts]}) -> 152 | S#state{options=Opts, db=V, exists=false, objs=[]}; 153 | next_state(#state{db=Db}=S, _V, {call,_,close,[Db]}) when Db /= undefined -> 154 | S#state{db=undefined}; 155 | next_state(S, _V, {call,_,put,[_Db,Obj,_Opts]}) -> 156 | insert_obj(S, Obj); 157 | next_state(S, _V, {call,_,delete,[_Db,Key,_Opts]}) -> 158 | delete_obj(S, Key); 159 | next_state(S, _V, {call,_,_,_}) -> 160 | S. 161 | 162 | -spec invariant(#state{}) -> boolean(). 163 | invariant(_S) -> 164 | true. 165 | 166 | -spec precondition(#state{}, tuple()) -> boolean(). 167 | precondition(#state{exists=true}, {call,_,open,[__Opts]}) -> 168 | false; 169 | precondition(#state{exists=false}, {call,_,reopen,[__Opts]}) -> 170 | false; 171 | precondition(#state{exists=false}, {call,_,destroy,[__Opts]}) -> 172 | false; 173 | precondition(#state{exists=false}, {call,_,repair,[__Opts]}) -> 174 | false; 175 | precondition(#state{db=Db}, {call,_,open,[__Opts]}) when Db /= undefined-> 176 | false; 177 | precondition(#state{db=Db}, {call,_,reopen,[__Opts]}) when Db /= undefined-> 178 | false; 179 | precondition(#state{db=Db}, {call,_,destroy,[__Opts]}) when Db /= undefined-> 180 | false; 181 | precondition(#state{db=Db}, {call,_,repair,[__Opts]}) when Db /= undefined-> 182 | false; 183 | precondition(_S, {call,_,_,_}) -> 184 | true. 185 | 186 | -spec postcondition(#state{}, tuple(), term()) -> boolean(). 187 | postcondition(#state{exists=false}, {call,_,open,[__Opts]}, Res) -> 188 | ?IMPL:is_db(Res); 189 | postcondition(#state{exists=true}, {call,_,reopen,[_Opts]}, Res) -> 190 | ?IMPL:is_db(Res); 191 | postcondition(#state{exists=true}, {call,_,destroy,[_Opts]}, Res) -> 192 | Res; 193 | postcondition(#state{exists=true}, {call,_,repair,[_Opts]}, Res) -> 194 | Res; 195 | postcondition(#state{db=Db}, {call,_,close,[_Db]}, Res) -> 196 | Res andalso Db /= undefined; 197 | postcondition(_S, {call,_,put,[_Db,_,_Opts]}, Res) -> 198 | Res; 199 | postcondition(_S, {call,_,delete,[_Db,_,_Opts]}, Res) -> 200 | Res; 201 | postcondition(S, {call,_,get,[_Db,Key,_Opts]}, Res) -> 202 | Res =:= get_val(S, Key); 203 | postcondition(#state{objs=[]}, {call,_,first,[_Db,_Opts]}, Res) -> 204 | Res; 205 | postcondition(S, {call,_,first,[_Db,_Opts]}, Res) -> 206 | #obj{key=K} = hd(sort_objs(S)), 207 | Res =:= K; 208 | postcondition(#state{objs=[]}, {call,_,last,[_Db,_Opts]}, Res) -> 209 | Res; 210 | postcondition(S, {call,_,last,[_Db,_Opts]}, Res) -> 211 | #obj{key=K} = hd(lists:reverse(sort_objs(S))), 212 | Res =:= K; 213 | postcondition(S, {call,_,next,[_Db,Key,_Opts]}, Res) -> 214 | case lists:dropwhile(fun(#obj{key=X}) -> X =< Key end, sort_objs(S)) of 215 | [] -> 216 | Res; 217 | [#obj{key=K}|_] -> 218 | Res =:= K 219 | end; 220 | postcondition(S, {call,_,prev,[_Db,Key,_Opts]}, Res) -> 221 | case lists:dropwhile(fun(#obj{key=X}) -> X >= Key end, rsort_objs(S)) of 222 | [] -> 223 | Res; 224 | [#obj{key=K}|_] -> 225 | Res =:= K 226 | end; 227 | postcondition(_S, {call,_,_,_}, _Res) -> 228 | false. 229 | 230 | -spec init() -> ok. 231 | init() -> 232 | ok. 233 | 234 | -spec init(#state{}) -> ok. 235 | init(_State) -> 236 | ok. 237 | 238 | -spec stop(#state{}, #state{}) -> ok. 239 | stop(_State0, _State) -> 240 | ok. 241 | 242 | -spec aggregate([{integer(), term(), term(), #state{}}]) 243 | -> [{{atom(), integer()}, term()}]. 244 | aggregate(L) -> 245 | [ {{Cmd,length(Args)},filter_reply(Reply)} || {_N,{set,_,{call,_,Cmd,Args}},Reply,_State} <- L ]. 246 | 247 | filter_reply({'EXIT',{Err,_}}) -> 248 | {error,Err}; 249 | filter_reply(_) -> 250 | ok. 251 | 252 | 253 | %%%---------------------------------------------------------------------- 254 | %%% Internal - Generators 255 | %%%---------------------------------------------------------------------- 256 | 257 | gen_db_options() -> 258 | oneof([paranoid_checks, {paranoid_checks,gen_boolean()}, {write_buffer_size,gen_pos_integer()}, {max_open_files,gen_pos_integer()}, {block_cache_size,gen_pos_integer()}, {block_size,gen_pos_integer()}, {block_restart_interval,gen_pos_integer()}, compression, {compression, oneof([no, snappy])}, {filter_policy, oneof([no, {bloom,gen_pos_integer()}])}]). 259 | 260 | gen_db_read_options() -> 261 | oneof([verify_checksums, {verify_checksums,gen_boolean()}, fill_cache, {fill_cache,gen_boolean()}]). 262 | 263 | gen_db_write_options() -> 264 | oneof([sync, {sync,gen_boolean()}]). 265 | 266 | gen_boolean() -> 267 | oneof([true, false]). 268 | 269 | gen_pos_integer() -> 270 | ?LET(N, nat(), N+1). 271 | 272 | gen_bytes() -> 273 | ?LET(B, list(choose(0,127)), list_to_binary(B)). 274 | 275 | gen_key() -> 276 | gen_bytes(). 277 | 278 | gen_val() -> 279 | gen_bytes(). 280 | 281 | gen_obj() -> 282 | #obj{key=gen_key(), val=gen_val()}. 283 | 284 | gen_key(#state{objs=[]}) -> 285 | gen_key(); 286 | gen_key(#state{objs=Objs}) -> 287 | oneof([?LET(Obj, oneof(Objs), Obj#obj.key), gen_key()]). 288 | 289 | gen_obj(#state{objs=[]}) -> 290 | gen_obj(); 291 | gen_obj(#state{objs=Objs}) -> 292 | oneof([oneof(Objs), gen_obj()]). 293 | 294 | 295 | %%%---------------------------------------------------------------------- 296 | %%% Internal - Model 297 | %%%---------------------------------------------------------------------- 298 | 299 | insert_obj(S, #obj{key=K}=Obj) -> 300 | case keymember(K, S) of 301 | false -> 302 | S#state{objs=[Obj|S#state.objs]}; 303 | true -> 304 | S#state{objs=keyreplace(K, Obj, S)} 305 | end. 306 | 307 | delete_obj(S, K) -> 308 | S#state{objs=keydelete(K, S)}. 309 | 310 | get_val(S, K) -> 311 | case keyfind(K, S) of 312 | [] -> 313 | true; 314 | [#obj{val=Val}] -> 315 | Val 316 | end. 317 | 318 | sort_objs(#state{objs=Objs}) -> 319 | lists:sort(Objs). 320 | 321 | rsort_objs(S) -> 322 | lists:reverse(sort_objs(S)). 323 | 324 | keydelete(X, #state{objs=L}) -> 325 | lists:filter(fun(#obj{key=K}) -> K =/= X end, L). 326 | 327 | keyreplace(X, Y, #state{objs=L}) -> 328 | lists:map(fun(Z=#obj{key=K}) -> case K =:= X of true -> Y; false -> Z end end, L). 329 | 330 | keyfind(X, #state{objs=L}) -> 331 | lists:filter(fun(#obj{key=K}) -> K =:= X end, L). 332 | 333 | keymember(X, S) -> 334 | [] /= keyfind(X, S). 335 | 336 | 337 | %%%---------------------------------------------------------------------- 338 | %%% Internal - Implementation 339 | %%%---------------------------------------------------------------------- 340 | 341 | -endif. %% -ifdef(QC_STATEM). 342 | 343 | -endif. %% -ifdef(QC_EQC). 344 | -endif. %% -ifdef(QC). 345 | --------------------------------------------------------------------------------