perf(config): read zone conf once

This commit is contained in:
William Yang 2023-05-23 16:11:22 +02:00
parent feecd53436
commit 88f9782db0
1 changed files with 84 additions and 16 deletions

View File

@ -189,23 +189,11 @@ find_raw(KeyPath) ->
-spec get_zone_conf(atom(), emqx_utils_maps:config_key_path()) -> term().
get_zone_conf(Zone, KeyPath) ->
case find(?ZONE_CONF_PATH(Zone, KeyPath)) of
%% not found in zones, try to find the global config
{not_found, _, _} ->
?MODULE:get(KeyPath);
{ok, Value} ->
Value
end.
?MODULE:get(?ZONE_CONF_PATH(Zone, KeyPath)).
-spec get_zone_conf(atom(), emqx_utils_maps:config_key_path(), term()) -> term().
get_zone_conf(Zone, KeyPath, Default) ->
case find(?ZONE_CONF_PATH(Zone, KeyPath)) of
%% not found in zones, try to find the global config
{not_found, _, _} ->
?MODULE:get(KeyPath, Default);
{ok, Value} ->
Value
end.
?MODULE:get(?ZONE_CONF_PATH(Zone, KeyPath), Default).
-spec put_zone_conf(atom(), emqx_utils_maps:config_key_path(), term()) -> ok.
put_zone_conf(Zone, KeyPath, Conf) ->
@ -245,8 +233,10 @@ erase(RootName) ->
-spec put(emqx_utils_maps:config_key_path(), term()) -> ok.
put(KeyPath, Config) ->
Putter = fun(Path, Map, Value) ->
emqx_utils_maps:deep_put(Path, Map, Value)
Putter = fun(Path, Map, Value0) ->
Value = emqx_utils_maps:deep_put(Path, Map, Value0),
maybe_update_zone(KeyPath, Value0),
Value
end,
do_put(?CONF, Putter, KeyPath, Config).
@ -596,6 +586,15 @@ save_to_app_env(AppEnvs0) ->
-spec save_to_config_map(config(), raw_config()) -> ok.
save_to_config_map(Conf, RawConf) ->
?MODULE:put(Conf),
try emqx_config:get([zones]) of
Zones when is_map(Zones) ->
init_default_zone()
catch
error:{config_not_found, [zones]} ->
%% emqx schema is not loaded.
%% note, don't trust get_root_names/0
skip
end,
?MODULE:put_raw(RawConf).
-spec save_to_override_conf(boolean(), raw_config(), update_opts()) -> ok | {error, term()}.
@ -788,3 +787,72 @@ to_atom_conf_path(Path, OnFail) ->
V
end
end.
%% @doc Init zones under root `zones'
%% 1. ensure one `default' zone as it is referenced by listeners.
%% if default zone is unset, clone all default values from `GlobalDefaults'
%% if default zone is set, values are merged with `GlobalDefaults'
%% 2. For any user defined zones, merge with `GlobalDefaults'
%%
%% note1, this should be called as post action after emqx_config terms (zones, and GlobalDefaults)
%% are written in the PV storage during emqx config loading/initialization.
-spec init_default_zone() -> ok.
init_default_zone() ->
Zones =
case ?MODULE:get([zones], #{}) of
#{default := _DefaultZone} = Z1 ->
Z1;
Z2 ->
Z2#{default => #{}}
end,
GlobalDefaults = maps:from_list([{K, ?MODULE:get([K])} || K <- zone_roots()]),
NewZones = maps:map(
fun(_ZoneName, ZoneVal) ->
merge_with_global_defaults(ZoneVal, GlobalDefaults)
end,
Zones
),
?MODULE:put([zones], NewZones).
%% @TODO just use deep merge?
-spec merge_with_global_defaults(map(), map()) -> map().
merge_with_global_defaults(Val, Defaults) ->
maps:fold(
fun(K, V, Acc) ->
case maps:get(K, Acc, ?CONFIG_NOT_FOUND_MAGIC) of
?CONFIG_NOT_FOUND_MAGIC ->
%% Use the value of global default
Acc#{K => V};
Override ->
%% Merge with overrides
Acc#{K => emqx_utils_maps:deep_merge(V, Override)}
end
end,
Val,
Defaults
).
%% @doc Update zones in case global defaults are changed.
-spec maybe_update_zone(runtime_config_key_path(), Val :: term()) -> skip | ok.
maybe_update_zone([], _Value) ->
skip;
maybe_update_zone([RootName | _T] = Path, Value) ->
case lists:member(RootName, zone_roots()) of
false ->
skip;
true ->
Zones = ?MODULE:get([zones], #{}),
NewZones = maps:map(
fun(_ZoneName, ZoneVal) ->
%% @TODO we should not overwrite if it is a user defined value
emqx_utils_maps:deep_put(Path, ZoneVal, Value)
end,
Zones
),
?MODULE:put([zones], NewZones),
ok
end.
-spec zone_roots() -> [atom()].
zone_roots() ->
lists:map(fun atom/1, emqx_zone_schema:roots()).