couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject [couchdb] 02/03: Generalize cache entry specific logic
Date Fri, 16 Jun 2017 21:40:28 GMT
This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch optimize-ddoc-cache
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 3615fa68f6ed7af834481a0b982b2dad0b81eeea
Author: Paul J. Davis <paul.joseph.davis@gmail.com>
AuthorDate: Fri Jun 16 15:18:28 2017 -0500

    Generalize cache entry specific logic
    
    There was a lot of guff going on with all of the various special cased
    function clauses to separate out different behavior. This makes things a
    lot more straight forward in terms of isolating the different logic.
    
    The one slight downside is that there's a somewhat complex change to how
    we manage evictions now that the ets table keys are opaque. Though on
    the plus side this changed turned an ets table scan into a set of O(1)
    khash lookups, so there's that at least.
    
    This will still not work in production as we're not kicking out entries
    when their existence changes. Patch three in this series will address
    that last detail.
---
 src/ddoc_cache/src/ddoc_cache.app.src              |   2 +-
 src/ddoc_cache/src/ddoc_cache.erl                  |  62 ++-------
 src/ddoc_cache/src/ddoc_cache_entry.erl            |  82 +++++++++++
 ...c_cache.app.src => ddoc_cache_entry_custom.erl} |  47 +++----
 ...c_cache.app.src => ddoc_cache_entry_ddocid.erl} |  50 ++++---
 ...che.app.src => ddoc_cache_entry_ddocid_rev.erl} |  52 ++++---
 ...pp.src => ddoc_cache_entry_validation_funs.erl} |  54 ++++----
 src/ddoc_cache/src/ddoc_cache_lru.erl              | 102 +++++++++-----
 src/ddoc_cache/src/ddoc_cache_opener.erl           | 150 +++------------------
 src/ddoc_cache/src/ddoc_cache_tables.erl           |   2 +-
 10 files changed, 280 insertions(+), 323 deletions(-)

diff --git a/src/ddoc_cache/src/ddoc_cache.app.src b/src/ddoc_cache/src/ddoc_cache.app.src
index 084895e..3b6617b 100644
--- a/src/ddoc_cache/src/ddoc_cache.app.src
+++ b/src/ddoc_cache/src/ddoc_cache.app.src
@@ -35,5 +35,5 @@
         couch_log,
         couch_stats
     ]},
-    {mod, {ddoc_cache_app, []}},
+    {mod, {ddoc_cache_app, []}}
 ]}.
diff --git a/src/ddoc_cache/src/ddoc_cache.erl b/src/ddoc_cache/src/ddoc_cache.erl
index 07d89ac..f9eea9f 100644
--- a/src/ddoc_cache/src/ddoc_cache.erl
+++ b/src/ddoc_cache/src/ddoc_cache.erl
@@ -33,66 +33,32 @@ start() ->
 stop() ->
     application:stop(ddoc_cache).
 
+
 open_doc(DbName, DocId) ->
-    Key = {DbName, DocId, '_'},
-    case ddoc_cache_opener:match_newest(Key) of
-        {ok, _} = Resp ->
-            couch_stats:increment_counter([ddoc_cache, hit]),
-            Resp;
-        missing ->
-            couch_stats:increment_counter([ddoc_cache, miss]),
-            ddoc_cache_opener:open_doc(DbName, DocId);
-        recover ->
-            couch_stats:increment_counter([ddoc_cache, recovery]),
-            ddoc_cache_opener:recover_doc(DbName, DocId)
-    end.
+    Key = {ddoc_cache_entry_ddocid, {DbName, DocId}},
+    ddoc_cache_opener:open(Key).
+
 
 open_doc(DbName, DocId, RevId) ->
