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

openSUSE Build Service is sponsored by