Skip to content

Commit 2889164

Browse files
Refactor parts of rabbit_definitions for dialyzability
1 parent 75701d3 commit 2889164

File tree

1 file changed

+87
-33
lines changed

1 file changed

+87
-33
lines changed

deps/rabbit/src/rabbit_definitions.erl

Lines changed: 87 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@
8080
'bindings' |
8181
'exchanges'.
8282

83-
-type definition_object() :: #{binary() => any()}.
83+
-type definition_key() :: binary() | atom().
84+
-type definition_object() :: #{definition_key() => any()}.
8485
-type definition_list() :: [definition_object()].
8586

8687
-type definitions() :: #{
@@ -104,18 +105,73 @@ maybe_load_definitions() ->
104105
{error, E} -> {error, E}
105106
end.
106107

107-
validate_definitions(Defs) when is_list(Defs) ->
108+
-spec validate_parsing_of_doc(any()) -> boolean().
109+
validate_parsing_of_doc(Body) when is_binary(Body) ->
110+
case decode(Body) of
111+
{ok, _Map} -> true;
112+
{error, _Err} -> false
113+
end.
114+
115+
-spec validate_parsing_of_doc_collection(list(any())) -> boolean().
116+
validate_parsing_of_doc_collection(Defs) when is_list(Defs) ->
108117
lists:foldl(fun(_Body, false) ->
109-
false;
110-
(Body, true) ->
111-
case decode(Body) of
112-
{ok, _Map} -> true;
113-
{error, _Err} -> false
114-
end
115-
end, true, Defs);
118+
false;
119+
(Body, true) ->
120+
case decode(Body) of
121+
{ok, _Map} -> true;
122+
{error, _Err} -> false
123+
end
124+
end, true, Defs).
125+
126+
-spec filter_orphaned_objects(definition_list()) -> definition_list().
127+
filter_orphaned_objects(Maps) ->
128+
lists:filter(fun(M) -> maps:get(<<"vhost">>, M, undefined) =:= undefined end, Maps).
129+
130+
-spec any_orphaned_objects(definition_list()) -> boolean().
131+
any_orphaned_objects(Maps) ->
132+
length(filter_orphaned_objects(Maps)) > 0.
133+
134+
-spec any_orphaned_in_definitions(definitions()) -> boolean().
135+
any_orphaned_in_definitions(DefsMap) ->
136+
any_orphaned_in_category(DefsMap, <<"queues">>)
137+
orelse any_orphaned_in_category(DefsMap, <<"exchanges">>)
138+
orelse any_orphaned_in_category(DefsMap, <<"bindings">>).
139+
140+
-spec any_orphaned_in_category(definitions(), definition_category() | binary()) -> boolean().
141+
any_orphaned_in_category(DefsMap, Category) ->
142+
%% try both binary and atom keys
143+
any_orphaned_objects(maps:get(Category, DefsMap,
144+
maps:get(rabbit_data_coercion:to_atom(Category), DefsMap, []))).
145+
146+
-spec validate_orphaned_objects_in_doc_collection(list() | binary()) -> boolean().
147+
validate_orphaned_objects_in_doc_collection(Defs) when is_list(Defs) ->
148+
lists:foldl(fun(_Body, false) ->
149+
false;
150+
(Body, true) ->
151+
validate_parsing_of_doc(Body)
152+
end, true, Defs).
153+
154+
-spec validate_orphaned_objects_in_doc(binary()) -> boolean().
155+
validate_orphaned_objects_in_doc(Body) when is_binary(Body) ->
156+
case decode(Body) of
157+
{ok, DefsMap} ->
158+
AnyOrphaned = any_orphaned_in_definitions(DefsMap),
159+
case AnyOrphaned of
160+
true ->
161+
log_an_error_about_orphaned_objects();
162+
false -> ok
163+
end,
164+
AnyOrphaned;
165+
{error, _Err} -> false
166+
end.
167+
168+
-spec validate_definitions(list(any()) | binary()) -> boolean().
169+
validate_definitions(Defs) when is_list(Defs) ->
170+
validate_parsing_of_doc_collection(Defs) andalso
171+
validate_orphaned_objects_in_doc_collection(Defs);
116172
validate_definitions(Body) when is_binary(Body) ->
117173
case decode(Body) of
118-
{ok, _Map} -> true;
174+
{ok, Defs} -> validate_orphaned_objects_in_doc(Defs);
119175
{error, _Err} -> false
120176
end.
121177

