From 38bde53e2429f60b3209d71c562218f3c7429945 Mon Sep 17 00:00:00 2001 From: Adam Kocoloski Date: Mon, 7 Jun 2010 14:46:35 -0400 Subject: map views w/o keylist, BugzID 10220 --- src/fabric_rpc.erl | 105 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 8 deletions(-) (limited to 'src/fabric_rpc.erl') diff --git a/src/fabric_rpc.erl b/src/fabric_rpc.erl index a2d42007..0eab5e6d 100644 --- a/src/fabric_rpc.erl +++ b/src/fabric_rpc.erl @@ -2,7 +2,7 @@ -export([get_db_info/1, get_doc_count/1, get_update_seq/1]). -export([open_doc/3, open_revs/4, get_missing_revs/2, update_docs/3]). --export([all_docs/2]). +-export([all_docs/2, map_view/4]). -include("fabric.hrl"). @@ -11,6 +11,7 @@ limit, include_docs, offset = nil, + total_rows, reduce_fun = fun couch_db:enum_docs_reduce_to_count/1, stop_fun, group_level = 0 @@ -30,14 +31,46 @@ all_docs(DbName, #view_query_args{keys=nil} = QueryArgs) -> direction = Dir } = QueryArgs, StartId = if is_binary(StartKey) -> StartKey; true -> StartDocId end, + {ok, Total} = couch_db:get_doc_count(Db), Acc0 = #view_acc{ db = Db, include_docs = IncludeDocs, limit = Limit+Skip, + total_rows = Total, stop_fun = all_docs_stop_fun(QueryArgs) }, {ok, Acc} = couch_db:enum_docs(Db, StartId, Dir, fun view_fold/3, Acc0), - final_all_docs_response(Db, Acc#view_acc.offset). + final_response(Total, Acc#view_acc.offset). + +map_view(DbName, DDoc, ViewName, #view_query_args{keys=nil} = QueryArgs) -> + {ok, Db} = couch_db:open(DbName, []), + #view_query_args{ + start_key = StartKey, + start_docid = StartDocId, + limit = Limit, + skip = Skip, + include_docs = IncludeDocs, + direction = Dir, + stale = Stale, + view_type = ViewType + } = QueryArgs, + Start = {StartKey, StartDocId}, + MinSeq = if Stale == ok -> 0; true -> couch_db:get_update_seq(Db) end, + Group0 = couch_view_group:design_doc_to_view_group(Db, DDoc), + {ok, Pid} = gen_server:call(couch_view, {get_group_server, DbName, Group0}), + {ok, Group} = couch_view_group:request_group(Pid, MinSeq), + View = extract_view(Pid, ViewName, Group#group.views, ViewType), + {ok, Total} = couch_view:get_row_count(View), + Acc0 = #view_acc{ + db = Db, + include_docs = IncludeDocs, + limit = Limit+Skip, + total_rows = Total, + reduce_fun = fun couch_view:reduce_to_count/1, + stop_fun = default_stop_fun(QueryArgs) + }, + {ok, Acc} = couch_view:fold(View, Start, Dir, fun view_fold/3, Acc0), + final_response(Total, Acc#view_acc.offset). get_db_info(DbName) -> with_db(DbName, [], {couch_db, get_db_info, []}). @@ -101,10 +134,9 @@ view_fold(#full_doc_info{} = FullDocInfo, OffsetReds, Acc) -> #doc_info{revs=[#rev_info{deleted=true}|_]} -> {ok, Acc} end; -view_fold(KV, OffsetReds, #view_acc{offset=nil} = Acc) -> +view_fold(KV, OffsetReds, #view_acc{offset=nil, total_rows=Total} = Acc) -> % calculates the offset for this shard - #view_acc{db=Db, reduce_fun=Reduce} = Acc, - {ok, Total} = couch_db:get_doc_count(Db), + #view_acc{reduce_fun=Reduce} = Acc, Offset = Reduce(OffsetReds), case rexi:sync_reply({total_and_offset, Total, Offset}) of ok -> @@ -150,10 +182,67 @@ all_docs_stop_fun(#view_query_args{direction=rev, end_key=EndKey}) -> couch_db_updater:less_docid(ViewKey, EndKey) end. -final_all_docs_response(Db, nil) -> - {ok, Total} = couch_db:get_doc_count(Db), +final_response(Total, nil) -> case rexi:sync_reply({total_and_offset, Total, Total}) of ok -> rexi:reply(complete); stop -> ok end; -final_all_docs_response(_Db, _Offset) -> +final_response(_Total, _Offset) -> rexi:reply(complete). + +default_stop_fun(#view_query_args{direction=fwd, inclusive_end=true} = Args) -> + #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args, + fun(ViewKey, ViewId) -> + couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId]) + end; +default_stop_fun(#view_query_args{direction=fwd} = Args) -> + #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args, + fun + (ViewKey, _ViewId) when ViewKey == EndKey -> + true; + (ViewKey, ViewId) -> + couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId]) + end; +default_stop_fun(#view_query_args{direction=rev, inclusive_end=true} = Args) -> + #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args, + fun(ViewKey, ViewId) -> + couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId]) + end; +default_stop_fun(#view_query_args{direction=rev} = Args) -> + #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args, + fun + (ViewKey, _ViewId) when ViewKey == EndKey -> + true; + (ViewKey, ViewId) -> + couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId]) + end. + +extract_view(Pid, ViewName, [], _ViewType) -> + ?LOG_ERROR("missing_named_view ~p", [ViewName]), + exit(Pid, kill), + exit(missing_named_view); +extract_view(Pid, ViewName, [View|Rest], ViewType) -> + case lists:member(ViewName, view_names(View, ViewType)) of + true -> + if ViewType == reduce -> + {index_of(ViewName, view_names(View, reduce)), View}; + true -> + View + end; + false -> + extract_view(Pid, ViewName, Rest, ViewType) + end. + +view_names(View, Type) when Type == red_map; Type == reduce -> + [Name || {Name, _} <- View#view.reduce_funs]; +view_names(View, map) -> + View#view.map_names. + +index_of(X, List) -> + index_of(X, List, 1). + +index_of(_X, [], _I) -> + not_found; +index_of(X, [X|_Rest], I) -> + I; +index_of(X, [_|Rest], I) -> + index_of(X, Rest, I+1). -- cgit v1.2.3