-    Key = {DbName, DocId, RevId},
-    case ddoc_cache_opener:lookup(Key) of
-        {ok, _} = Resp ->
-            couch_stats:increment_counter([ddoc_cache, hit]),
-            Resp;
-        missing ->
-            couch_stats:increment_counter([ddoc_cache, miss]),
-            ddoc_cache_opener:open_doc(DbName, DocId, RevId);
-        recover ->
-            couch_stats:increment_counter([ddoc_cache, recovery]),
-            ddoc_cache_opener:recover_doc(DbName, DocId, RevId)
-    end.
+    Key = {ddoc_cache_entry_ddocid_rev, {DbName, DocId, RevId}},
+    ddoc_cache_opener:open(Key).
+
 
 open_validation_funs(DbName) ->
-    Key = {DbName, validation_funs},
-    case ddoc_cache_opener:lookup(Key) of
-        {ok, _} = Resp ->
-            couch_stats:increment_counter([ddoc_cache, hit]),
-            Resp;
-        missing ->
-            couch_stats:increment_counter([ddoc_cache, miss]),
-            ddoc_cache_opener:open_validation_funs(DbName);
-        recover ->
-            couch_stats:increment_counter([ddoc_cache, recovery]),
-            ddoc_cache_opener:recover_validation_funs(DbName)
-    end.
+    Key = {ddoc_cache_entry_validation_funs, DbName},
+    ddoc_cache_opener:open(Key).
+
 
 open_custom(DbName, Mod) ->
-    Key = {DbName, Mod},
-    case ddoc_cache_opener:lookup(Key) of
-        {ok, _} = Resp ->
-            couch_stats:increment_counter([ddoc_cache, hit]),
-            Resp;
-        missing ->
-            couch_stats:increment_counter([ddoc_cache, miss]),
-            ddoc_cache_opener:open_doc(DbName, Mod);
-        recover ->
-            couch_stats:increment_counter([ddoc_cache, recovery]),
-            Mod:recover(DbName)
-    end.
+    Key = {ddoc_cache_entry_custom, {DbName, Mod}},
+    ddoc_cache_opener:open(Key).
+
 
 evict(ShardDbName, DDocIds) ->
     DbName = mem3:dbname(ShardDbName),
     ddoc_cache_lru:evict(DbName, DDocIds).
 
+
 open(DbName, validation_funs) ->
     open_validation_funs(DbName);
 open(DbName, Module) when is_atom(Module) ->