@@ -409,13 +465,10 @@ should_skip_if_unchanged() ->
409465
ReachedTargetClusterSize = rabbit_nodes:reached_target_cluster_size(),
410466
OptedIn andalso ReachedTargetClusterSize.
411467

412-
-spec any_orphaned_objects(list(#{atom() => any()})) -> boolean().
413-
any_orphaned_objects(Maps) ->
414-
Filtered = lists:filter(fun(M) ->
415-
maps:get(<<"vhost">>, M, undefined) =:= undefined
416-
end, Maps),
417-
length(Filtered) > 0.
418-
468+
log_an_error_about_orphaned_objects() ->
469+
rabbit_log:error("Definitions import: some queues, exchanges or bindings in the definition file "
470+
"are missing the virtual host field. Such files are produced when definitions of "
471+
"a single virtual host are exported. They cannot be used to import definitions at boot time").
419472

420473
-spec apply_defs(Map :: #{atom() => any()}, ActingUser :: rabbit_types:username()) -> 'ok' | {error, term()}.
421474

@@ -435,15 +488,11 @@ apply_defs(Map, ActingUser, SuccessFun) when is_function(SuccessFun) ->
435488
%% If any of the queues or exchanges do not have virtual hosts set,
436489
%% this definition file was a virtual-host specific import. They cannot be applied
437490
%% as "complete" definition imports, most notably, imported on boot.
438-
HasQueuesWithoutVirtualHostField = any_orphaned_objects(maps:get(queues, Map, [])),
439-
HasExchangesWithoutVirtualHostField = any_orphaned_objects(maps:get(exchanges, Map, [])),
440-
HasBindingsWithoutVirtualHostField = any_orphaned_objects(maps:get(bindings, Map, [])),
491+
AnyOrphaned = any_orphaned_in_definitions(Map),
441492

442-
case (HasQueuesWithoutVirtualHostField orelse HasExchangesWithoutVirtualHostField orelse HasBindingsWithoutVirtualHostField) of
493+
case AnyOrphaned of
443494
true ->
444-
rabbit_log:error("Definitions import: some queues, exchanges or bindings in the definition file "
445-
"are missing the virtual host field. Such files are produced when definitions of "
446-
"a single virtual host are exported. They cannot be used to import definitions at boot time"),
495+
log_an_error_about_orphaned_objects(),
447496
throw({error, invalid_definitions_file});
448497
false ->
449498
ok
@@ -612,8 +661,11 @@ do_concurrent_for_all(List, WorkPoolFun) ->
612661
fun() ->
613662
_ = try
614663
WorkPoolFun(M)
615-
catch {error, E} -> gatherer:in(Gatherer, {error, E});
616-
_:E:_Stacktrace -> gatherer:in(Gatherer, {error, E})
664+
catch {error, E} -> gatherer:in(Gatherer, {error, E});
665+
_:E:Stacktrace ->
666+
rabbit_log:debug("Definition import: a work pool operation has thrown an exception ~st, stacktrace: ~p",
667+
[E, Stacktrace]),
668+
gatherer:in(Gatherer, {error, E})
617669
end,
618670
gatherer:finish(Gatherer)
619671
end)
@@ -882,21 +934,23 @@ filter_out_existing_queues(VHost, Queues) ->
882934

883935
build_queue_data(Queue) ->
884936
VHost = maps:get(<<"vhost">>, Queue, undefined),
885-
Rec = rv(VHost, queue, <<"name">>, Queue),
886-
{Rec, VHost}.
937+
case VHost of
938+
undefined -> undefined;
939+
Value ->
940+
Rec = rv(Value, queue, <<"name">>, Queue),
941+
{Rec, VHost}
942+
end.
887943

888944
build_filtered_map([], AccMap) ->
889945
{ok, AccMap};
890946
build_filtered_map([Queue|Rest], AccMap0) ->
891-
{Rec, VHost} = build_queue_data(Queue),
892947
%% If virtual host is not specified in a queue,
893948
%% this definition file is likely virtual host-specific.
894949
%%
895950
%% Skip such queues.
896-
case VHost of
897-
undefined ->
898-
build_filtered_map(Rest, AccMap0);
899-
_Other ->
951+
case build_queue_data(Queue) of
952+
undefined -> build_filtered_map(Rest, AccMap0);
953+
{Rec, VHost} when VHost =/= undefined ->
900954
case rabbit_amqqueue:exists(Rec) of
901955
false ->
902956
AccMap1 = maps:update_with(VHost, fun(V) -> V + 1 end, 1, AccMap0),

0 commit comments

Comments
 (0)