Repository: couchdb-fabric
Updated Branches:
refs/heads/master d44f7fba4 -> 19c273ac5
Provide an access to a document info
The functions `get_doc_info/3` and `get_full_doc_info/3` were
added to API to provide an access to the records `#doc_info{}`
and `#full_doc_info{}` accordingly.
The functions are re-using `fabric_open_doc` coordinator
and consequently are the subject of the same read quorum rules
as `open_doc/3` function. However the info functions do not trigger
read repair on a not fully complete quorum.
Function `get_full_doc_info/3` accepts an option `deleted` to
allow to provide an information for a deleted document,
similar to `open_doc/3`.
FogBugz: 12933
This is a cherry-pick of:
https://github.com/cloudant/fabric/commit/c85569287ad8f86122b47775adc2ab9218db0322
Conflicts:
src/fabric_rpc.erl
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fabric/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fabric/commit/d7d6be85
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fabric/tree/d7d6be85
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fabric/diff/d7d6be85
Branch: refs/heads/master
Commit: d7d6be8535443fd3ddbe65c0a6a35534b4b98e29
Parents: d44f7fb
Author: Eric Avdey <[email protected]>
Authored: Mon Nov 10 20:12:42 2014 -0400
Committer: Mike Wallace <[email protected]>
Committed: Wed Jun 3 14:54:21 2015 +0100
----------------------------------------------------------------------
src/fabric.erl | 34 ++++++++++++++++++++--
src/fabric_doc_open.erl | 68 +++++++++++++++++++++++++++++++++++++++++---
src/fabric_rpc.erl | 10 +++++--
3 files changed, 103 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fabric/blob/d7d6be85/src/fabric.erl
----------------------------------------------------------------------
diff --git a/src/fabric.erl b/src/fabric.erl
index 958e63c..25205f8 100644
--- a/src/fabric.erl
+++ b/src/fabric.erl
@@ -23,8 +23,9 @@
get_security/2, get_all_security/1, get_all_security/2]).
% Documents
--export([open_doc/3, open_revs/4, get_missing_revs/2, get_missing_revs/3,
- update_doc/3, update_docs/3, purge_docs/2, att_receiver/2]).
+-export([open_doc/3, open_revs/4, get_doc_info/3, get_full_doc_info/3,
+ get_missing_revs/2, get_missing_revs/3, update_doc/3, update_docs/3,
+ purge_docs/2, att_receiver/2]).
% Views
-export([all_docs/4, all_docs/5, changes/4, query_view/3, query_view/4,
@@ -161,7 +162,12 @@ get_all_security(DbName, Options) ->
{error, any()} |
{error, any() | any()}.
open_doc(DbName, Id, Options) ->
- fabric_doc_open:go(dbname(DbName), docid(Id), opts(Options)).
+ case proplists:get_value(doc_info, Options) of
+ undefined ->
+ fabric_doc_open:go(dbname(DbName), docid(Id), opts(Options));
+ Else ->
+ {error, {invalid_option, {doc_info, Else}}}
+ end.
%% @doc retrieve a collection of revisions, possible all
-spec open_revs(dbname(), docid(), [revision()] | all, [option()]) ->
@@ -172,6 +178,28 @@ open_doc(DbName, Id, Options) ->
open_revs(DbName, Id, Revs, Options) ->
fabric_doc_open_revs:go(dbname(DbName), docid(Id), Revs, opts(Options)).
+%% @doc Retrieves an information on a document with a given id
+-spec get_doc_info(dbname(), docid(), [options()]) ->
+ {ok, #doc_info{}} |
+ {not_found, missing} |
+ {timeout, any()} |
+ {error, any()} |
+ {error, any() | any()}.
+get_doc_info(DbName, Id, Options) ->
+ Options1 = [doc_info|Options],
+ fabric_doc_open:go(dbname(DbName), docid(Id), opts(Options1)).
+
+%% @doc Retrieves a full information on a document with a given id
+-spec get_full_doc_info(dbname(), docid(), [options()]) ->
+ {ok, #full_doc_info{}} |
+ {not_found, missing | deleted} |
+ {timeout, any()} |
+ {error, any()} |
+ {error, any() | any()}.
+get_full_doc_info(DbName, Id, Options) ->
+ Options1 = [{doc_info, full}|Options],
+ fabric_doc_open:go(dbname(DbName), docid(Id), opts(Options1)).
+
%% @equiv get_missing_revs(DbName, IdsRevs, [])
get_missing_revs(DbName, IdsRevs) ->
get_missing_revs(DbName, IdsRevs, []).
http://git-wip-us.apache.org/repos/asf/couchdb-fabric/blob/d7d6be85/src/fabric_doc_open.erl
----------------------------------------------------------------------
diff --git a/src/fabric_doc_open.erl b/src/fabric_doc_open.erl
index c7d90a4..1607946 100644
--- a/src/fabric_doc_open.erl
+++ b/src/fabric_doc_open.erl
@@ -30,7 +30,12 @@
go(DbName, Id, Options) ->
- Workers = fabric_util:submit_jobs(mem3:shards(DbName,Id), open_doc,
+ Handler = case proplists:get_value(doc_info, Options) of
+ true -> get_doc_info;
+ full -> get_full_doc_info;
+ undefined -> open_doc
+ end,
+ Workers = fabric_util:submit_jobs(mem3:shards(DbName,Id), Handler,
[Id, [deleted|Options]]),
SuppressDeletedDoc = not lists:member(deleted, Options),
N = mem3:n(DbName),
@@ -44,11 +49,15 @@ go(DbName, Id, Options) ->
},
RexiMon = fabric_util:create_monitors(Workers),
try fabric_util:recv(Workers, #shard.ref, fun handle_message/3, Acc0) of
- {ok, #acc{}=Acc} ->
+ {ok, #acc{}=Acc} when Handler =:= open_doc ->
Reply = handle_response(Acc),
format_reply(Reply, SuppressDeletedDoc);
+ {ok, #acc{state = r_not_met}} ->
+ {error, quorum_not_met};
+ {ok, #acc{q_reply = QuorumReply}} ->
+ format_reply(QuorumReply, SuppressDeletedDoc);
{timeout, #acc{workers=DefunctWorkers}} ->
- fabric_util:log_timeout(DefunctWorkers, "open_doc"),
+ fabric_util:log_timeout(DefunctWorkers, atom_to_list(Handler)),
{error, timeout};
Error ->
Error
@@ -156,12 +165,15 @@ choose_reply(Docs) ->
end, Docs),
{ok, Winner}.
+format_reply({ok, #full_doc_info{deleted=true}}, true) ->
+ {not_found, deleted};
format_reply({ok, #doc{deleted=true}}, true) ->
{not_found, deleted};
+format_reply(not_found, _) ->
+ {not_found, missing};
format_reply(Else, _) ->
Else.
-
is_r_met_test() ->
Workers0 = [],
Workers1 = [nil],
@@ -472,6 +484,54 @@ handle_response_quorum_met_test() ->
stop_meck_(),
ok.
+get_doc_info_test() ->
+ start_meck_(),
+ meck:new([mem3, rexi_monitor, fabric_util]),
+ meck:expect(twig, log, fun(_, _, _) -> ok end),
+ meck:expect(fabric, update_docs, fun(_, _, _) -> {ok, []} end),
+ meck:expect(couch_stats, increment_counter, fun(_) -> ok end),
+ meck:expect(fabric_util, submit_jobs, fun(_, _, _) -> ok end),
+ meck:expect(fabric_util, create_monitors, fun(_) -> ok end),
+ meck:expect(rexi_monitor, stop, fun(_) -> ok end),
+ meck:expect(mem3, shards, fun(_, _) -> ok end),
+ meck:expect(mem3, n, fun(_) -> 3 end),
+ meck:expect(mem3, quorum, fun(_) -> 2 end),
+
+ meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+ {ok, #acc{state = r_not_met}}
+ end),
+ Rsp1 = fabric_doc_open:go("test", "one", [doc_info]),
+ ?assertEqual({error, quorum_not_met}, Rsp1),
+
+ Rsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+ ?assertEqual({error, quorum_not_met}, Rsp2),
+
+ meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+ {ok, #acc{state = r_met, q_reply = not_found}}
+ end),
+ MissingRsp1 = fabric_doc_open:go("test", "one", [doc_info]),
+ ?assertEqual({not_found, missing}, MissingRsp1),
+ MissingRsp2 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+ ?assertEqual({not_found, missing}, MissingRsp2),
+
+ meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+ A = #doc_info{},
+ {ok, #acc{state = r_met, q_reply = {ok, A}}}
+ end),
+ {ok, Rec1} = fabric_doc_open:go("test", "one", [doc_info]),
+ ?assert(is_record(Rec1, doc_info)),
+
+ meck:expect(fabric_util, recv, fun(_, _, _, _) ->
+ A = #full_doc_info{deleted = true},
+ {ok, #acc{state = r_met, q_reply = {ok, A}}}
+ end),
+ Rsp3 = fabric_doc_open:go("test", "one", [{doc_info, full}]),
+ ?assertEqual({not_found, deleted}, Rsp3),
+ {ok, Rec2} = fabric_doc_open:go("test", "one", [{doc_info, full},deleted]),
+ ?assert(is_record(Rec2, full_doc_info)),
+
+ meck:unload([mem3, rexi_monitor, fabric_util]),
+ stop_meck_().
start_meck_() ->
meck:new([couch_log, rexi, fabric, couch_stats]).
http://git-wip-us.apache.org/repos/asf/couchdb-fabric/blob/d7d6be85/src/fabric_rpc.erl
----------------------------------------------------------------------
diff --git a/src/fabric_rpc.erl b/src/fabric_rpc.erl
index eeaebd1..057dec3 100644
--- a/src/fabric_rpc.erl
+++ b/src/fabric_rpc.erl
@@ -13,8 +13,8 @@
-module(fabric_rpc).
-export([get_db_info/1, get_doc_count/1, get_update_seq/1]).
--export([open_doc/3, open_revs/4, get_missing_revs/2, get_missing_revs/3,
- update_docs/3]).
+-export([open_doc/3, open_revs/4, get_doc_info/3, get_full_doc_info/3,
+ get_missing_revs/2, get_missing_revs/3, update_docs/3]).
-export([all_docs/3, changes/3, map_view/4, reduce_view/4, group_info/2]).
-export([create_db/1, delete_db/1, reset_validation_funs/1, set_security/3,
set_revs_limit/3, create_shard_db_doc/2, delete_shard_db_doc/2]).
@@ -174,6 +174,12 @@ open_doc(DbName, DocId, Options) ->
open_revs(DbName, Id, Revs, Options) ->
with_db(DbName, Options, {couch_db, open_doc_revs, [Id, Revs, Options]}).
+get_full_doc_info(DbName, DocId, Options) ->
+ with_db(DbName, Options, {couch_db, get_full_doc_info, [DocId]}).
+
+get_doc_info(DbName, DocId, Options) ->
+ with_db(DbName, Options, {couch_db, get_doc_info, [DocId]}).
+
get_missing_revs(DbName, IdRevsList) ->
get_missing_revs(DbName, IdRevsList, []).