@@ -1223,7 +1223,8 @@ get_timeout(_) -> khepri_app:get_default_timeout().
12231223% %
12241224% % @private
12251225
1226- clear_cache (_StoreId ) ->
1226+ clear_cache (StoreId ) ->
1227+ clear_cached_effective_machine_version (StoreId ),
12271228 ok .
12281229
12291230- spec sending_sync_command_locally (StoreId ) -> ok when
@@ -1311,6 +1312,9 @@ init(Params) ->
13111312 % % state format.
13121313 State = khepri_machine_v0 :init (Params ),
13131314
1315+ # config {store_id = StoreId } = get_config (State ),
1316+ cache_effective_machine_version (StoreId , 0 ),
1317+
13141318 % % Create initial "schema" if provided.
13151319 Commands = maps :get (commands , Params , []),
13161320 State3 = lists :foldl (
@@ -1700,6 +1704,12 @@ apply(
17001704apply (Meta , {machine_version , OldMacVer , NewMacVer }, OldState ) ->
17011705 NewState = convert_state (OldState , OldMacVer , NewMacVer ),
17021706 Ret = {NewState , ok },
1707+
1708+ % % We cache the effective machine version for fast query from any
1709+ % % processes. This is useful because this machine version is used to
1710+ % % determine what a user of Khepri can or cannot do.
1711+ # config {store_id = StoreId } = get_config (NewState ),
1712+ cache_effective_machine_version (StoreId , NewMacVer ),
17031713 post_apply (Ret , Meta );
17041714apply (#{machine_version := MacVer } = Meta , UnknownCommand , State ) ->
17051715 Error = ? khepri_exception (
@@ -1926,32 +1936,62 @@ which_module(2) -> ?MODULE;
19261936which_module (1 ) -> ? MODULE ;
19271937which_module (0 ) -> ? MODULE .
19281938
1939+ - define (
1940+ PT_EFFECTIVE_MACVER (StoreId ),
1941+ {khepri , effective_machine_version , StoreId }).
1942+
19291943- spec effective_version (StoreId ) -> Ret when
19301944 StoreId :: khepri :store_id (),
19311945 Ret :: khepri :ok (EffectiveMacVer ) | khepri :error (),
19321946 EffectiveMacVer :: ra_machine :version ().
19331947% % @doc Returns the effective state machine version of the local Ra server.
1948+ % %
1949+ % % The effective machine version is queried from a cached value, not from the
1950+ % % actual Ra server, to be more efficient.
19341951
19351952effective_version (StoreId ) when ? IS_KHEPRI_STORE_ID (StoreId ) ->
1936- ThisNode = node (),
1937- RaServer = khepri_cluster :node_to_member (StoreId , ThisNode ),
1938- case ra_counters :counters (RaServer , [effective_machine_version ]) of
1939- #{effective_machine_version := EffectiveMacVer } ->
1940- {ok , EffectiveMacVer };
1941- _ ->
1942- case ra :member_overview (RaServer ) of
1943- {ok , #{effective_machine_version := EffectiveMacVer }, _ } ->
1944- {ok , EffectiveMacVer };
1945- {error , _ } = Error ->
1946- Reason = ? khepri_error (
1947- effective_machine_version_not_defined ,
1948- #{store_id => StoreId ,
1949- ra_server => RaServer ,
1950- error => Error }),
1951- {error , Reason }
1952- end
1953+ Key = ? PT_EFFECTIVE_MACVER (StoreId ),
1954+ try
1955+ EffectiveMacVer = persistent_term :get (Key ),
1956+ {ok , EffectiveMacVer }
1957+ catch
1958+ error :badarg ->
1959+ ThisNode = node (),
1960+ RaServer = khepri_cluster :node_to_member (StoreId , ThisNode ),
1961+ Reason = ? khepri_error (
1962+ effective_machine_version_not_defined ,
1963+ #{store_id => StoreId ,
1964+ ra_server => RaServer }),
1965+ {error , Reason }
19531966 end .
19541967
1968+ - spec cache_effective_machine_version (StoreId , EffectiveMacVer ) -> ok when
1969+ StoreId :: khepri :store_id (),
1970+ EffectiveMacVer :: ra_machine :version ().
1971+ % % @doc Caches effective machine version for fast query.
1972+ % %
1973+ % % The effective machine version is cached whenever the machine is initialised
1974+ % % and upgraded.
1975+ % %
1976+ % % @private
1977+
1978+ cache_effective_machine_version (StoreId , EffectiveMacVer ) ->
1979+ Key = ? PT_EFFECTIVE_MACVER (StoreId ),
1980+ persistent_term :put (Key , EffectiveMacVer ).
1981+
1982+ - spec clear_cached_effective_machine_version (StoreId ) -> ok when
1983+ StoreId :: khepri :store_id ().
1984+ % % @doc Clears the cached effective machine version.
1985+ % %
1986+ % % The cached effective machine version is cleared when the store is stopped.
1987+ % %
1988+ % % @private
1989+
1990+ clear_cached_effective_machine_version (StoreId ) ->
1991+ Key = ? PT_EFFECTIVE_MACVER (StoreId ),
1992+ _ = persistent_term :erase (Key ),
1993+ ok .
1994+
19551995- spec does_api_comply_with (Behaviour , MacVer | StoreId ) -> DoesUse when
19561996 Behaviour :: khepri_machine :api_behaviour (),
19571997 MacVer :: ra_machine :version (),
0 commit comments