diff --git a/src/ddoc_cache/src/ddoc_cache_entry.erl b/src/ddoc_cache/src/ddoc_cache_entry.erl
new file mode 100644
index 0000000..a1bcb3a
--- /dev/null
+++ b/src/ddoc_cache/src/ddoc_cache_entry.erl
@@ -0,0 +1,82 @@
+% Licensed 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.
+
+-module(ddoc_cache_entry).
+
+
+-export([
+    dbname/1,
+    ddocid/1,
+    spawn_link/1,
+    handle_resp/1,
+    open/1,
+    recover/1
+]).
+
+-export([
+    do_open/1,
+    do_open/2
+]).
+
+dbname({Mod, Arg}) ->
+    Mod:dbname(Arg).
+
+
+ddocid({Mod, Arg}) ->
+    Mod:ddocid(Arg).
+
+
+spawn_link(Key) ->
+    erlang:spawn_link(?MODULE, do_open, [Key]).
+
+
+handle_resp({open_ok, _Key, Resp}) ->
+    Resp;
+
+handle_resp({open_error, _Key, Type, Reason, Stack}) ->
+    erlang:raise(Type, Reason, Stack);
+
+handle_resp(Else) ->
+    erlang:error({ddoc_cache_entry, Else}).
+
+
+open(Key) ->
+    {_Pid, Ref} = erlang:spawn_monitor(?MODULE, do_open, [Key]),
+    receive
+        {'DOWN', Ref, _, _, {open_ok, Key, Resp}} ->
+            Resp;
+        {'DOWN', Ref, _, _, {open_error, Key, Class, Reason, Stack}} ->
+            erlang:raise(Class, Reason, Stack);
+        {'DOWN', Ref, _, _, Other} ->
+            erlang:error({ddoc_cache_entry, Other})
+    end.
+
+
+recover({Mod, Arg}) ->
+    Mod:recover(Arg).
+
+
+do_open(Key) ->
+    do_open(Key, false).
+
+
+do_open({Mod, Arg} = Key, DoInsert) ->
+    try Mod:recover(Arg) of
+        {ok, Resp} when DoInsert ->
+            ddoc_cache_lru:insert(Key, Resp),
+            erlang:exit({open_ok, Key, {ok, Resp}});
+        Resp ->
+            erlang:exit({open_ok, Key, Resp})
+    catch T:R ->
+        S = erlang:get_stacktrace(),
+        erlang:exit({open_error, Key, T, R, S})
+    end.
diff --git a/src/ddoc_cache/src/ddoc_cache.app.src b/src/ddoc_cache/src/ddoc_cache_entry_custom.erl
similarity index 50%
copy from src/ddoc_cache/src/ddoc_cache.app.src
copy to src/ddoc_cache/src/ddoc_cache_entry_custom.erl
index 084895e..d858ad6 100644
--- a/src/ddoc_cache/src/ddoc_cache.app.src
+++ b/src/ddoc_cache/src/ddoc_cache_entry_custom.erl
@@ -10,30 +10,23 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
-{application, ddoc_cache, [
-    {description, "Design Document Cache"},
-    {vsn, git},
-    {modules, [
-        ddoc_cache,
-        ddoc_cache_app,
-        ddoc_cache_opener,
-        ddoc_cache_sup,
-        ddoc_cache_util
-    ]},
-    {registered, [
-        ddoc_cache_tables,
-        ddoc_cache_lru,
-        ddoc_cache_opener
-    ]},
-    {applications, [
-        kernel,
-        stdlib,
-        crypto,
-        couch_event,
-        mem3,
-        fabric,
-        couch_log,
-        couch_stats
-    ]},
-    {mod, {ddoc_cache_app, []}},
-]}.
+-module(ddoc_cache_entry_custom).
+
+
+-export([
+    dbname/1,
+    ddocid/1,
+    recover/1
+]).
+
+
+dbname({DbName, _}) ->
+    DbName.
+
+
+ddocid(_) ->
+    no_ddocid.
+
+
+recover({DbName, Mod}) ->
+    Mod:recover(DbName).
diff --git a/src/ddoc_cache/src/ddoc_cache.app.src b/src/ddoc_cache/src/ddoc_cache_entry_ddocid.erl
similarity index 50%
copy from src/ddoc_cache/src/ddoc_cache.app.src
copy to src/ddoc_cache/src/ddoc_cache_entry_ddocid.erl
index 084895e..cac9abc 100644
--- a/src/ddoc_cache/src/ddoc_cache.app.src
+++ b/src/ddoc_cache/src/ddoc_cache_entry_ddocid.erl
@@ -10,30 +10,26 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
-{application, ddoc_cache, [
-    {description, "Design Document Cache"},
-    {vsn, git},
-    {modules, [
-        ddoc_cache,
-        ddoc_cache_app,
-        ddoc_cache_opener,
-        ddoc_cache_sup,
-        ddoc_cache_util
-    ]},
-    {registered, [
-        ddoc_cache_tables,
-        ddoc_cache_lru,
-        ddoc_cache_opener
-    ]},
-    {applications, [
-        kernel,
-        stdlib,
-        crypto,
-        couch_event,
-        mem3,
-        fabric,
-        couch_log,
-        couch_stats
-    ]},
-    {mod, {ddoc_cache_app, []}},
-]}.
+-module(ddoc_cache_entry_ddocid).
+
+
+-export([
+    dbname/1,
+    ddocid/1,
+    recover/1
+]).
+
+
+-include_lib("couch/include/couch_db.hrl").
+
+
+dbname({DbName, _}) ->
+    DbName.
+
+
+ddocid({_, DDocId}) ->
+    DDocId.
+
+
+recover({DbName, DDocId}) ->
+    fabric:open_doc(DbName, DDocId, [ejson_body, ?ADMIN_CTX]).
diff --git a/src/ddoc_cache/src/ddoc_cache.app.src b/src/ddoc_cache/src/ddoc_cache_entry_ddocid_rev.erl
similarity index 50%
copy from src/ddoc_cache/src/ddoc_cache.app.src
copy to src/ddoc_cache/src/ddoc_cache_entry_ddocid_rev.erl
index 084895e..012abab 100644
--- a/src/ddoc_cache/src/ddoc_cache.app.src
+++ b/src/ddoc_cache/src/ddoc_cache_entry_ddocid_rev.erl
@@ -10,30 +10,28 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
-{application, ddoc_cache, [
-    {description, "Design Document Cache"},
-    {vsn, git},
-    {modules, [
-        ddoc_cache,
-        ddoc_cache_app,
-        ddoc_cache_opener,
-        ddoc_cache_sup,
-        ddoc_cache_util
-    ]},
-    {registered, [
-        ddoc_cache_tables,
-        ddoc_cache_lru,
-        ddoc_cache_opener
-    ]},
-    {applications, [
-        kernel,
-        stdlib,
-        crypto,
-        couch_event,
-        mem3,
-        fabric,
-        couch_log,
-        couch_stats
-    ]},
-    {mod, {ddoc_cache_app, []}},
-]}.
+-module(ddoc_cache_entry_ddocid_rev).
+
+
+-export([
+    dbname/1,
+    ddocid/1,
+    recover/1
+]).
+
+
+-include_lib("couch/include/couch_db.hrl").
+
+
+dbname({DbName, _, _}) ->
+    DbName.
+
+
+ddocid({_, DDocId, _}) ->
+    DDocId.
+
+
+recover({DbName, DDocId, Rev}) ->
+    Opts = [ejson_body, ?ADMIN_CTX],
+    {ok, [Resp]} = fabric:open_revs(DbName, DDocId, [Rev], Opts),
+    Resp.
diff --git a/src/ddoc_cache/src/ddoc_cache.app.src b/src/ddoc_cache/src/ddoc_cache_entry_validation_funs.erl
similarity index 50%
copy from src/ddoc_cache/src/ddoc_cache.app.src
copy to src/ddoc_cache/src/ddoc_cache_entry_validation_funs.erl
index 084895e..3d43f7a 100644
--- a/src/ddoc_cache/src/ddoc_cache.app.src
+++ b/src/ddoc_cache/src/ddoc_cache_entry_validation_funs.erl
@@ -10,30 +10,30 @@
 % License for the specific language governing permissions and limitations under
 % the License.
 
