add open/2 and open/3
This commit is contained in:
parent
1a33be0432
commit
ebb69cd53d
6 changed files with 186 additions and 18 deletions
13
README.md
13
README.md
|
@ -12,7 +12,12 @@ But this module could also be used as a general key-value store to replace:
|
||||||
* Erlang R14B04+
* GCC 4.2+ or MS VisualStudio 2010+
Build
-----
$ make
API
---
|
* Erlang R14B04+
* GCC 4.2+ or MS VisualStudio 2010+
Build
-----
$ make
API
---
|
||||||
The following functions were implemented:
|
The following functions were implemented:
|
||||||
|
|
||||||
* `open/1`: creates a new MDB database. This call also re-open an already existing one.
|
* `open/1`: equivalent to `emdb:open(DirName, 10485760)`.
|
||||||
|
* `open/1`: equivalent to `emdb:open(DirName, 10485760, 0)`.
|
||||||
|
* `open/3`: creates a new MDB database. This call also re-open an already existing one. Arguments are:
|
||||||
|
* DirName: database directory name
|
||||||
|
* MapSize: database map size (see [map.hrl](http://gitorious.org/mdb/mdb/blobs/master/libraries/libmdb/mdb.h))
|
||||||
|
* EnvFlags: database environment flags (see [map.hrl](http://gitorious.org/mdb/mdb/blobs/master/libraries/libmdb/mdb.h)). The possible values are defined in **emdb.hrl**.
|
||||||
* `close/2`: closes the database
|
* `close/2`: closes the database
|
||||||
* `put/2`: inserts Key with value Val into the database. Assumes that the key is not present, 'key_exit' is returned otherwise.
|
* `put/2`: inserts Key with value Val into the database. Assumes that the key is not present, 'key_exit' is returned otherwise.
|
||||||
* `get/1`: retrieves the value stored with Key in the database.
|
* `get/1`: retrieves the value stored with Key in the database.
|
||||||
|
@ -58,9 +63,15 @@ $ ./start.sh
|
||||||
|
|
||||||
%% close the database
16> ok = Handle:close().
|
%% close the database
16> ok = Handle:close().
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
17> q().
|
17> q().
|
||||||
|
|
||||||
|
|
||||||
|
####Note:
|
||||||
|
This code below create a new database with **80GB** MapSize, **avoid fsync**
|
||||||
|
after each commit (for max speed) and use the experimental **MDB_FIXEDMAP**.
{ok, Handle} = emdb:open("/tmp/emdb2", 85899345920, ?MDB_NOSYNC bor ?MDB_FIXEDMAP).
|
||||||
|
|
||||||
Performance
-----------
For maximum speed, this library use only binaries for both keys and values.
|
Performance
-----------
For maximum speed, this library use only binaries for both keys and values.
|
||||||
See the impressive [microbench](http://highlandsun.com/hyc/mdb/microbench/) against:
|
See the impressive [microbench](http://highlandsun.com/hyc/mdb/microbench/) against:
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ static struct emdb_map_t * emdb_map = NULL;
|
||||||
|
|
||||||
/* emdb errors */
|
/* emdb errors */
|
||||||
#define EMDB_MALLOC_ERR "error_malloc"
|
#define EMDB_MALLOC_ERR "error_malloc"
|
||||||
|
#define EMDB_MAKE_BINARY_ERR "error_make_binary"
|
||||||
#define EMDB_CREATE_ERR "error_create"
|
#define EMDB_CREATE_ERR "error_create"
|
||||||
#define EMDB_MAPSIZE_ERR "error_mapsize"
|
#define EMDB_MAPSIZE_ERR "error_mapsize"
|
||||||
#define EMDB_OPEN_ERR "error_open"
|
#define EMDB_OPEN_ERR "error_open"
|
||||||
|
@ -100,6 +101,8 @@ static ERL_NIF_TERM emdb_open_nif (ErlNifEnv * env,
|
||||||
struct emdb_map_t * node;
|
struct emdb_map_t * node;
|
||||||
MDB_txn * txn;
|
MDB_txn * txn;
|
||||||
char * err;
|
char * err;
|
||||||
|
ErlNifUInt64 mapsize;
|
||||||
|
ErlNifUInt64 envflags;
|
||||||
|
|
||||||
if (enif_get_string(env, argv[0], dirname, MAXPATHLEN, ERL_NIF_LATIN1) <= 0)
|
if (enif_get_string(env, argv[0], dirname, MAXPATHLEN, ERL_NIF_LATIN1) <= 0)
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
|
@ -110,10 +113,16 @@ static ERL_NIF_TERM emdb_open_nif (ErlNifEnv * env,
|
||||||
if (mdb_env_create(& (node -> env)))
|
if (mdb_env_create(& (node -> env)))
|
||||||
FAIL_FAST(EMDB_CREATE_ERR, err2);
|
FAIL_FAST(EMDB_CREATE_ERR, err2);
|
||||||
|
|
||||||
if (mdb_env_set_mapsize(node -> env, 10485760))
|
if (! enif_get_uint64(env, argv[1], & mapsize))
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
|
||||||
|
if (mdb_env_set_mapsize(node -> env, mapsize))
|
||||||
FAIL_FAST(EMDB_MAPSIZE_ERR, err2);
|
FAIL_FAST(EMDB_MAPSIZE_ERR, err2);
|
||||||
|
|
||||||
if (mdb_env_open(node -> env, dirname, MDB_FIXEDMAP, 0664))
|
if (! enif_get_uint64(env, argv[2], & envflags))
|
||||||
|
return enif_make_badarg(env);
|
||||||
|
|
||||||
|
if (mdb_env_open(node -> env, dirname, envflags, 0664))
|
||||||
FAIL_FAST(EMDB_OPEN_ERR, err2);
|
FAIL_FAST(EMDB_OPEN_ERR, err2);
|
||||||
|
|
||||||
if (mdb_txn_begin(node -> env, NULL, 0, & txn))
|
if (mdb_txn_begin(node -> env, NULL, 0, & txn))
|
||||||
|
@ -209,7 +218,7 @@ static ERL_NIF_TERM emdb_put_nif (ErlNifEnv * env,
|
||||||
ret = mdb_put(txn, node -> dbi, & mkey, & mdata, MDB_NOOVERWRITE);
|
ret = mdb_put(txn, node -> dbi, & mkey, & mdata, MDB_NOOVERWRITE);
|
||||||
if (MDB_KEYEXIST == ret)
|
if (MDB_KEYEXIST == ret)
|
||||||
FAIL_FAST(EMDB_RET_KEY_EXIST, err1);
|
FAIL_FAST(EMDB_RET_KEY_EXIST, err1);
|
||||||
if (ret)
|
if (ret)
|
||||||
FAIL_FAST(EMDB_PUT_ERR, err1);
|
FAIL_FAST(EMDB_PUT_ERR, err1);
|
||||||
|
|
||||||
if (mdb_txn_commit(txn))
|
if (mdb_txn_commit(txn))
|
||||||
|
@ -229,6 +238,7 @@ static ERL_NIF_TERM emdb_get_nif (ErlNifEnv * env,
|
||||||
{
|
{
|
||||||
ErlNifBinary key;
|
ErlNifBinary key;
|
||||||
ErlNifBinary val;
|
ErlNifBinary val;
|
||||||
|
/* ERL_NIF_TERM term; */
|
||||||
|
|
||||||
MDB_val mkey;
|
MDB_val mkey;
|
||||||
MDB_val mdata;
|
MDB_val mdata;
|
||||||
|
@ -265,7 +275,7 @@ static ERL_NIF_TERM emdb_get_nif (ErlNifEnv * env,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! enif_alloc_binary(mdata.mv_size, & val))
|
if (! enif_alloc_binary(mdata.mv_size, & val))
|
||||||
FAIL_FAST(EMDB_MALLOC_ERR, err2);
|
FAIL_FAST(EMDB_MALLOC_ERR, err2);
|
||||||
|
|
||||||
memcpy(val.data, mdata.mv_data, mdata.mv_size);
|
memcpy(val.data, mdata.mv_data, mdata.mv_size);
|
||||||
|
|
||||||
|
@ -275,6 +285,16 @@ static ERL_NIF_TERM emdb_get_nif (ErlNifEnv * env,
|
||||||
atom_ok,
|
atom_ok,
|
||||||
enif_make_binary(env, & val));
|
enif_make_binary(env, & val));
|
||||||
|
|
||||||
|
/* val.size = mdata.mv_size; */
|
||||||
|
/* val.data = mdata.mv_data; */
|
||||||
|
|
||||||
|
/* mdb_txn_abort(txn); */
|
||||||
|
|
||||||
|
/* return enif_make_tuple(env, 2, */
|
||||||
|
/* atom_ok, */
|
||||||
|
/* term); */
|
||||||
|
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
mdb_txn_abort(txn);
|
mdb_txn_abort(txn);
|
||||||
err1:
|
err1:
|
||||||
|
@ -451,7 +471,7 @@ static void emdb_unload(ErlNifEnv* env, void* priv)
|
||||||
|
|
||||||
|
|
||||||
static ErlNifFunc nif_funcs [] = {
|
static ErlNifFunc nif_funcs [] = {
|
||||||
{"open", 1, emdb_open_nif},
|
{"open", 3, emdb_open_nif},
|
||||||
{"close", 1, emdb_close_nif},
|
{"close", 1, emdb_close_nif},
|
||||||
{"put", 3, emdb_put_nif},
|
{"put", 3, emdb_put_nif},
|
||||||
{"get", 2, emdb_get_nif},
|
{"get", 2, emdb_get_nif},
|
||||||
|
|
36
include/emdb.hrl
Normal file
36
include/emdb.hrl
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
%%-------------------------------------------------------------------
|
||||||
|
%% This file is part of EMDB - Erlang MDB API
|
||||||
|
%%
|
||||||
|
%% Copyright (c) 2012 by Aleph Archives. All rights reserved.
|
||||||
|
%%
|
||||||
|
%%-------------------------------------------------------------------
|
||||||
|
%% Redistribution and use in source and binary forms, with or without
|
||||||
|
%% modification, are permitted only as authorized by the OpenLDAP
|
||||||
|
%% Public License.
|
||||||
|
%%
|
||||||
|
%% A copy of this license is available in the file LICENSE in the
|
||||||
|
%% top-level directory of the distribution or, alternatively, at
|
||||||
|
%% <http://www.OpenLDAP.org/license.html>.
|
||||||
|
%%
|
||||||
|
%% Permission to use, copy, modify, and distribute this software for any
|
||||||
|
%% purpose with or without fee is hereby granted, provided that the above
|
||||||
|
%% copyright notice and this permission notice appear in all copies.
|
||||||
|
%%
|
||||||
|
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
%%-------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
%% Environment Flags
|
||||||
|
-define(MDB_FIXEDMAP, 16#01).
|
||||||
|
-define(MDB_NOSUBDIR, 16#02).
|
||||||
|
-define(MDB_NOSYNC, 16#10000).
|
||||||
|
-define(MDB_RDONLY, 16#20000).
|
||||||
|
-define(MDB_NOMETASYNC, 16#40000).
|
||||||
|
-define(MDB_WRITEMAP, 16#80000).
|
||||||
|
-define(MDB_MAPASYNC, 16#100000).
|
95
include/emdb.hrl~
Normal file
95
include/emdb.hrl~
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
%% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% This file is provided to you under the Apache License,
|
||||||
|
%% Version 2.0 (the "License"); you may not use this file
|
||||||
|
%% except in compliance with the License. You may obtain
|
||||||
|
%% a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing,
|
||||||
|
%% software distributed under the License is distributed on an
|
||||||
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
%% KIND, either express or implied. See the License for the
|
||||||
|
%% specific language governing permissions and limitations
|
||||||
|
%% under the License.
|
||||||
|
|
||||||
|
-define(LEVELS,
|
||||||
|
[debug, info, notice, warning, error, critical, alert, emergency, none]).
|
||||||
|
|
||||||
|
-define(DEBUG, 7).
|
||||||
|
-define(INFO, 6).
|
||||||
|
-define(NOTICE, 5).
|
||||||
|
-define(WARNING, 4).
|
||||||
|
-define(ERROR, 3).
|
||||||
|
-define(CRITICAL, 2).
|
||||||
|
-define(ALERT, 1).
|
||||||
|
-define(EMERGENCY, 0).
|
||||||
|
-define(LOG_NONE, -1).
|
||||||
|
|
||||||
|
-define(LEVEL2NUM(Level),
|
||||||
|
case Level of
|
||||||
|
debug -> ?DEBUG;
|
||||||
|
info -> ?INFO;
|
||||||
|
notice -> ?NOTICE;
|
||||||
|
warning -> ?WARNING;
|
||||||
|
error -> ?ERROR;
|
||||||
|
critical -> ?CRITICAL;
|
||||||
|
alert -> ?ALERT;
|
||||||
|
emergency -> ?EMERGENCY
|
||||||
|
end).
|
||||||
|
|
||||||
|
-define(NUM2LEVEL(Num),
|
||||||
|
case Num of
|
||||||
|
?DEBUG -> debug;
|
||||||
|
?INFO -> info;
|
||||||
|
?NOTICE -> notice;
|
||||||
|
?WARNING -> warning;
|
||||||
|
?ERROR -> error;
|
||||||
|
?CRITICAL -> critical;
|
||||||
|
?ALERT -> alert;
|
||||||
|
?EMERGENCY -> emergency
|
||||||
|
end).
|
||||||
|
|
||||||
|
-define(SHOULD_LOG(Level),
|
||||||
|
lager_util:level_to_num(Level) =< element(1, lager_mochiglobal:get(loglevel, {?LOG_NONE, []}))).
|
||||||
|
|
||||||
|
-define(NOTIFY(Level, Pid, Format, Args),
|
||||||
|
gen_event:notify(lager_event, {log, lager_util:level_to_num(Level),
|
||||||
|
lager_util:format_time(), [io_lib:format("[~p] ", [Level]),
|
||||||
|
io_lib:format("~p ", [Pid]), io_lib:format(Format, Args)]})).
|
||||||
|
|
||||||
|
%% FOR INTERNAL USE ONLY
|
||||||
|
%% internal non-blocking logging call
|
||||||
|
%% there's some special handing for when we try to log (usually errors) while
|
||||||
|
%% lager is still starting.
|
||||||
|
-ifdef(TEST).
|
||||||
|
-define(INT_LOG(Level, Format, Args),
|
||||||
|
case ?SHOULD_LOG(Level) of
|
||||||
|
true ->
|
||||||
|
?NOTIFY(Level, self(), Format, Args);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end).
|
||||||
|
-else.
|
||||||
|
-define(INT_LOG(Level, Format, Args),
|
||||||
|
Self = self(),
|
||||||
|
%% do this in a spawn so we don't cause a deadlock calling gen_event:which_handlers
|
||||||
|
%% from a gen_event handler
|
||||||
|
spawn(fun() ->
|
||||||
|
case catch(gen_event:which_handlers(lager_event)) of
|
||||||
|
X when X == []; X == {'EXIT', noproc} ->
|
||||||
|
%% there's no handlers yet or lager isn't running, try again
|
||||||
|
%% in half a second.
|
||||||
|
timer:sleep(500),
|
||||||
|
?NOTIFY(Level, Self, Format, Args);
|
||||||
|
_ ->
|
||||||
|
case ?SHOULD_LOG(Level) of
|
||||||
|
true ->
|
||||||
|
?NOTIFY(Level, Self, Format, Args);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)).
|
||||||
|
-endif.
|
22
src/emdb.erl
22
src/emdb.erl
|
@ -32,18 +32,22 @@
|
||||||
%% EXPORTS
|
%% EXPORTS
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
-export([
|
-export([
|
||||||
open/1
|
open/1,
|
||||||
|
open/2,
|
||||||
|
open/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% Types
|
%% Includes
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
-record(emdb_oop, {
|
-include("emdb.hrl").
|
||||||
handle :: non_neg_integer()
|
|
||||||
}).
|
|
||||||
|
|
||||||
|
|
||||||
|
%%====================================================================
|
||||||
|
%% Macros
|
||||||
|
%%====================================================================
|
||||||
|
-define(MDB_MAP_SIZE, 10485760). %% 10MB
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% PUBLIC API
|
%% PUBLIC API
|
||||||
|
@ -53,12 +57,14 @@
|
||||||
%% @doc Create a new MDB database
|
%% @doc Create a new MDB database
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec open(file:name()) -> #emdb_oop{}.
|
|
||||||
open(DirName) ->
|
open(DirName) ->
|
||||||
|
open(DirName, ?MDB_MAP_SIZE).
|
||||||
|
open(DirName, MapSize) when is_integer(MapSize) andalso MapSize > 0 ->
|
||||||
|
open(DirName, MapSize, 0).
|
||||||
|
open(DirName, MapSize, EnvFlags) when is_integer(MapSize) andalso MapSize > 0 andalso is_integer(EnvFlags) andalso EnvFlags >= 0 ->
|
||||||
%% ensure directory exists
|
%% ensure directory exists
|
||||||
ok = filelib:ensure_dir(DirName ++ "/"),
|
ok = filelib:ensure_dir(DirName ++ "/"),
|
||||||
decorate(emdb_drv:open(DirName)).
|
decorate(emdb_drv:open(DirName, MapSize, EnvFlags)).
|
||||||
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
%% PRIVATE API
|
%% PRIVATE API
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
%% EXPORTS
|
%% EXPORTS
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
-export([
|
-export([
|
||||||
open/1,
|
open/3,
|
||||||
close/1,
|
close/1,
|
||||||
|
|
||||||
put/3,
|
put/3,
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
%% @doc
|
%% @doc
|
||||||
%% @end
|
%% @end
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
open(_DirName) ->
|
open(_DirName, _MapSize, _EnvFlags) ->
|
||||||
?NOT_LOADED.
|
?NOT_LOADED.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue