File 0001-Add-count-function.patch of Package eleveldb
From 61c1f5b3cffa61372e97598e22d6b3ec274bd73d Mon Sep 17 00:00:00 2001
From: mocchira <nekotaroh@gmail.com>
Date: Thu, 25 Jan 2018 17:15:37 +0900
Subject: [PATCH] Add count function
---
c_src/eleveldb.cc | 28 ++++++++++++++++++++++++++++
c_src/eleveldb.h | 2 ++
c_src/workitems.cc | 30 ++++++++++++++++++++++++++++++
c_src/workitems.h | 17 +++++++++++++++++
src/eleveldb.erl | 18 +++++++++++++++++-
5 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/c_src/eleveldb.cc b/c_src/eleveldb.cc
index de93560..a453a8e 100644
--- a/c_src/eleveldb.cc
+++ b/c_src/eleveldb.cc
@@ -66,6 +66,8 @@ static ErlNifFunc nif_funcs[] =
{"repair", 2, eleveldb_repair},
{"is_empty", 1, eleveldb_is_empty},
+ {"async_count", 2, eleveldb::async_count},
+
{"async_open", 3, eleveldb::async_open},
{"async_write", 4, eleveldb::async_write},
{"async_get", 4, eleveldb::async_get},
@@ -1033,6 +1035,32 @@ async_iterator_move(
} // async_iter_move
+ERL_NIF_TERM
+async_count(
+ ErlNifEnv* env,
+ int argc,
+ const ERL_NIF_TERM argv[])
+{
+ const ERL_NIF_TERM& caller_ref = argv[0];
+ const ERL_NIF_TERM& dbh_ref = argv[1];
+
+ ReferencePtr<DbObject> db_ptr;
+
+ db_ptr.assign(DbObject::RetrieveDbObject(env, dbh_ref));
+
+ if(NULL==db_ptr.get() || 0!=db_ptr->GetCloseRequested())
+ {
+ return enif_make_badarg(env);
+ }
+
+ // likely useless
+ if(NULL == db_ptr->m_Db)
+ return send_reply(env, caller_ref, error_einval(env));
+
+ eleveldb::WorkTask *work_item = new eleveldb::CountTask(env, caller_ref, db_ptr);
+ return submit_to_thread_queue(work_item, env, caller_ref);
+} // async_count
+
ERL_NIF_TERM
async_close(
diff --git a/c_src/eleveldb.h b/c_src/eleveldb.h
index 1336188..a3e7b05 100644
--- a/c_src/eleveldb.h
+++ b/c_src/eleveldb.h
@@ -51,6 +51,8 @@ ERL_NIF_TERM async_iterator(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM async_iterator_move(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM async_iterator_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM async_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
} // namespace eleveldb
diff --git a/c_src/workitems.cc b/c_src/workitems.cc
index 911a45c..25174f1 100644
--- a/c_src/workitems.cc
+++ b/c_src/workitems.cc
@@ -592,6 +592,36 @@ DestroyTask::DoWork()
} // DestroyTask::DoWork()
+/**
+ * CountTask functions
+ */
+
+CountTask::CountTask(ErlNifEnv *_caller_env,
+ ERL_NIF_TERM _caller_ref,
+ DbObjectPtr_t & _db_handle)
+ : WorkTask(_caller_env, _caller_ref, _db_handle)
+{}
+
+CountTask::~CountTask() {}
+
+work_result
+CountTask::DoWork()
+{
+
+ uint64_t cnt = 0;
+
+ leveldb::Iterator* it = m_DbPtr->m_Db->NewIterator(leveldb::ReadOptions());
+ for (it->SeekToFirst(); it->Valid(); it->Next()) {
+ cnt++;
+ }
+ leveldb::Status status = it->status();
+ delete it;
+ if(!status.ok()){
+ return work_result(local_env(), ATOM_ERROR, status);
+ }
+
+ return work_result(local_env(), ATOM_OK, enif_make_uint64(local_env_, cnt));
+}
} // namespace eleveldb
diff --git a/c_src/workitems.h b/c_src/workitems.h
index 475b751..e65d2d7 100644
--- a/c_src/workitems.h
+++ b/c_src/workitems.h
@@ -336,6 +336,23 @@ private:
}; // class DestroyTask
+/**
+ * Background object for async count,
+ */
+
+class CountTask : public WorkTask
+{
+public:
+ CountTask(ErlNifEnv *_caller_env,
+ ERL_NIF_TERM _caller_ref,
+ DbObjectPtr_t & _db_handle);
+
+ virtual ~CountTask();
+
+ virtual work_result DoWork();
+
+}; // class CountTask
+
} // namespace eleveldb
diff --git a/src/eleveldb.erl b/src/eleveldb.erl
index b6f591e..e5d60f3 100644
--- a/src/eleveldb.erl
+++ b/src/eleveldb.erl
@@ -35,6 +35,8 @@
repair/2,
is_empty/1]).
+-export([count/1]).
+
-export([option_types/1,
validate_options/2]).
@@ -252,6 +254,16 @@ iterator_close(IRef) ->
async_iterator_close(_CallerRef, _IRef) ->
erlang:nif_error({error, not_loaded}).
+%% Iterating over all records in the database and return the number of records.
+-spec count(db_ref()) -> {ok, non_neg_integer()} | {error, any()}.
+count(Ref) ->
+ CallerRef = make_ref(),
+ async_count(CallerRef, Ref),
+ ?WAIT_FOR_REPLY(CallerRef).
+
+async_count(_CallerRef, _Ref) ->
+ erlang:nif_error({error, not_loaded}).
+
-type fold_fun() :: fun(({Key::binary(), Value::binary()}, any()) -> any()).
%% Fold over the keys and values in the database
@@ -563,6 +575,7 @@ test_open(TestDir) ->
?assertEqual(ok, ?MODULE:put(Ref, <<"abc">>, <<"123">>, [])),
?assertEqual({ok, <<"123">>}, ?MODULE:get(Ref, <<"abc">>, [])),
?assertEqual(not_found, ?MODULE:get(Ref, <<"def">>, [])),
+ ?assertEqual({ok, 1}, ?MODULE:count(Ref)),
assert_close(Ref).
test_open_many(TestDir, HowMany) ->
@@ -584,7 +597,8 @@ test_open_many(TestDir, HowMany) ->
end, WorkSet),
lists:foreach(
fun({Ref, Key, Val}) ->
- ?assertEqual({ok, Val}, ?MODULE:get(Ref, Key, []))
+ ?assertEqual({ok, Val}, ?MODULE:get(Ref, Key, [])),
+ ?assertEqual({ok, 1}, ?MODULE:count(Ref))
end, WorkSet),
lists:foreach(fun assert_close/1, [R || {R, _, _} <- WorkSet]).
@@ -601,6 +615,7 @@ test_fold(TestDir) ->
?assertEqual(
[{<<"abc">>, <<"123">>}, {<<"def">>, <<"456">>}, {<<"hij">>, <<"789">>}],
lists:reverse(?MODULE:fold(Ref, fun accumulate/2, [], []))),
+ ?assertEqual({ok, 3}, ?MODULE:count(Ref)),
assert_close(Ref).
test_fold_keys(TestDir) ->
@@ -711,6 +726,7 @@ run_load(TestDir, IntSeq) ->
fun({Key, Val}) ->
?assertEqual({ok, Val}, ?MODULE:get(Ref, Key, []))
end, KVOut),
+ ?assertEqual({ok, length(IntSeq)}, ?MODULE:count(Ref)),
assert_close(Ref).
%% ===================================================================
--
2.16.1