-{application, ddoc_cache, [
-    {description, "Design Document Cache"},
-    {vsn, git},
-    {modules, [
-        ddoc_cache,
-        ddoc_cache_app,
-        ddoc_cache_opener,
-        ddoc_cache_sup,
-        ddoc_cache_util
-    ]},
-    {registered, [
-        ddoc_cache_tables,
-        ddoc_cache_lru,
-        ddoc_cache_opener
-    ]},
-    {applications, [
-        kernel,
-        stdlib,
-        crypto,
-        couch_event,
-        mem3,
-        fabric,
-        couch_log,
-        couch_stats
-    ]},
-    {mod, {ddoc_cache_app, []}},
-]}.
+-module(ddoc_cache_entry_validation_funs).
+
+
+-export([
+    dbname/1,
+    ddocid/1,
+    recover/1
+]).
+
+
+dbname(DbName) ->
+    DbName.
+
+
+ddocid(_) ->
+    no_ddocid.
+
+
+recover(DbName) ->
+    {ok, DDocs} = fabric:design_docs(mem3:dbname(DbName)),
+    Funs = lists:flatmap(fun(DDoc) ->
+        case couch_doc:get_validate_doc_fun(DDoc) of
+            nil -> [];
+            Fun -> [Fun]
+        end
+    end, DDocs),
+    {ok, Funs}.
diff --git a/src/ddoc_cache/src/ddoc_cache_lru.erl b/src/ddoc_cache/src/ddoc_cache_lru.erl
index 9d8c397..ce53d1d 100644
--- a/src/ddoc_cache/src/ddoc_cache_lru.erl
+++ b/src/ddoc_cache/src/ddoc_cache_lru.erl
@@ -20,7 +20,6 @@
 
     insert/2,
     accessed/1,
