diff options
author | ncshaw <ncshaw@ibm.com> | 2022-05-20 16:21:44 -0500 |
---|---|---|
committer | Noah Shaw <ncshaw@ibm.com> | 2022-07-22 15:05:03 -0500 |
commit | 963daf6ca9df5815973bb6934c3fdc02b905f6f9 (patch) | |
tree | 4b42b4994fb25943d52614960eea872f10fd91b8 | |
parent | fff03ef8e8491e609bd9159e0272fcebeeab1387 (diff) | |
download | couchdb-963daf6ca9df5815973bb6934c3fdc02b905f6f9.tar.gz |
Implement view_report function
-rw-r--r-- | src/couch/src/couch_debug.erl | 80 | ||||
-rw-r--r-- | src/couch_mrview/src/couch_mrview_debug.erl | 391 |
2 files changed, 459 insertions, 12 deletions
diff --git a/src/couch/src/couch_debug.erl b/src/couch/src/couch_debug.erl index 9dc5053e6..93e11bf30 100644 --- a/src/couch/src/couch_debug.erl +++ b/src/couch/src/couch_debug.erl @@ -47,7 +47,9 @@ ]). -export([ - print_table/2 + print_table/2, + print_report/1, + print_report_with_info_width/2 ]). -type throw(_Reason) :: no_return(). @@ -80,6 +82,8 @@ help() -> print_linked_processes, memory_info, print_table, + print_report, + print_report_with_info_width, restart, restart_busy ]. @@ -287,15 +291,16 @@ help(print_linked_processes) -> Print cluster of linked processes. This function receives the initial Pid to start from. The function doesn't recurse to pids - older than initial one. The output would look like similar to: - ``` -couch_debug:print_linked_processes(whereis(couch_index_server)). -name | reductions | message_queue_len | memory -couch_index_server[<0.288.0>] | 478240 | 0 | 109696 - couch_index:init/1[<0.3520.22>] | 4899 | 0 | 109456 - couch_file:init/1[<0.886.22>] | 11973 | 0 | 67984 - couch_index:init/1[<0.3520.22>] | 4899 | 0 | 109456 - ``` + older than initial one. + + The output will look like similar to: + + couch_debug:print_linked_processes(whereis(couch_index_server)). + name | reductions | message_queue_len | memory + couch_index_server[<0.288.0>] | 478240 | 0 | 109696 + couch_index:init/1[<0.3520.22>] | 4899 | 0 | 109456 + couch_file:init/1[<0.886.22>] | 11973 | 0 | 67984 + couch_index:init/1[<0.3520.22>] | 4899 | 0 | 109456 --- ", []); @@ -328,6 +333,41 @@ help(print_table) -> --- ", []); +help(print_report) -> + io:format(" + print_report(Report) + -------------------------------- + + Print a report in table form. + - Report: List of {InfoKey, InfoVal} where each InfoKey is unique + (unlike print_table/2). + + The output will look similar to: + + |info | value + | btree_size | 51 + | def | function(doc){emit(doc.id, 1);} + | id_num | 0 + | options | + | purge_seq | 0 + | reduce_funs | + | update_seq | 3 + + --- + ", []); +help(print_report_with_info_width) -> + io:format(" + print_report_with_info_width(Report, Width) + -------------------------------- + + Print a report in table form. Same as print_report/1 but with a custom + width for the InfoKey column. + - Report: List of {InfoKey, InfoVal} where each InfoKey is unique + (unlike print_table/2). + - Width: Width of InfoKey column in TableSpec. Default is 50. + + --- + ", []); help(print_tree) -> io:format(" print_tree(Tree, TableSpec) @@ -891,6 +931,26 @@ print_table(Rows, TableSpec) -> ), ok. +print_report(Report) -> + print_report_with_info_width(Report, 50). + +print_report_with_info_width(Report, Width) -> + TableSpec = [ + {Width, left, info}, + {100, right, value} + ], + io:format("~s~n", [format(TableSpec)]), + lists:map( + fun({InfoKey, Value}) -> + TableSpec1 = [ + {Width, left, info}, + {100, right, InfoKey} + ], + io:format("~s~n", [table_row(InfoKey, 2, [{InfoKey, Value}], TableSpec1)]) + end, + Report + ). + print_tree(Tree, TableSpec) -> io:format("~s~n", [format(TableSpec)]), map_tree(Tree, fun(_, {Id, Props}, Pos) -> diff --git a/src/couch_mrview/src/couch_mrview_debug.erl b/src/couch_mrview/src/couch_mrview_debug.erl index a4203d49d..66f5d79d9 100644 --- a/src/couch_mrview/src/couch_mrview_debug.erl +++ b/src/couch_mrview/src/couch_mrview_debug.erl @@ -18,14 +18,30 @@ ]). -export([ - view_signature/2 + view_signature/2, + index_state/1, + view_state/1, + view_state/2, + index_view_state/1, + index_view_state/2, + index_report/1, + view_report/1, + view_report/2, + index_view_report/1, + index_view_report/2 ]). -include_lib("couch_mrview/include/couch_mrview.hrl"). help() -> [ - view_signature + view_signature, + index_state, + view_state, + index_view_state, + index_report, + view_report, + index_view_report ]. -spec help(Function :: atom()) -> ok. @@ -34,7 +50,223 @@ help(view_signature) -> io:format(" view_signature(ShardName, DDocName) -------------- + Returns a view signature for given ddoc for a given (non clustered) database. + + --- + ", []); +help(index_state) -> + io:format(" + index_state(Pid) + -------------- + + Pid: Pid of couch_index:init/1, specifically an mrview index. + + Returns a state map for an index that includes the following fields: + - collator_versions + - compact_running + - db_name + - idx_name + - language + - pending_updates + - purge_seq + - signature + - sizes + - update_options + - update_seq + - updater_running + - view_file_path + - waiting_clients + - waiting_commit + + --- + ", []); +help(view_state) -> + io:format(" + view_state(PidOrIdxState) + view_state(Pid, ViewName) + view_state(IdxState, ViewName) + -------------- + + PidOrIdxState: Pid of couch_index:init/1, specifically an mrview index, or the state + of an mrview index. + Pid: Pid of couch_index:init/1, specifically an mrview index. + IdxState: State of an mrview index (#mrst{} record). + ViewName: Name of the view to be queried or undefined. + + Returns a state map for a ViewName if specified or all views if not that includes the + following fields: + - btree_size + - def + - id_num + - options + - purge_seq + - reduce_funs + - update_seq + + --- + ", []); +help(index_view_state) -> + io:format(" + index_view_state(Pid) + index_view_state(Pid, ViewName) + -------------- + + Pid: Pid of couch_index:init/1, specifically an mrview index. + ViewName: Name of the view to be queried or undefined. + + Returns a state map that includes the index state returned by index_state/1 and the view + state returned by view_state/2. Like view_state/2, a ViewName can be specified or not. + + --- + ", []); +help(index_report) -> + io:format(" + index_report(Pid) + -------------- + + Pid: Pid of couch_index:init/1, specifically an mrview index. + + Prints a report for the index state of an mrview index that includes the following fields: + - signature + - db_name + - idx_name + - update_seq + - purge_seq + - view_file_path + - pending_updates + + The output will look similar to: + + |info | value + | collator_versions | 153.112 + | compact_running | false + | db_name | shards/00000000-ffffffff/dbv1.1658179540 + | idx_name | _design/dbv1ddoc + | language | javascript + | pending_updates | 0 + | purge_seq | 0 + | signature | a967fb72089e71e870f790f32bcc6a55 + | sizes | {[{file,4264},{active,163},{external,51}]} + | update_options | + | update_seq | 3 + | updater_running | false + | view_file_path | .shards/00000000-ffffffff/dbv1.1658179540_design/mrview/a967fb72089e71e870f790f32bcc6a55.view + | waiting_clients | 0 + | waiting_commit | false + + --- + ", []); +help(view_report) -> + io:format(" + view_report(PidOrIdxState) + view_report(Pid, ViewName) + view_report(IdxState, ViewName) + -------------- + + PidOrIdxState: Pid of couch_index:init/1, specifically an mrview index, or the state + of an mrview index. + Pid: Pid of couch_index:init/1, specifically an mrview index. + IdxState: State of an mrview index (#mrst{} record). + ViewName: Name of the view to be queried or undefined. + + Prints a report for a ViewName if specified or all views if not that includes the following + fields: + - id_num + - update_seq + - purge_seq + - reduce_funs + - def + - btree_size + - options + + The output will look similar to: + + dbv1view + |info | value + | btree_size | 51 + | def | function(doc){emit(doc.id, 1);} + | id_num | 0 + | options | + | purge_seq | 0 + | reduce_funs | + | update_seq | 3 + dbv2view + |info | value + | btree_size | 50 + | def | function(doc){emit(doc.id, 2);} + | id_num | 1 + | options | + | purge_seq | 0 + | reduce_funs | _sum + | update_seq | 3 + + --- + ", []); +help(index_view_report) -> + io:format(" + index_view_report(Pid) + index_view_report(Pid, ViewName) + -------------- + + Pid: Pid of couch_index:init/1, specifically an mrview index. + ViewName: Name of the view to be queried or undefined. + + Prints a report for the index state and views of an mrview index. The report includes the following + fields for an index state: + - signature + - db_name + - idx_name + - update_seq + - purge_seq + - view_file_path + - pending_updates + The report also includes the following fields for a ViewName if specified or all views if not: + - id_num + - update_seq + - purge_seq + - reduce_funs + - def + - btree_size + - options + + The output will look similar to: + + |info | value + | collator_versions | 153.112 + | compact_running | false + | db_name | shards/00000000-ffffffff/dbv1.1658179540 + | idx_name | _design/dbv1ddoc + | language | javascript + | pending_updates | 0 + | purge_seq | 0 + | signature | a967fb72089e71e870f790f32bcc6a55 + | sizes | {[{file,4264},{active,163},{external,51}]} + | update_options | + | update_seq | 3 + | updater_running | false + | view_file_path | .shards/00000000-ffffffff/dbv1.1658179540_design/mrview/a967fb72089e71e870f790f32bcc6a55.view + | waiting_clients | 0 + | waiting_commit | false + dbv1view + |info | value + | btree_size | 51 + | def | function(doc){emit(doc.id, 1);} + | id_num | 0 + | options | + | purge_seq | 0 + | reduce_funs | + | update_seq | 3 + dbv2view + |info | value + | btree_size | 50 + | def | function(doc){emit(doc.id, 2);} + | id_num | 1 + | options | + | purge_seq | 0 + | reduce_funs | _sum + | update_seq | 3 + --- ", []); help(Unknown) -> @@ -48,3 +280,158 @@ view_signature(DbName, DDocName) -> {ok, DDoc} = couch_db:open_doc_int(Db, <<"_design/", DDocName/binary>>, []), {ok, IdxState} = couch_mrview_util:ddoc_to_mrst(DDocName, DDoc), couch_util:to_hex(IdxState#mrst.sig). + +index_state(Pid) when is_pid(Pid) -> + {ok, IdxState} = couch_index:get_state(Pid, 0), + case IdxState of + #mrst{} -> + {ok, Info} = couch_index:get_info(Pid), + Sig = IdxState#mrst.sig, + DbName = IdxState#mrst.db_name, + State = + Info ++ + [ + {signature, Sig}, + {db_name, DbName}, + {idx_name, IdxState#mrst.idx_name}, + {view_file_path, couch_mrview_util:index_file(DbName, Sig)} + ], + {ok, maps:from_list(State)}; + _ -> + {error, not_mrview_index} + end. + +view_state(PidOrIdxState) -> + view_state(PidOrIdxState, undefined). + +view_state(Pid, ViewName) when is_pid(Pid) -> + {ok, IdxState} = couch_index:get_state(Pid, 0), + view_state(IdxState, ViewName); +view_state(IdxState, ViewName) -> + case IdxState of + #mrst{} -> + MrViews = lists:foldl( + fun(MrView, Acc) -> + {Name, ReduceFuns} = + case MrView#mrview.reduce_funs of + [] -> + {hd(MrView#mrview.map_names), []}; + _ -> + % reduce_funs contains tuples of {Name, ReduceFuns} + hd(MrView#mrview.reduce_funs) + end, + View = #{ + id_num => MrView#mrview.id_num, + update_seq => MrView#mrview.update_seq, + purge_seq => MrView#mrview.purge_seq, + reduce_funs => ReduceFuns, + def => MrView#mrview.def, + btree_size => couch_btree:size(MrView#mrview.btree), + options => MrView#mrview.options + }, + maps:put(Name, View, Acc) + end, + #{}, + IdxState#mrst.views + ), + case ViewName of + undefined -> + {ok, MrViews}; + _ -> + case maps:get(ViewName, MrViews) of + {badkey, Key} -> + io:format("No view named ~p was found.", [Key]), + {error, {badkey, Key}}; + Value -> + {ok, #{ViewName => Value}} + end + end; + _ -> + {error, not_mrview_index} + end. + +index_view_state(Pid) when is_pid(Pid) -> + index_view_state(Pid, undefined). + +index_view_state(Pid, ViewName) when is_pid(Pid) -> + {ok, IdxState} = index_state(Pid), + {ok, ViewState} = view_state(Pid, ViewName), + {ok, maps:put(views, ViewState, IdxState)}. + +index_report(Pid) when is_pid(Pid) -> + case index_state(Pid) of + {ok, IdxState} -> + Sig = maps:get(signature, IdxState), + IdxState2 = maps:put(signature, couch_util:to_hex(Sig), IdxState), + % Convert collator versions to strings to print pretty + IdxState3 = convert_collator_versions_to_strings(IdxState2), + IdxState4 = maps:update_with(view_file_path, fun format_view_path/1, IdxState3), + couch_debug:print_report_with_info_width(maps:to_list(IdxState4), 21); + Error -> + Error + end. + +view_report(PidOrIdxState) -> + view_report(PidOrIdxState, undefined). + +view_report(Pid, ViewName) when is_pid(Pid) -> + {ok, IdxState} = couch_index:get_state(Pid, 0), + view_report(IdxState, ViewName); +view_report(IdxState, ViewName) -> + case view_state(IdxState, ViewName) of + {ok, ViewState} -> + lists:foreach( + fun({Name, Info}) -> + io:format("~s~n", [binary_to_list(Name)]), + couch_debug:print_report_with_info_width(maps:to_list(Info), 15) + end, + maps:to_list(ViewState) + ); + Error -> + Error + end. + +index_view_report(Pid) when is_pid(Pid) -> + index_view_report(Pid, undefined). +index_view_report(Pid, ViewName) when is_pid(Pid) -> + case index_view_state(Pid) of + {ok, State} -> + AllViews = maps:get(views, State), + Views = + case ViewName of + undefined -> + AllViews; + _ -> + #{ViewName => maps:get(ViewName, AllViews)} + end, + Sig = maps:get(signature, State), + State2 = maps:put(signature, couch_util:to_hex(Sig), State), + % Convert collator versions to strings to print pretty + State3 = convert_collator_versions_to_strings(State2), + State4 = maps:update_with(view_file_path, fun format_view_path/1, State3), + couch_debug:print_report_with_info_width( + maps:to_list(maps:without([views], State4)), 21 + ), + lists:foreach( + fun({Name, Info}) -> + io:format("~s~n", [binary_to_list(Name)]), + couch_debug:print_report_with_info_width(maps:to_list(Info), 15) + end, + maps:to_list(Views) + ); + Error -> + Error + end. + +convert_collator_versions_to_strings(State) -> + CollatorVersions = lists:map( + fun(Version) -> + binary_to_list(Version) + end, + maps:get(collator_versions, State) + ), + maps:put(collator_versions, CollatorVersions, State). + +format_view_path(ViewFilePath) -> + BaseDir = config:get("couchdb", "view_index_dir"), + lists:flatten(string:replace(ViewFilePath, BaseDir ++ "/", "")). |