This is an automated email from the ASF dual-hosted git repository.

bbastian pushed a commit to branch 8409-view-lru
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit f9a0d86906754e9bcfc711e1fa63246554c02048
Author: Benjamin Bastian <benjamin.bast...@gmail.com>
AuthorDate: Fri Mar 17 11:47:29 2017 -0700

    Generalize couch_lru
    
    This commit makes couch_lru take a function which closes the database,
    thereby making couch_lru no longer be tightly coupled to couch_server.
    This change is necessary to be able to use couch_lru in
    couch_index_server for making an LRU for view indices.
---
 src/couch/include/couch_db.hrl     |  6 ++++
 src/couch/src/couch_lru.erl        | 67 ++++++++++++++++++--------------------
 src/couch/src/couch_server.erl     | 24 ++++++++++++--
 src/couch/test/couch_lru_tests.erl | 24 +++++++-------
 4 files changed, 71 insertions(+), 50 deletions(-)

diff --git a/src/couch/include/couch_db.hrl b/src/couch/include/couch_db.hrl
index e7cd85d..135a2ea 100644
--- a/src/couch/include/couch_db.hrl
+++ b/src/couch/include/couch_db.hrl
@@ -231,6 +231,12 @@
     atts = []
 }).
 
+-record(couch_lru, {
+    count=0,
+    updates,
+    counts,
+    close_fun
+}).
 
 -type doc() :: #doc{}.
 -type ddoc() :: #doc{}.
diff --git a/src/couch/src/couch_lru.erl b/src/couch/src/couch_lru.erl
index b79286e..91ffdcc 100644
--- a/src/couch/src/couch_lru.erl
+++ b/src/couch/src/couch_lru.erl
@@ -11,34 +11,36 @@
 % the License.
 
 -module(couch_lru).
--export([new/0, insert/2, update/2, close/1]).
+-export([new/1, insert/2, update/2, close/1]).
 
 -include_lib("couch/include/couch_db.hrl").
 
-new() ->
+new(CloseFun) ->
     Updates = ets:new(couch_lru_updates, [ordered_set]),
-    Dbs = ets:new(couch_lru_dbs, [set]),
-    {0, Updates, Dbs}.
+    Counts = ets:new(couch_lru_counts, [set]),
+    #couch_lru{updates=Updates, counts=Counts, close_fun=CloseFun}.
 
-insert(DbName, {Count, Updates, Dbs}) ->
-    update(DbName, {Count, Updates, Dbs}).
+insert(Name, Lru) ->
+    update(Name, Lru).
 
-update(DbName, {Count, Updates, Dbs}) ->
-    case ets:lookup(Dbs, DbName) of
+update(Name, Lru) ->
+    #couch_lru{counts=Counts, updates=Updates, count=Count} = Lru,
+    case ets:lookup(Counts, Name) of
         [] ->
-            true = ets:insert(Dbs, {DbName, Count});
-        [{DbName, OldCount}] ->
-            true = ets:update_element(Dbs, DbName, {2, Count}),
-            true = ets:delete(Updates, {OldCount, DbName})
+            true = ets:insert(Counts, {Name, Count});
+        [{Name, OldCount}] ->
+            true = ets:update_element(Counts, Name, {2, Count}),
+            true = ets:delete(Updates, {OldCount, Name})
     end,
-    true = ets:insert(Updates, {{Count, DbName}}),
-    {Count + 1, Updates, Dbs}.
+    true = ets:insert(Updates, {{Count, Name}}),
+    Lru#couch_lru{count=Count+1}.
 
 
-close({Count, Updates, Dbs}) ->
-    case close_int(ets:next(Updates, {-1, <<>>}), Updates, Dbs) of
+close(Lru) ->
+    #couch_lru{updates=Updates} = Lru,
+    case close_int(ets:next(Updates, {-1, <<>>}), Lru) of
         true ->
-            {true, {Count, Updates, Dbs}};
+            {true, Lru};
         false ->
             false
     end.
