From 146bc594aef47b675670e7a7fd7f89b7c6a10843 Mon Sep 17 00:00:00 2001 From: John Christopher Anderson Date: Sun, 15 Feb 2009 20:36:53 +0000 Subject: View etags are now provided. See note in the source about how they could be more efficient. Changes arity on make_view_fold_fun etc. Closes COUCHDB-4 git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@744747 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_httpd_show.erl | 102 +++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 47 deletions(-) (limited to 'src/couchdb/couch_httpd_show.erl') diff --git a/src/couchdb/couch_httpd_show.erl b/src/couchdb/couch_httpd_show.erl index 1da8fe98..39c6cc1e 100644 --- a/src/couchdb/couch_httpd_show.erl +++ b/src/couchdb/couch_httpd_show.erl @@ -77,15 +77,15 @@ send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db) -> reduce = Reduce } = QueryArgs = couch_httpd_view:parse_view_query(Req, nil, nil, true), case couch_view:get_map_view(Db, DesignId, ViewName, Stale) of - {ok, View} -> - output_map_list(Req, Lang, ListSrc, View, Db, QueryArgs); + {ok, View, Group} -> + output_map_list(Req, Lang, ListSrc, View, Group, Db, QueryArgs); {not_found, _Reason} -> case couch_view:get_reduce_view(Db, DesignId, ViewName, Stale) of - {ok, ReduceView} -> + {ok, ReduceView, Group} -> case Reduce of false -> MapView = couch_view:extract_map_view(ReduceView), - output_map_list(Req, Lang, ListSrc, MapView, Db, QueryArgs); + output_map_list(Req, Lang, ListSrc, MapView, Group, Db, QueryArgs); _ -> throw({not_implemented, reduce_view_lists}) end; @@ -94,7 +94,7 @@ send_view_list_response(Lang, ListSrc, ViewName, DesignId, Req, Db) -> end end. -output_map_list(Req, Lang, ListSrc, View, Db, QueryArgs) -> +output_map_list(#httpd{mochi_req=MReq}=Req, Lang, ListSrc, View, Group, Db, QueryArgs) -> #view_query_args{ limit = Limit, direction = Dir, @@ -104,51 +104,59 @@ output_map_list(Req, Lang, ListSrc, View, Db, QueryArgs) -> } = QueryArgs, {ok, RowCount} = couch_view:get_row_count(View), Start = {StartKey, StartDocId}, - % get the os process here - % pass it into the view fold with closures - {ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc), - - StartListRespFun = fun(Req2, Code, TotalViewCount, Offset) -> - JsonResp = couch_query_servers:render_list_head(QueryServer, - Req2, Db, TotalViewCount, Offset), - #extern_resp_args{ - code = Code, - data = BeginBody, - ctype = CType, - headers = Headers - } = couch_httpd_external:parse_external_response(JsonResp), - JsonHeaders = couch_httpd_external:default_or_content_type(CType, Headers), - {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders), - {ok, Resp, binary_to_list(BeginBody)} - end, + Headers = MReq:get(headers), + Hlist = mochiweb_headers:to_list(Headers), + Accept = proplists:get_value('Accept', Hlist), + CurrentEtag = couch_httpd_view:view_group_etag(Group, {Lang, ListSrc, Accept}), + couch_httpd:etag_respond(Req, CurrentEtag, fun() -> + % get the os process here + % pass it into the view fold with closures + {ok, QueryServer} = couch_query_servers:start_view_list(Lang, ListSrc), + + StartListRespFun = fun(Req2, Etag, TotalViewCount, Offset) -> + ExternalResp = couch_query_servers:render_list_head(QueryServer, + Req2, Db, TotalViewCount, Offset), + JsonResp = apply_etag(ExternalResp, CurrentEtag), + #extern_resp_args{ + code = Code, + data = BeginBody, + ctype = CType, + headers = ExtHeaders + } = couch_httpd_external:parse_external_response(JsonResp), + JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders), + % TODO use the Etag + {ok, Resp} = start_chunked_response(Req, Code, JsonHeaders), + {ok, Resp, binary_to_list(BeginBody)} + end, - SendListRowFun = fun(Resp, Db2, {{Key, DocId}, Value}, - RowFront, _IncludeDocs) -> - JsonResp = couch_query_servers:render_list_row(QueryServer, - Req, Db2, {{Key, DocId}, Value}), - #extern_resp_args{ - stop = StopIter, - data = RowBody - } = couch_httpd_external:parse_external_response(JsonResp), - RowFront2 = case RowFront of - nil -> []; - _ -> RowFront + SendListRowFun = fun(Resp, Db2, {{Key, DocId}, Value}, + RowFront, _IncludeDocs) -> + JsonResp = couch_query_servers:render_list_row(QueryServer, + Req, Db2, {{Key, DocId}, Value}), + #extern_resp_args{ + stop = StopIter, + data = RowBody + } = couch_httpd_external:parse_external_response(JsonResp), + RowFront2 = case RowFront of + nil -> []; + _ -> RowFront + end, + case StopIter of + true -> stop; + _ -> send_chunk(Resp, RowFront2 ++ binary_to_list(RowBody)) + end end, - case StopIter of - true -> stop; - _ -> send_chunk(Resp, RowFront2 ++ binary_to_list(RowBody)) - end - end, - FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, Db, RowCount, - #view_fold_helper_funs{ - reduce_count = fun couch_view:reduce_to_count/1, - start_response = StartListRespFun, - send_row = SendListRowFun - }), - FoldAccInit = {Limit, SkipCount, undefined, []}, - FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit), - finish_view_list(Req, Db, QueryServer, RowCount, FoldResult, StartListRespFun). + FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, CurrentEtag, Db, RowCount, + #view_fold_helper_funs{ + reduce_count = fun couch_view:reduce_to_count/1, + start_response = StartListRespFun, + send_row = SendListRowFun + }), + FoldAccInit = {Limit, SkipCount, undefined, []}, + FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit), + finish_view_list(Req, Db, QueryServer, RowCount, FoldResult, StartListRespFun) + end). finish_view_list(Req, Db, QueryServer, TotalRows, FoldResult, StartListRespFun) -> -- cgit v1.2.3