You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/05/24 19:57:35 UTC

[couchdb] branch prototype/rfc-001-revision-metadata-model updated: Implement VDU functions

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

davisp pushed a commit to branch prototype/rfc-001-revision-metadata-model
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/prototype/rfc-001-revision-metadata-model by this push:
     new abd5d86  Implement VDU functions
abd5d86 is described below

commit abd5d86b5c673dcf638405fc7fe10c29577eb96d
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Fri May 24 14:57:19 2019 -0500

    Implement VDU functions
---
 src/couch/src/couch_att.erl                    |   9 +-
 src/fabric/src/fabric2.hrl                     |   1 +
 src/fabric/src/fabric2_db.erl                  |  55 +++++----
 src/fabric/src/fabric2_fdb.erl                 | 154 +++++++++++++++++++++----
 src/fabric/test/fabric2_changes_fold_tests.erl |  37 +++---
 src/fabric/test/fabric2_db_misc_tests.erl      |   2 +-
 src/fabric/test/fabric2_doc_fold_tests.erl     |  22 ++--
 7 files changed, 196 insertions(+), 84 deletions(-)

diff --git a/src/couch/src/couch_att.erl b/src/couch/src/couch_att.erl
index 924b58d..0dc5fa5 100644
--- a/src/couch/src/couch_att.erl
+++ b/src/couch/src/couch_att.erl
@@ -400,9 +400,12 @@ flush(Db, DocId, Att1) ->
             % Already flushed
             Att1;
         _ when is_binary(Data) ->
-            IdentityMd5 = get_identity_md5(Data, fetch(encoding, Att4)),
-            couch_util:check_md5(IdentityMd5, ReqMd5),
-            fabric2_db:write_attachment(Db, DocId, Att4)
+            IdentMd5 = get_identity_md5(Data, fetch(encoding, Att4)),
+            if ReqMd5 == undefined -> ok; true ->
+                couch_util:check_md5(IdentMd5, ReqMd5)
+            end,
+            Att5 = store(md5, IdentMd5, Att4),
+            fabric2_db:write_attachment(Db, DocId, Att5)
     end.
 
 
diff --git a/src/fabric/src/fabric2.hrl b/src/fabric/src/fabric2.hrl
index 2d6778d..de1d3d1 100644
--- a/src/fabric/src/fabric2.hrl
+++ b/src/fabric/src/fabric2.hrl
@@ -57,6 +57,7 @@
 
 -define(PDICT_DB_KEY, '$fabric_db_handle').
 -define(PDICT_LAYER_CACHE, '$fabric_layer_id').
+-define(PDICT_CHECKED_DB_IS_CURRENT, '$fabric_checked_db_is_current').
 -define(PDICT_TX_ID_KEY, '$fabric_tx_id').
 -define(PDICT_TX_RES_KEY, '$fabric_tx_result').
 -define(COMMIT_UNKNOWN_RESULT, 1021).
diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index 230cec0..18f358e 100644
--- a/src/fabric/src/fabric2_db.erl
+++ b/src/fabric/src/fabric2_db.erl
@@ -563,17 +563,31 @@ update_docs(Db, Docs, Options) ->
                 end)
             end, Docs)
     end,
-    Status = lists:foldl(fun(Resp, Acc) ->
+    % Convert errors
+    Resps1 = lists:map(fun(Resp) ->
         case Resp of
-            {ok, _} -> Acc;
-            _ -> error
+            {#doc{} = Doc, Error} ->
+                #doc{
+                    id = DocId,
+                    revs = {RevPos, [Rev | _]}
+                } = Doc,
+                {{DocId, {RevPos, Rev}}, Error};
+            Else ->
+                Else
         end
-    end, ok, Resps0),
-    Resps1 = case lists:member(replicated_changes, Options) of
-        true -> [R || R <- Resps0, R /= {ok, []}];
-        false -> Resps0
-    end,
-    {Status, Resps1}.
+    end, Resps0),
+    case lists:member(replicated_changes, Options) of
+        true ->
+            {ok, [R || R <- Resps1, R /= {ok, []}]};
+        false ->
+            Status = lists:foldl(fun(Resp, Acc) ->
+                case Resp of
+                    {ok, _} -> Acc;
+                    _ -> error
+                end
+            end, ok, Resps1),
+            {Status, Resps1}
+    end.
 
 
 read_attachment(Db, DocId, AttId) ->