@@ -46,26 +48,19 @@ close({Count, Updates, Dbs}) ->
 
 %% internals
 
-close_int('$end_of_table', _Updates, _Dbs) ->
+close_int('$end_of_table', _Lru) ->
     false;
-close_int({_Count, DbName} = Key, Updates, Dbs) ->
-    case ets:update_element(couch_dbs, DbName, {#db.fd_monitor, locked}) of
-    true ->
-        [#db{main_pid = Pid} = Db] = ets:lookup(couch_dbs, DbName),
-        case couch_db:is_idle(Db) of true ->
-            true = ets:delete(couch_dbs, DbName),
-            true = ets:delete(couch_dbs_pid_to_name, Pid),
-            exit(Pid, kill),
+close_int({_Count, Name} = Key, Lru) ->
+    #couch_lru{updates=Updates, counts=Counts, close_fun=CloseFun} = Lru,
+    {Stop, Remove} = CloseFun(Name),
+    case Remove of
+        true ->
             true = ets:delete(Updates, Key),
-            true = ets:delete(Dbs, DbName),
-            true;
+            true = ets:delete(Counts, Name);
         false ->
-            true = ets:update_element(couch_dbs, DbName, {#db.fd_monitor, 
nil}),
-            couch_stats:increment_counter([couchdb, couch_server, lru_skip]),
-            close_int(ets:next(Updates, Key), Updates, Dbs)
-        end;
-    false ->
-        true = ets:delete(Updates, Key),
-        true = ets:delete(Dbs, DbName),
-        close_int(ets:next(Updates, Key), Updates, Dbs)
+            ok
+    end,
+    case Stop of
+        false -> close_int(ets:next(Updates, Key), Lru);
+        true -> true
     end.
diff --git a/src/couch/src/couch_server.erl b/src/couch/src/couch_server.erl
index 1152300..53dc9e1 100644
--- a/src/couch/src/couch_server.erl
+++ b/src/couch/src/couch_server.erl
@@ -20,7 +20,7 @@
 -export([init/1, handle_call/3,sup_start_link/0]).
 -export([handle_cast/2,code_change/3,handle_info/2,terminate/2]).
 -export([dev_start/0,is_admin/2,has_admins/0,get_stats/0]).
--export([close_lru/0]).
+-export([close_lru/0, maybe_close_db/1]).
 
 % config_listener api
 -export([handle_config_change/5, handle_config_terminate/3]).
@@ -36,7 +36,7 @@
     dbs_open=0,
     start_time="",
     update_lru_on_read=true,
-    lru = couch_lru:new()
+    lru = couch_lru:new(fun maybe_close_db/1)
     }).
 
 dev_start() ->
@@ -97,6 +97,26 @@ update_lru(DbName) ->
 close_lru() ->
     gen_server:call(couch_server, close_lru).
 
+maybe_close_db(DbName) ->
+    % First element of return indicates if we should stop closing DBs from the
+    % LRU and the second element indicates if we closed a DB.
+    case ets:update_element(couch_dbs, DbName, {#db.fd_monitor, locked}) of
+    true ->
+        [#db{main_pid = Pid} = Db] = ets:lookup(couch_dbs, DbName),
+        case couch_db:is_idle(Db) of true ->
+            true = ets:delete(couch_dbs, DbName),
+            true = ets:delete(couch_dbs_pid_to_name, Pid),
+            exit(Pid, kill),
+            {true, true};
+        false ->
+            true = ets:update_element(couch_dbs, DbName, {#db.fd_monitor, 
nil}),
+            couch_stats:increment_counter([couchdb, couch_server, lru_skip]),
+            {false, false}
+        end;
+    false ->
+        {false, true}
+    end.
+
 create(DbName, Options0) ->
     Options = maybe_add_sys_db_callbacks(DbName, Options0),
     case gen_server:call(couch_server, {create, DbName, Options}, infinity) of
diff --git a/src/couch/test/couch_lru_tests.erl 
b/src/couch/test/couch_lru_tests.erl
index 1559835..02a131c 100644
--- a/src/couch/test/couch_lru_tests.erl
+++ b/src/couch/test/couch_lru_tests.erl
@@ -20,7 +20,7 @@ setup() ->
     ok = meck:new(couch_db, [passthrough]),
     ets:new(couch_dbs, [set, public, named_table, {keypos, #db.name}]),
     ets:new(couch_dbs_pid_to_name, [set, public, named_table]),
-    couch_lru:new().
+    couch_lru:new(fun couch_server:maybe_close_db/1).
 
 teardown(_) ->
     ets:delete(couch_dbs),
@@ -29,18 +29,18 @@ teardown(_) ->
 
 new_test_() ->
     {setup,
-        fun() -> couch_lru:new() end,
+        fun() -> couch_lru:new(fun couch_server:maybe_close_db/1) end,
         fun(Lru) ->
-            ?_assertMatch({0, _, _}, Lru)
+            ?_assertEqual(0, Lru#couch_lru.count)
         end
     }.
 
 insert_test_() ->
     {setup,
-        fun() -> couch_lru:new() end,
+        fun() -> couch_lru:new(fun couch_server:maybe_close_db/1) end,
         fun(Lru) ->
             Key = <<"test">>,
-            {1, Updates, Dbs} = couch_lru:insert(Key, Lru),
+            #couch_lru{count=1, updates=Updates, counts=Dbs} = 
couch_lru:insert(Key, Lru),
             [
                 ?_assertEqual(1, ets_size(Dbs)),
                 ?_assert(ets:member(Dbs, Key)),
@@ -52,11 +52,11 @@ insert_test_() ->
 
 insert_same_test_() ->
     {setup,
-        fun() -> couch_lru:new() end,
+        fun() -> couch_lru:new(fun couch_server:maybe_close_db/1) end,
         fun(Lru) ->
             Key = <<"test">>,
-            Lru1 = {1, Updates, Dbs} = couch_lru:insert(Key, Lru),
-            {2, Updates, Dbs} = couch_lru:insert(Key, Lru1),
+            Lru1 = #couch_lru{count=1} = couch_lru:insert(Key, Lru),
+            #couch_lru{count=2, updates=Updates, counts=Dbs} = 
couch_lru:insert(Key, Lru1),
             [
                 ?_assertEqual(1, ets_size(Dbs)),
                 ?_assert(ets:member(Dbs, Key)),
@@ -68,11 +68,11 @@ insert_same_test_() ->
 
 update_test_() ->
     {setup,
-        fun() -> couch_lru:new() end,
+        fun() -> couch_lru:new(fun couch_server:maybe_close_db/1) end,
         fun(Lru) ->
             Key = <<"test">>,
-            Lru1 = {1, Updates, Dbs} = couch_lru:update(Key, Lru),
-            {2, Updates, Dbs} = couch_lru:update(Key, Lru1),
+            Lru1 = #couch_lru{count=1} = couch_lru:update(Key, Lru),
+            #couch_lru{count=2, updates=Updates, counts=Dbs} = 
couch_lru:update(Key, Lru1),
             [
                 ?_assertEqual(1, ets_size(Dbs)),
                 ?_assert(ets:member(Dbs, Key)),
@@ -90,7 +90,7 @@ close_test_() ->
             ok = meck:expect(couch_db, is_idle, 1, true),
             {ok, Lru1} = add_record(Lru, <<"test1">>, c:pid(0, 1001, 0)),
             {ok, Lru2} = add_record(Lru1, <<"test2">>, c:pid(0, 2001, 0)),
-            {true, {2, Updates, Dbs}} = couch_lru:close(Lru2),
+            {true, #couch_lru{count=2, updates=Updates, counts=Dbs}} = 
couch_lru:close(Lru2),
             [
                 ?_assertEqual(1, ets_size(Dbs)),
                 ?_assert(ets:member(Dbs, <<"test2">>)),

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <commits@couchdb.apache.org>.

Reply via email to