-    evict/1,
     evict/2
 ]).
 
@@ -42,7 +41,8 @@
 
 
 -record(st, {
-    keys,
+    keys, % key -> time
+    dbs, % dbname -> docid -> key -> []
     time,
     max_size,
     evictor
@@ -54,7 +54,7 @@ start_link() ->
 
 
 insert(Key, Val) ->
-    gen_server:call(?MODULE, {insert, Key}).
+    gen_server:call(?MODULE, {insert, Key, Val}).
 
 
 accessed(Key) ->
@@ -68,12 +68,14 @@ evict(DbName, DDocIds) ->
 
 init(_) ->
     {ok, Keys} = khash:new(),
+    {ok, Dbs} = khash:new(),
     {ok, Evictor} = couch_event:link_listener(
             ?MODULE, handle_db_event, nil, [all_dbs]
         ),
     MaxSize = config:get_integer("ddoc_cache", "max_size", 1000),
     {ok, #st{
         keys = Keys,
+        dbs = Dbs,
         time = 0,
         max_size = MaxSize,
         evictor = Evictor
@@ -91,19 +93,21 @@ terminate(_Reason, St) ->
 handle_call({insert, Key, Val}, _From, St) ->
     #st{
         keys = Keys,
+        dbs = Dbs,
         time = Time
     } = St,
     NewTime = Time + 1,
     true = ets:insert(?CACHE, #entry{key = Key, val = Val}),
     true = ets:insert(?ATIMES, {NewTime, Key}),
     ok = khash:put(Keys, NewTime),
+    store_key(Dbs, Key),
     {reply, ok, trim(St#st{time = NewTime})};
 
 handle_call(Msg, _From, St) ->
     {stop, {invalid_call, Msg}, {invalid_call, Msg}, St}.
 
 
-handle_cast({accessed, Key}, _St) ->
+handle_cast({accessed, Key}, St) ->
     #st{
         keys = Keys,
         time = Time
@@ -129,36 +133,51 @@ handle_cast({evict, _, _} = Msg, St) ->
     gen_server:abcast(mem3:nodes(), ?MODULE, Msg),
     {noreply, St};
 
-handle_cast({do_evict, DbName} = Msg, St) ->
-    Pattern = #entry{
-        key = {DbName, '$1', '_'},
-        val = '_',
-        _ = '_'
-    },
-    DDocIds = lists:flatten(ets:match(?CACHE, Pattern)),
-    handle_cast({do_evict, DbName, DDocIds});
+handle_cast({do_evict, DbName}, St) ->
+    #st{
+        keys = KeyTimes,
+        dbs = Dbs
+    } = St,
+    case khash:lookup(Dbs, DbName) of
+        {value, DDocIds} ->
+            khash:fold(DDocIds, fun(_, Keys, _) ->
+                khash:fold(Keys, fun(Key, _, _) ->
+                    {value, Time} = khash:lookup(KeyTimes, Key),
+                    remove(St, Time)
+                end, nil)
+            end, nil),
+            khash:del(Dbs, DbName);
+        not_found ->
+            ok
+    end,
+    {noreply, St};
 
 handle_cast({do_evict, DbName, DDocIds}, St) ->
-    Pattern = #entry{
-        key = {DbName, '$1'},
-        val = '_',
-        _ = '_'
-    },
-    CustomKeys = lists:flatten(ets:match(?CACHE, Pattern)),
-    lists:foreach(fun(Mod) ->
-        ets:delete(?CACHE, {DbName, Mod})
-    end, CustomKeys),
-    lists:foreach(fun(DDocId) ->
-        RevPattern = #entry{
-            key = {DbName, DDocId, '$1'},
-            val = '_',
-            _ = '_'
-        },
-        Revs = lists:flatten(ets:match(?CACHE, RevPattern)),
-        lists:foreach(fun(Rev) ->
-            ets:delete(?CACHE, {DbName, DDocId, Rev})
-        end, Revs)
-    end, DDocIds),
+    #st{
+        keys = KeyTimes,
+        dbs = Dbs
+    } = St,
+    case khash:lookup(Dbs, DbName) of
+        {value, DDocIds} ->
+            lists:foreach(fun(DDocId) ->
+                case khash:lookup(DDocIds, DDocId) of
+                    {value, Keys} ->
+                        khash:fold(Keys, fun(Key, _, _) ->
+                            {value, Time} = khash:lookup(KeyTimes, Key),
+                            remove(St, Time)
+                        end, nil);
+                    not_found ->
+                        ok
+                end,
+                khash:del(DDocIds, DDocId)
+            end, [no_ddocid | DDocIds]),
+            case khash:size(DDocIds) of
+                0 -> khash:del(Dbs, DbName);
+                _ -> ok
+            end;
+        not_found ->
+            ok
+    end,
     {noreply, St};
 
 handle_cast(Msg, St) ->