@@ -1164,28 +1178,25 @@ prep_and_validate(Db, NewDoc, PrevRevInfo) ->
 validate_doc_update(Db, #doc{id = <<"_design/", _/binary>>} = Doc, _) ->
     case catch check_is_admin(Db) of
         ok -> validate_ddoc(Db, Doc);
-        Error -> ?RETURN(Error)
+        Error -> ?RETURN({Doc, Error})
     end;
 validate_doc_update(Db, Doc, PrevDoc) ->
     #{
         security_doc := Security,
-        user_ctx := UserCtx,
         validate_doc_update_funs := VDUs
     } = Db,
     Fun = fun() ->
-        JsonCtx = fabric2_util:user_ctx_to_json(UserCtx),
-        try
-            lists:map(fun(VDU) ->
+        JsonCtx = fabric2_util:user_ctx_to_json(Db),
+        lists:map(fun(VDU) ->
+            try
                 case VDU(Doc, PrevDoc, JsonCtx, Security) of
                     ok -> ok;
-                    Error -> ?RETURN(Error)
+                    Error1 -> throw(Error1)
                 end
-            end, VDUs),
-            ok
-        catch
-            throw:Error ->
-                Error
-        end
+            catch throw:Error2 ->
+                ?RETURN({Doc, Error2})
+            end
+        end, VDUs)
     end,
     Stat = [couchdb, query_server, vdu_process_time],
     if VDUs == [] -> ok; true ->
@@ -1202,7 +1213,7 @@ validate_ddoc(Db, DDoc) ->
         throw:{compilation_error, Reason} ->
             throw({bad_request, compilation_error, Reason});
         throw:Error ->
-            ?RETURN(Error)
+            ?RETURN({DDoc, Error})
     end.
 
 
diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index 9a6f6e9..0a4f298 100644
--- a/src/fabric/src/fabric2_fdb.erl
+++ b/src/fabric/src/fabric2_fdb.erl
@@ -40,6 +40,8 @@
     get_non_deleted_rev/3,
 
     get_doc_body/3,
+    get_doc_body_future/3,
+    get_doc_body_wait/4,
     get_local_doc/2,
 
     write_doc/6,
@@ -110,7 +112,7 @@ create(#{} = Db0, Options) ->
         name := DbName,
         tx := Tx,
         layer_prefix := LayerPrefix
-    } = Db = ensure_current(Db0),
+    } = Db = ensure_current(Db0, false),
 
     % Eventually DbPrefix will be HCA allocated. For now
     % we're just using the DbName so that debugging is easier.
@@ -170,7 +172,7 @@ open(#{} = Db0, Options) ->
         name := DbName,
         tx := Tx,
         layer_prefix := LayerPrefix
-    } = Db1 = ensure_current(Db0),
+    } = Db1 = ensure_current(Db0, false),
 
     DbKey = erlfdb_tuple:pack({?ALL_DBS, DbName}, LayerPrefix),
     DbPrefix = case erlfdb:wait(erlfdb:get(Tx, DbKey)) of
@@ -193,14 +195,14 @@ open(#{} = Db0, Options) ->
 
         % Place holders until we implement these
         % bits.
-        validate_doc_upate_funs => [],
+        validate_doc_update_funs => [],
         before_doc_update => undefined,
         after_doc_read => undefined,
 
         db_options => Options
     },
 
