From e8c43b1e8e6f5393e579ae9e015c5b7c282dbf2a Mon Sep 17 00:00:00 2001 From: Adam Kocoloski Date: Wed, 9 Jun 2010 14:02:21 -0400 Subject: rewrite fabric_db_info --- src/fabric.erl | 6 +-- src/fabric_db_info.erl | 124 +++++++++++++++++-------------------------------- 2 files changed, 45 insertions(+), 85 deletions(-) diff --git a/src/fabric.erl b/src/fabric.erl index 80646561..e4887953 100644 --- a/src/fabric.erl +++ b/src/fabric.erl @@ -1,7 +1,7 @@ -module(fabric). % DBs --export([all_dbs/0, all_dbs/1, create_db/2, delete_db/2, get_db_info/2, +-export([all_dbs/0, all_dbs/1, create_db/2, delete_db/2, get_db_info/1, get_doc_count/1]). % Documents @@ -29,8 +29,8 @@ all_dbs() -> all_dbs(Customer) -> fabric_all_databases:all_databases(Customer). -get_db_info(DbName, Customer) -> - fabric_db_info:get_db_info(dbname(DbName), Customer). +get_db_info(DbName) -> + fabric_db_info:go(dbname(DbName)). get_doc_count(DbName) -> fabric_db_doc_count:go(dbname(DbName)). diff --git a/src/fabric_db_info.erl b/src/fabric_db_info.erl index e70b335c..8db7212f 100644 --- a/src/fabric_db_info.erl +++ b/src/fabric_db_info.erl @@ -1,91 +1,51 @@ -module(fabric_db_info). --author(brad@cloudant.com). --export([get_db_info/2]). +-export([go/1]). -include("fabric.hrl"). -%% @doc get database information tuple -get_db_info(DbName, Customer) -> - Name = cloudant_db_name(Customer, DbName), +go(DbName) -> Shards = partitions:all_parts(DbName), Workers = fabric_util:submit_jobs(Shards, get_db_info, []), - Acc0 = {false, length(Workers), lists:usort([ {Beg, nil} || - #shard{range=[Beg,_]} <- Workers])}, - case fabric_util:recv(Workers, #shard.ref, fun handle_info_msg/3, Acc0) of - {ok, ShardInfos} -> - {ok, process_infos(ShardInfos, [{db_name, Name}])}; - Error -> Error - end. - - -%% ===================== -%% internal -%% ===================== - -handle_info_msg(_, _, {true, _, Infos0}) -> - {stop, Infos0}; -handle_info_msg(_, _, {false, 1, Infos0}) -> - MissingShards = lists:reverse(lists:foldl(fun - ({S,nil}, Acc) -> [S|Acc]; - (_, Acc) -> Acc - end, [], Infos0)), - ?LOG_ERROR("get_db_info error, missing shards: ~p", [MissingShards]), - {error, get_db_info}; -handle_info_msg({ok, Info}, #shard{range=[Beg,_]}, {false, N, Infos0}) -> - case couch_util:get_value(Beg, Infos0) of + Acc0 = {fabric_dict:init(Workers, nil), []}, + fabric_util:recv(Workers, #shard.ref, fun handle_message/3, Acc0). + +handle_message({ok, Info}, #shard{dbname=Name} = Shard, {Counters, Acc}) -> + case fabric_dict:lookup_element(Shard, Counters) of + undefined -> + % already heard from someone else in this range + {ok, {Counters, Acc}}; nil -> - Infos = lists:keyreplace(Beg, 1, Infos0, {Beg, Info}), - case is_complete(Infos) of - true -> {ok, {true, N-1, Infos}}; - false -> {ok, {false, N-1, Infos}} - end; - _ -> - {ok, {false, N-1, Infos0}} + C1 = fabric_dict:store(Shard, ok, Counters), + C2 = fabric_view:remove_overlapping_shards(Shard, C1), + case fabric_dict:any(nil, C2) of + true -> + {ok, {C2, [Info|Acc]}}; + false -> + {stop, [{db_name,Name}|merge_results(lists:flatten([Info|Acc]))]} + end end; -handle_info_msg(_Other, _, {Complete, N, Infos0}) -> - {ok, {Complete, N-1, Infos0}}. - -is_complete(List) -> - not lists:any(fun({_,Info}) -> Info =:= nil end, List). - -cloudant_db_name(Customer, FullName) -> - case Customer of - "" -> FullName; - Name -> re:replace(FullName, [Name,"/"], "", [{return, binary}]) - end. - -%% Loop through Tasks on the flattened Infos and get the aggregated result -process_infos(Infos, Initial) -> - Tasks = [ - {doc_count, fun sum/2, 0}, - {doc_del_count, fun sum/2, 0}, - {update_seq, fun max/2, 1}, - {purge_seq, fun sum/2, 0}, - {compact_running, fun bool/2, 0}, - {disk_size, fun sum/2, 0}, - {instance_start_time, fun(_, _) -> <<"0">> end, 0}, - {disk_format_version, fun max/2, 0}], - - Infos1 = lists:flatten(Infos), - - Result = lists:map(fun({Type, Fun, Default}) -> - {Type, process_info(Type, Fun, Default, Infos1)} - end, Tasks), - lists:flatten([Initial, Result]). - - process_info(Type, Fun, Default, List) -> - lists:foldl(fun(V, AccIn) -> Fun(V, AccIn) end, Default, - proplists:get_all_values(Type, List)). - -sum(New, Existing) -> - New + Existing. - -bool(New, Existing) -> - New andalso Existing. - -max(New, Existing) -> - case New > Existing of - true -> New; - false -> Existing - end. +handle_message(_, _, Acc) -> + {ok, Acc}. + +merge_results(Info) -> + Dict = lists:foldl(fun({K,V},D0) -> orddict:append(K,V,D0) end, + orddict:new(), Info), + orddict:fold(fun + (doc_count, X, Acc) -> + [{doc_count, lists:sum(X)} | Acc]; + (doc_del_count, X, Acc) -> + [{doc_del_count, lists:sum(X)} | Acc]; + (update_seq, X, Acc) -> + [{update_seq, lists:sum(X)} | Acc]; + (purge_seq, X, Acc) -> + [{purge_seq, lists:sum(X)} | Acc]; + (compact_running, X, Acc) -> + [{compact_running, lists:member(true, X)} | Acc]; + (disk_size, X, Acc) -> + [{disk_size, lists:sum(X)} | Acc]; + (disk_format_version, X, Acc) -> + [{disk_format_version, lists:max(X)} | Acc]; + (_, _, Acc) -> + Acc + end, [{instance_start_time, <<"0">>}], Dict). -- cgit v1.2.3