@@ -192,6 +211,25 @@ handle_db_event(_DbName, _Event, St) ->
     {ok, St}.
 
 
+store_key(Dbs, Key) ->
+    DbName = ddoc_cache_entry:dbname(Key),
+    DDocId = ddoc_cache_entry:ddocid(Key),
+    case khash:lookup(Dbs, DbName) of
+        {value, DDocIds} ->
+            case khash:lookup(DDocIds, DDocId) of
+                {value, Keys} ->
+                    khash:put(Keys, Key, []);
+                not_found ->
+                    {ok, Keys} = khash:from_list([{Key, []}]),
+                    khash:put(DDocIds, DDocId, Keys)
+            end;
+        not_found ->
+            {ok, Keys} = khash:from_list([{Key, []}]),
+            {ok, DDocIds} = khash:from_list([{DDocId, Keys}]),
+            khash:put(Dbs, DDocId, DDocIds)
+    end.
+
+
 trim(St) ->
     #st{
         keys = Keys,
diff --git a/src/ddoc_cache/src/ddoc_cache_opener.erl b/src/ddoc_cache/src/ddoc_cache_opener.erl
index a4adffc..654a98a 100644
--- a/src/ddoc_cache/src/ddoc_cache_opener.erl
+++ b/src/ddoc_cache/src/ddoc_cache_opener.erl
@@ -32,17 +32,7 @@
 ]).
 
 -export([
-    open_doc/2,
-    open_doc/3,
-    open_validation_funs/1,
-    lookup/1,
-    match_newest/1,
-    recover_doc/2,
-    recover_doc/3,
-    recover_validation_funs/1
-]).
--export([
-    fetch_doc_data/1
+    open/1
 ]).
 
 -include("ddoc_cache.hrl").
@@ -58,75 +48,22 @@
 start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 