-    lists:foldl(fun({Key, Val}, DbAcc) ->
+    Db3 = lists:foldl(fun({Key, Val}, DbAcc) ->
         case Key of
             <<"uuid">> ->
                 DbAcc#{uuid => Val};
@@ -209,7 +211,9 @@ open(#{} = Db0, Options) ->
             <<"security_doc">> ->
                 DbAcc#{security_doc => ?JSON_DECODE(Val)}
         end
-    end, Db2, get_config(Db2)).
+    end, Db2, get_config(Db2)),
+
+    load_validate_doc_funs(Db3).
 
 
 reopen(#{} = OldDb) ->
@@ -241,7 +245,7 @@ exists(#{name := DbName} = Db) when is_binary(DbName) ->
     #{
         tx := Tx,
         layer_prefix := LayerPrefix
-    } = ensure_current(Db),
+    } = ensure_current(Db, false),
 
     DbKey = erlfdb_tuple:pack({?ALL_DBS, DbName}, LayerPrefix),
     case erlfdb:wait(erlfdb:get(Tx, DbKey)) of
@@ -426,19 +430,34 @@ get_non_deleted_rev(#{} = Db, DocId, RevId) ->
     end.
 
 
-get_doc_body(#{} = Db0, DocId, RevInfo) ->
+get_doc_body(Db, DocId, RevInfo) ->
+    Future = get_doc_body_future(Db, DocId, RevInfo),
+    get_doc_body_wait(Db, DocId, RevInfo, Future).
+
+
+get_doc_body_future(#{} = Db, DocId, RevInfo) ->
     #{
         tx := Tx,
         db_prefix := DbPrefix
-    } = Db = ensure_current(Db0),
+    } = ensure_current(Db),
+
+    #{
+        rev_id := {RevPos, Rev}
+    } = RevInfo,
+
+    Key = erlfdb_tuple:pack({?DB_DOCS, DocId, RevPos, Rev}, DbPrefix),
+    erlfdb:get(Tx, Key).
+
+
+get_doc_body_wait(#{} = Db0, DocId, RevInfo, Future) ->
+    Db = ensure_current(Db0),
 
     #{
         rev_id := {RevPos, Rev},
         rev_path := RevPath
     } = RevInfo,
 
-    Key = erlfdb_tuple:pack({?DB_DOCS, DocId, RevPos, Rev}, DbPrefix),
-    Val = erlfdb:wait(erlfdb:get(Tx, Key)),
+    Val = erlfdb:wait(Future),
     fdb_to_doc(Db, DocId, RevPos, [Rev | RevPath], Val).
 
 
@@ -530,6 +549,10 @@ write_doc(#{} = Db0, Doc, NewWinner0, OldWinner, ToUpdate, ToRemove) ->
         _ -> false
     end,
 
+    if not IsDDoc -> ok; true ->
+        bump_db_version(Db)
+    end,
+
     case UpdateStatus of
         created ->
             if not IsDDoc -> ok; true ->
@@ -629,7 +652,7 @@ fold_docs(#{} = Db, UserFun, UserAcc0, Options) ->
     DocCountBin = erlfdb:wait(erlfdb:get(Tx, DocCountKey)),
 
     try
-        UserAcc1 = maybe_stop(UserFun(Db, {meta, [
+        UserAcc1 = maybe_stop(UserFun({meta, [
             {total, ?bin2uint(DocCountBin)},
             {offset, null}
         ]}, UserAcc0)),
@@ -637,14 +660,14 @@ fold_docs(#{} = Db, UserFun, UserAcc0, Options) ->
         UserAcc2 = erlfdb:fold_range(Tx, Start, End, fun({K, V}, UserAccIn) ->
             {?DB_ALL_DOCS, DocId} = erlfdb_tuple:unpack(K, DbPrefix),
             RevId = erlfdb_tuple:unpack(V),
-            maybe_stop(UserFun(Db, {row, [
+            maybe_stop(UserFun({row, [
                 {id, DocId},
                 {key, DocId},
                 {value, couch_doc:rev_to_str(RevId)}
             ]}, UserAccIn))
         end, UserAcc1, [{reverse, Reverse}] ++ Options),
 
-        {ok, maybe_stop(UserFun(Db, complete, UserAcc2))}
+        {ok, maybe_stop(UserFun(complete, UserAcc2))}
     catch throw:{stop, FinalUserAcc} ->
         {ok, FinalUserAcc}
     end.
@@ -705,7 +728,7 @@ get_last_change(#{} = Db) ->
     Options = [{limit, 1}, {reverse, true}],
     case erlfdb:get_range(Tx, Start, End, Options) of
         [] ->
-            fabric2_util:to_hex(fabric2_util:seq_zero());
+            vs_to_seq(fabric2_util:seq_zero_vs());
         [{K, _V}] ->
             {?DB_CHANGES, SeqVS} = erlfdb_tuple:unpack(K, DbPrefix),
             vs_to_seq(SeqVS)
@@ -753,6 +776,64 @@ init_db(Tx, DbName, Options) ->
     }.
 
 
+load_validate_doc_funs(#{} = Db) ->
+    FoldFun = fun
+        ({row, Row}, Acc) ->
+            DDocInfo = #{id => fabric2_util:get_value(id, Row)},
+            {ok, [DDocInfo | Acc]};
+        (_, Acc) ->
+            {ok, Acc}
+    end,
+
+    Options = [
+        {start_key, <<"_design/">>},
+        {end_key, <<"_design0">>}
+    ],
+
+    {ok, Infos1} = fold_docs(Db, FoldFun, [], Options),
+
+    Infos2 = lists:map(fun(Info) ->
+        #{
+            id := DDocId = <<"_design/", _/binary>>
+        } = Info,
+        Info#{
+            rev_info => get_winning_revs_future(Db, DDocId, 1)
+        }
+    end, Infos1),
+
+    Infos3 = lists:flatmap(fun(Info) ->
+        #{
+            id := DDocId,
+            rev_info := RevInfoFuture
+        } = Info,
+        [RevInfo] = get_winning_revs_wait(Db, RevInfoFuture),
+        #{deleted := Deleted} = RevInfo,
+        if Deleted -> []; true ->
+            [Info#{
+                rev_info := RevInfo,
+                body => get_doc_body_future(Db, DDocId, RevInfo)
+            }]
+        end
+    end, Infos2),
+
+    VDUs = lists:flatmap(fun(Info) ->
+        #{
+            id := DDocId,
+            rev_info := RevInfo,
+            body := BodyFuture
+        } = Info,
+        #doc{} = Doc = get_doc_body_wait(Db, DDocId, RevInfo, BodyFuture),
+        case couch_doc:get_validate_doc_fun(Doc) of
+            nil -> [];
+            Fun -> [Fun]
+        end
+    end, Infos3),
+
+    Db#{
+        validate_doc_update_funs := VDUs
+    }.
+
+
 bump_metadata_version(Tx) ->
     % The 14 zero bytes is pulled from the PR for adding the
     % metadata version key. Not sure why 14 bytes when version
@@ -760,6 +841,17 @@ bump_metadata_version(Tx) ->
     erlfdb:set_versionstamped_value(Tx, ?METADATA_VERSION_KEY, <<0:112>>).
 
 
+bump_db_version(#{} = Db) ->
+    #{
+        tx := Tx,
+        db_prefix := DbPrefix
+    } = Db,
+
+    DbVersionKey = erlfdb_tuple:pack({?DB_VERSION}, DbPrefix),
+    DbVersion = fabric2_util:uuid(),
+    ok = erlfdb:set(Tx, DbVersionKey, DbVersion).
+
+
 write_doc_body(#{} = Db0, #doc{} = Doc) ->
     #{
         tx := Tx
@@ -999,14 +1091,16 @@ require_transaction(#{} = _Db) ->
     erlang:error(transaction_required).
 
 
-ensure_current(#{} = Db) ->
+ensure_current(Db) ->
+    ensure_current(Db, true).
+
+
+ensure_current(#{} = Db, CheckDbVersion) ->
     require_transaction(Db),
 
     #{
         tx := Tx,
-        md_version := MetaDataVersion,
-        db_prefix := DbPrefix,
-        db_version := DbVersion
+        md_version := MetaDataVersion
     } = Db,
 
     case erlfdb:wait(erlfdb:get(Tx, ?METADATA_VERSION_KEY)) of
@@ -1014,11 +1108,23 @@ ensure_current(#{} = Db) ->
         _NewVersion -> reopen(Db)
     end,
 
-    DbVersionKey = erlfdb:tuple_pack({?DB_VERSION}, DbPrefix),
-
-    case erlfdb:wait(erlfdb:get(Tx, DbVersionKey)) of
-        DbVersion -> Db;
-        _NewDBVersion -> reopen(Db)
+    AlreadyChecked = get(?PDICT_CHECKED_DB_IS_CURRENT),
+    if not CheckDbVersion orelse AlreadyChecked == true -> Db; true ->
+        #{
+            db_prefix := DbPrefix,
+            db_version := DbVersion
+        } = Db,
+
+        DbVersionKey = erlfdb_tuple:pack({?DB_VERSION}, DbPrefix),
+
+        case erlfdb:wait(erlfdb:get(Tx, DbVersionKey)) of
+            DbVersion ->
+                put(?PDICT_CHECKED_DB_IS_CURRENT, true),
+                Db;
+            _NewDBVersion ->
+                fabric2_server:remove(maps:get(name, Db)),
+                reopen(Db)
+        end
     end.
 
 
@@ -1033,6 +1139,7 @@ get_previous_transaction_result() ->
 
 
 execute_transaction(Tx, Fun, LayerPrefix) ->
+    put(?PDICT_CHECKED_DB_IS_CURRENT, false),
     Result = Fun(Tx),
     case erlfdb:is_read_only(Tx) of
         true ->
@@ -1046,6 +1153,7 @@ execute_transaction(Tx, Fun, LayerPrefix) ->
 
 clear_transaction() ->
     fabric2_txids:remove(get(?PDICT_TX_ID_KEY)),
+    erase(?PDICT_CHECKED_DB_IS_CURRENT),
     erase(?PDICT_TX_ID_KEY),
     erase(?PDICT_TX_RES_KEY).
 
diff --git a/src/fabric/test/fabric2_changes_fold_tests.erl b/src/fabric/test/fabric2_changes_fold_tests.erl
index a8b3b1f..892b448 100644
--- a/src/fabric/test/fabric2_changes_fold_tests.erl
+++ b/src/fabric/test/fabric2_changes_fold_tests.erl
@@ -49,13 +49,13 @@ setup() ->
             id = DocId,
             body = {[{<<"value">>, Val}]}
         },
-        {ok, Rev} = fabric2_db:update_doc(Db, Doc, []),
+        {ok, RevId} = fabric2_db:update_doc(Db, Doc, []),
         UpdateSeq = fabric2_db:get_update_seq(Db),
         #{
             id => DocId,
-            seq => UpdateSeq,
+            sequence => UpdateSeq,
             deleted => false,
-            rev => couch_doc:rev_to_str(Rev)
+            rev_id => RevId
         }
     end, lists:seq(1, ?DOC_COUNT)),
     {Db, Rows, Ctx}.
@@ -67,12 +67,12 @@ cleanup({Db, _DocIdRevs, Ctx}) ->
 
 
 fold_changes_basic({Db, DocRows, _}) ->
-    {ok, Rows} = fabric2_db:fold_changes(Db, 0, fun fold_fun/3, []),
+    {ok, Rows} = fabric2_db:fold_changes(Db, 0, fun fold_fun/2, []),
     ?assertEqual(lists:reverse(DocRows), Rows).
 
 
 fold_changes_since_now({Db, _, _}) ->
-    {ok, Rows} = fabric2_db:fold_changes(Db, now, fun fold_fun/3, []),
+    {ok, Rows} = fabric2_db:fold_changes(Db, now, fun fold_fun/2, []),
     ?assertEqual([], Rows).
 
 
@@ -80,21 +80,21 @@ fold_changes_since_seq({_, [], _}) ->
     ok;
 
 fold_changes_since_seq({Db, [Row | RestRows], _}) ->
-    #{seq := Since} = Row,
-    {ok, Rows} = fabric2_db:fold_changes(Db, Since, fun fold_fun/3, []),
+    #{sequence := Since} = Row,
+    {ok, Rows} = fabric2_db:fold_changes(Db, Since, fun fold_fun/2, []),
     ?assertEqual(lists:reverse(RestRows), Rows),
     fold_changes_since_seq({Db, RestRows, nil}).
 
 
 fold_changes_basic_rev({Db, _, _}) ->
     Opts = [{dir, rev}],
-    {ok, Rows} = fabric2_db:fold_changes(Db, 0, fun fold_fun/3, [], Opts),
+    {ok, Rows} = fabric2_db:fold_changes(Db, 0, fun fold_fun/2, [], Opts),
     ?assertEqual([], Rows).
 
 
 fold_changes_since_now_rev({Db, DocRows, _}) ->
     Opts = [{dir, rev}],
-    {ok, Rows} = fabric2_db:fold_changes(Db, now, fun fold_fun/3, [], Opts),
+    {ok, Rows} = fabric2_db:fold_changes(Db, now, fun fold_fun/2, [], Opts),
     ?assertEqual(DocRows, Rows).
 
 
@@ -102,24 +102,13 @@ fold_changes_since_seq_rev({_, [], _}) ->
     ok;
 
 fold_changes_since_seq_rev({Db, DocRows, _}) ->
-    #{seq := Since} = lists:last(DocRows),
+    #{sequence := Since} = lists:last(DocRows),
     Opts = [{dir, rev}],
-    {ok, Rows} = fabric2_db:fold_changes(Db, Since, fun fold_fun/3, [], Opts),
+    {ok, Rows} = fabric2_db:fold_changes(Db, Since, fun fold_fun/2, [], Opts),
     ?assertEqual(DocRows, Rows),
     RestRows = lists:sublist(DocRows, length(DocRows) - 1),
     fold_changes_since_seq_rev({Db, RestRows, nil}).
 
 
-fold_fun(_Db, start, Acc) ->
-    {ok, Acc};
-fold_fun(_Db, {change, {Props}}, Acc) ->
-    [{[{rev, Rev}]}] = fabric2_util:get_value(changes, Props),
-    Row = #{
-        id => fabric2_util:get_value(id, Props),
-        seq => fabric2_util:get_value(seq, Props),
-        deleted => fabric2_util:get_value(deleted, Props, false),
-        rev => Rev
-    },
-    {ok, [Row | Acc]};
-fold_fun(_Db, {stop, _LastSeq, null}, Acc) ->
-    {ok, Acc}.
+fold_fun(#{} = Change, Acc) ->
+    {ok, [Change | Acc]}.
diff --git a/src/fabric/test/fabric2_db_misc_tests.erl b/src/fabric/test/fabric2_db_misc_tests.erl
index 12a8f9f..8e64056 100644
--- a/src/fabric/test/fabric2_db_misc_tests.erl
+++ b/src/fabric/test/fabric2_db_misc_tests.erl
@@ -61,7 +61,7 @@ empty_db_info({DbName, Db, _}) ->
 
 
 accessors({DbName, Db, _}) ->
-    SeqZero = fabric2_util:to_hex(fabric2_util:seq_zero()),
+    SeqZero = fabric2_fdb:vs_to_seq(fabric2_util:seq_zero_vs()),
     ?assertEqual(DbName, fabric2_db:name(Db)),
     ?assertEqual(0, fabric2_db:get_instance_start_time(Db)),
     ?assertEqual(nil, fabric2_db:get_pid(Db)),
diff --git a/src/fabric/test/fabric2_doc_fold_tests.erl b/src/fabric/test/fabric2_doc_fold_tests.erl
index 1ded7ba..caa5f92 100644
--- a/src/fabric/test/fabric2_doc_fold_tests.erl
+++ b/src/fabric/test/fabric2_doc_fold_tests.erl
@@ -61,14 +61,14 @@ cleanup({Db, _DocIdRevs, Ctx}) ->
 
 
 fold_docs_basic({Db, DocIdRevs, _}) ->
-    {ok, {?DOC_COUNT, Rows}} = fabric2_db:fold_docs(Db, fun fold_fun/3, []),
+    {ok, {?DOC_COUNT, Rows}} = fabric2_db:fold_docs(Db, fun fold_fun/2, []),
     ?assertEqual(DocIdRevs, lists:reverse(Rows)).
 
 
 fold_docs_rev({Db, DocIdRevs, _}) ->
     Opts = [{dir, rev}],
     {ok, {?DOC_COUNT, Rows}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts),
     ?assertEqual(DocIdRevs, Rows).
 
 
@@ -76,7 +76,7 @@ fold_docs_with_start_key({Db, DocIdRevs, _}) ->
     {StartKey, _} = hd(DocIdRevs),
     Opts = [{start_key, StartKey}],
     {ok, {?DOC_COUNT, Rows}}
-            = fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts),
+            = fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts),
     ?assertEqual(DocIdRevs, lists:reverse(Rows)),
     if length(DocIdRevs) == 1 -> ok; true ->
         fold_docs_with_start_key({Db, tl(DocIdRevs), nil})
@@ -88,7 +88,7 @@ fold_docs_with_end_key({Db, DocIdRevs, _}) ->
     {EndKey, _} = hd(RevDocIdRevs),
     Opts = [{end_key, EndKey}],
     {ok, {?DOC_COUNT, Rows}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts),
     ?assertEqual(RevDocIdRevs, Rows),
     if length(DocIdRevs) == 1 -> ok; true ->
         fold_docs_with_end_key({Db, lists:reverse(tl(RevDocIdRevs)), nil})
@@ -111,12 +111,12 @@ fold_docs_with_different_keys({Db, DocIdRevs, _}) ->
 check_all_combos(Db, StartKey, EndKey, Rows) ->
     Opts1 = make_opts(fwd, StartKey, EndKey, true),
     {ok, {?DOC_COUNT, Rows1}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts1),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts1),
     ?assertEqual(lists:reverse(Rows), Rows1),
 
     Opts2 = make_opts(fwd, StartKey, EndKey, false),
     {ok, {?DOC_COUNT, Rows2}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts2),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts2),
     Expect2 = if EndKey == undefined -> lists:reverse(Rows); true ->
         lists:reverse(all_but_last(Rows))
     end,
@@ -124,12 +124,12 @@ check_all_combos(Db, StartKey, EndKey, Rows) ->
 
     Opts3 = make_opts(rev, StartKey, EndKey, true),
     {ok, {?DOC_COUNT, Rows3}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts3),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts3),
     ?assertEqual(Rows, Rows3),
 
     Opts4 = make_opts(rev, StartKey, EndKey, false),
     {ok, {?DOC_COUNT, Rows4}} =
-            fabric2_db:fold_docs(Db, fun fold_fun/3, [], Opts4),
+            fabric2_db:fold_docs(Db, fun fold_fun/2, [], Opts4),
     Expect4 = if StartKey == undefined -> Rows; true ->
         tl(Rows)
     end,
@@ -197,13 +197,13 @@ pick_end_key(Rows) ->
     end.
 
 
-fold_fun(_Db, {meta, Meta}, _Acc) ->
+fold_fun({meta, Meta}, _Acc) ->
     Total = fabric2_util:get_value(total, Meta),
     {ok, {Total, []}};
-fold_fun(_Db, {row, Row}, {Total, Rows}) ->
+fold_fun({row, Row}, {Total, Rows}) ->
     RowId = fabric2_util:get_value(id, Row),
     RowId = fabric2_util:get_value(key, Row),
     RowRev = fabric2_util:get_value(value, Row),
     {ok, {Total, [{RowId, RowRev} | Rows]}};
-fold_fun(_Db, complete, Acc) ->
+fold_fun(complete, Acc) ->
     {ok, Acc}.