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>.