--spec open_doc(dbname(), docid()) -> {ok, #doc{}}.
-open_doc(DbName, DocId) ->
-    Resp = gen_server:call(?MODULE, {open, {DbName, DocId}}, infinity),
-    handle_open_response(Resp).
-
--spec open_doc(dbname(), docid(), revision()) -> {ok, #doc{}}.
-open_doc(DbName, DocId, Rev) ->
-    Resp = gen_server:call(?MODULE, {open, {DbName, DocId, Rev}}, infinity),
-    handle_open_response(Resp).
-
--spec open_validation_funs(dbname()) -> {ok, [fun()]}.
-open_validation_funs(DbName) ->
-    Resp = gen_server:call(?MODULE, {open, {DbName, validation_funs}}, infinity),
-    handle_open_response(Resp).
 
-
-lookup(Key) ->
-    try ets:lookup(?CACHE, Key) of
-        [#entry{key = Key, val = Val}] ->
+open(Key) ->
+    case ets:lookup(?CACHE, Key) of
+        [#entry{val = Val}] ->
+            couch_stats:increment_counter([ddoc_cache, hit]),
             ddoc_cache_lru:accessed(Key),
             {ok, Val};
-        _ ->
-            missing
-    catch
-        error:badarg ->
-            recover
-    end.
-
-match_newest(Key) ->
-    Pattern = #entry{
-        key = Key,
-        val = '_',
-        _ = '_'
-    },
-    try ets:match_object(?CACHE, Pattern) of
         [] ->
-            missing;
-        Entries ->
-            Docs = lists:map(fun(#entry{key = K, val = V}) ->
-                ddoc_cache_lru:accessed(K),
-                V
-            end, Entries),
-            Sorted = lists:sort(
-                fun (#doc{deleted=DelL, revs=L}, #doc{deleted=DelR, revs=R}) ->
-                    {not DelL, L} > {not DelR, R}
-                end, Docs),
-            {ok, hd(Sorted)}
-    catch
-        error:badarg ->
-            recover
+            couch_stats:increment_counter([ddoc_cache, miss]),
+            Resp = gen_server:call(?MODULE, {open, Key}, infinity),
+            ddoc_cache_entry:handle_resp(Resp);
+        recover ->
+            couch_stats:increment_counter([ddoc_cache, recovery]),
+            ddoc_cache_entry:open(Key)
     end.
 
-recover_doc(DbName, DDocId) ->
-    fabric:open_doc(DbName, DDocId, [ejson_body, ?ADMIN_CTX]).
-
-recover_doc(DbName, DDocId, Rev) ->
-    {ok, [Resp]} = fabric:open_revs(DbName, DDocId, [Rev], [ejson_body, ?ADMIN_CTX]),
-    Resp.
-
-recover_validation_funs(DbName) ->
-    {ok, DDocs} = fabric:design_docs(mem3:dbname(DbName)),
-    Funs = lists:flatmap(fun(DDoc) ->
-        case couch_doc:get_validate_doc_fun(DDoc) of
-            nil -> [];
-            Fun -> [Fun]
-        end
-    end, DDocs),
-    {ok, Funs}.
-
 
 init(_) ->
     process_flag(trap_exit, true),
@@ -141,7 +78,7 @@ handle_call({open, OpenerKey}, From, St) ->
             ets:insert(?OPENERS, O#opener{clients=[From | Clients]}),
             {noreply, St};
         [] ->
-            Pid = spawn_link(?MODULE, fetch_doc_data, [OpenerKey]),
+            Pid = ddoc_cache_entry:spawn_link(OpenerKey),
             ets:insert(?OPENERS, #opener{key=OpenerKey, pid=Pid, clients=[From]}),
             {noreply, St}
     end;
@@ -156,8 +93,8 @@ handle_cast({do_evict, _} = Msg, St) ->
     gen_server:cast(?LRU, Msg),
     {noreply, St};
 
-handle_cast({do_evict, _, _}, St) ->
-    gen_server:cast(?LRU, Msg)
+handle_cast({do_evict, _, _} = Msg, St) ->
+    gen_server:cast(?LRU, Msg),
     {noreply, St};
 
 handle_cast(Msg, St) ->
@@ -168,8 +105,8 @@ handle_info({'EXIT', _Pid, {open_ok, OpenerKey, Resp}}, St) ->
     respond(OpenerKey, {open_ok, Resp}),
     {noreply, St};
 
-handle_info({'EXIT', _Pid, {open_error, OpenerKey, Type, Error}}, St) ->
-    respond(OpenerKey, {open_error, Type, Error}),
+handle_info({'EXIT', _Pid, {open_error, OpenerKey, Type, Reason, Stack}}, St) ->
+    respond(OpenerKey, {open_error, Type, Reason, Stack}),
     {noreply, St};
 
 handle_info({'EXIT', Pid, Reason}, St) ->
@@ -189,61 +126,8 @@ handle_info(Msg, St) ->
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
--spec fetch_doc_data({dbname(), validation_funs}) -> no_return();
-                    ({dbname(), atom()}) -> no_return();
-                    ({dbname(), docid()}) -> no_return();
-                    ({dbname(), docid(), revision()}) -> no_return().
-fetch_doc_data({DbName, validation_funs}=OpenerKey) ->
-    {ok, Funs} = recover_validation_funs(DbName),
-    ok = ddoc_cache_lru:insert(OpenerKey, Funs),
-    exit({open_ok, OpenerKey, {ok, Funs}});
-fetch_doc_data({DbName, Mod}=OpenerKey) when is_atom(Mod) ->
-    % This is not actually a docid but rather a custom cache key.
-    % Treat the argument as a code module and invoke its recover function.
-    try Mod:recover(DbName) of
-        {ok, Result} ->
-            ok = ddoc_cache_lru:insert(OpenerKey, Result),
-            exit({open_ok, OpenerKey, {ok, Result}});
-        Else ->
-            exit({open_ok, OpenerKey, Else})
-    catch
-        Type:Reason ->
-            exit({open_error, OpenerKey, Type, Reason})
-    end;
-fetch_doc_data({DbName, DocId}=OpenerKey) ->
-    try recover_doc(DbName, DocId) of
-        {ok, Doc} ->
-            {RevDepth, [RevHash| _]} = Doc#doc.revs,
-            Rev = {RevDepth, RevHash},
-            ok = ddoc_cache_lru:insert({DbName, DocId, Rev}, Doc),
-            exit({open_ok, OpenerKey, {ok, Doc}});
-        Else ->
-            exit({open_ok, OpenerKey, Else})
-    catch
-        Type:Reason ->
-            exit({open_error, OpenerKey, Type, Reason})
-    end;
-fetch_doc_data({DbName, DocId, Rev}=OpenerKey) ->
-    try recover_doc(DbName, DocId, Rev) of
-        {ok, Doc} ->
-            ok = ddoc_cache_lru:insert({DbName, DocId, Rev}, Doc),
-            exit({open_ok, OpenerKey, {ok, Doc}});
-        Else ->
-            exit({open_ok, OpenerKey, Else})
-    catch
-        Type:Reason ->
-            exit({open_error, OpenerKey, Type, Reason})
-    end.
-
-handle_open_response(Resp) ->
-    case Resp of
-        {open_ok, Value} -> Value;
-        {open_error, throw, Error} -> throw(Error);
-        {open_error, error, Error} -> erlang:error(Error);
-        {open_error, exit, Error} -> exit(Error)
-    end.
 
 respond(OpenerKey, Resp) ->
     [#opener{clients=Clients}] = ets:lookup(?OPENERS, OpenerKey),
-    _ = [gen_server:reply(C, Resp) || C <- Clients],
+    [gen_server:reply(C, Resp) || C <- Clients],
     ets:delete(?OPENERS, OpenerKey).
diff --git a/src/ddoc_cache/src/ddoc_cache_tables.erl b/src/ddoc_cache/src/ddoc_cache_tables.erl
index 9b35943..86cc9b3 100644
--- a/src/ddoc_cache/src/ddoc_cache_tables.erl
+++ b/src/ddoc_cache/src/ddoc_cache_tables.erl
@@ -40,7 +40,7 @@ init(_) ->
     BaseOpts = [public, named_table],
     ets:new(?CACHE, [set, {read_concurrency, true}] ++ BaseOpts),
     ets:new(?ATIMES, [sorted_set] ++ BaseOpts),
-    ets:new(?OPENING, [set, {keypos, #opener.key}] ++ BaseOpts),
+    ets:new(?OPENERS, [set, {keypos, #opener.key}] ++ BaseOpts),
     {ok, nil}.
 
 

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

Mime
View raw message