feat(dsrepl): release log entries occasionally
Also make tracepoints in `apply/3` callback implementation more uniform.
This commit is contained in:
parent
b6894c18fa
commit
2705226eb5
|
@ -579,6 +579,10 @@ list_nodes() ->
|
||||||
%% Too large for normal operation, need better backpressure mechanism.
|
%% Too large for normal operation, need better backpressure mechanism.
|
||||||
-define(RA_TIMEOUT, 60 * 1000).
|
-define(RA_TIMEOUT, 60 * 1000).
|
||||||
|
|
||||||
|
%% How often to release Raft logs?
|
||||||
|
%% Each N log entries mark everything up to the last N entries "releasable".
|
||||||
|
-define(RA_RELEASE_LOG_FREQ, 1000).
|
||||||
|
|
||||||
-define(SAFE_ERPC(EXPR),
|
-define(SAFE_ERPC(EXPR),
|
||||||
try
|
try
|
||||||
EXPR
|
EXPR
|
||||||
|
@ -746,6 +750,8 @@ ra_drop_shard(DB, Shard) ->
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
-define(pd_ra_idx_need_release, '$emqx_ds_raft_idx_need_release').
|
||||||
|
|
||||||
-spec init(_Args :: map()) -> ra_state().
|
-spec init(_Args :: map()) -> ra_state().
|
||||||
init(#{db := DB, shard := Shard}) ->
|
init(#{db := DB, shard := Shard}) ->
|
||||||
#{db_shard => {DB, Shard}, latest => 0}.
|
#{db_shard => {DB, Shard}, latest => 0}.
|
||||||
|
@ -753,7 +759,7 @@ init(#{db := DB, shard := Shard}) ->
|
||||||
-spec apply(ra_machine:command_meta_data(), ra_command(), ra_state()) ->
|
-spec apply(ra_machine:command_meta_data(), ra_command(), ra_state()) ->
|
||||||
{ra_state(), _Reply, _Effects}.
|
{ra_state(), _Reply, _Effects}.
|
||||||
apply(
|
apply(
|
||||||
#{index := RaftIdx},
|
RaftMeta,
|
||||||
#{
|
#{
|
||||||
?tag := ?BATCH,
|
?tag := ?BATCH,
|
||||||
?batch_messages := MessagesIn
|
?batch_messages := MessagesIn
|
||||||
|
@ -765,17 +771,17 @@ apply(
|
||||||
Result = emqx_ds_storage_layer:store_batch(DBShard, Messages, #{}),
|
Result = emqx_ds_storage_layer:store_batch(DBShard, Messages, #{}),
|
||||||
State = State0#{latest := Latest},
|
State = State0#{latest := Latest},
|
||||||
set_ts(DBShard, Latest),
|
set_ts(DBShard, Latest),
|
||||||
%% TODO: Need to measure effects of changing frequency of `release_cursor`.
|
Effects = try_release_log(RaftMeta, State),
|
||||||
Effect = {release_cursor, RaftIdx, State},
|
Effects =/= [] andalso ?tp(ds_ra_effects, #{effects => Effects, meta => RaftMeta}),
|
||||||
{State, Result, Effect};
|
{State, Result, Effects};
|
||||||
apply(
|
apply(
|
||||||
_RaftMeta,
|
RaftMeta,
|
||||||
#{?tag := add_generation, ?since := Since},
|
#{?tag := add_generation, ?since := Since},
|
||||||
#{db_shard := DBShard, latest := Latest0} = State0
|
#{db_shard := DBShard, latest := Latest0} = State0
|
||||||
) ->
|
) ->
|
||||||
?tp(
|
?tp(
|
||||||
info,
|
info,
|
||||||
ds_replication_layer_add_generation,
|
ds_ra_add_generation,
|
||||||
#{
|
#{
|
||||||
shard => DBShard,
|
shard => DBShard,
|
||||||
since => Since
|
since => Since
|
||||||
|
@ -785,15 +791,17 @@ apply(
|
||||||
Result = emqx_ds_storage_layer:add_generation(DBShard, Timestamp),
|
Result = emqx_ds_storage_layer:add_generation(DBShard, Timestamp),
|
||||||
State = State0#{latest := Latest},
|
State = State0#{latest := Latest},
|
||||||
set_ts(DBShard, Latest),
|
set_ts(DBShard, Latest),
|
||||||
{State, Result};
|
Effects = release_log(RaftMeta, State),
|
||||||
|
Effects =/= [] andalso ?tp(ds_ra_effects, #{effects => Effects, meta => RaftMeta}),
|
||||||
|
{State, Result, Effects};
|
||||||
apply(
|
apply(
|
||||||
_RaftMeta,
|
RaftMeta,
|
||||||
#{?tag := update_config, ?since := Since, ?config := Opts},
|
#{?tag := update_config, ?since := Since, ?config := Opts},
|
||||||
#{db_shard := DBShard, latest := Latest0} = State0
|
#{db_shard := DBShard, latest := Latest0} = State0
|
||||||
) ->
|
) ->
|
||||||
?tp(
|
?tp(
|
||||||
notice,
|
notice,
|
||||||
ds_replication_layer_update_config,
|
ds_ra_update_config,
|
||||||
#{
|
#{
|
||||||
shard => DBShard,
|
shard => DBShard,
|
||||||
config => Opts,
|
config => Opts,
|
||||||
|
@ -803,7 +811,9 @@ apply(
|
||||||
{Timestamp, Latest} = ensure_monotonic_timestamp(Since, Latest0),
|
{Timestamp, Latest} = ensure_monotonic_timestamp(Since, Latest0),
|
||||||
Result = emqx_ds_storage_layer:update_config(DBShard, Timestamp, Opts),
|
Result = emqx_ds_storage_layer:update_config(DBShard, Timestamp, Opts),
|
||||||
State = State0#{latest := Latest},
|
State = State0#{latest := Latest},
|
||||||
{State, Result};
|
Effects = release_log(RaftMeta, State),
|
||||||
|
Effects =/= [] andalso ?tp(ds_ra_effects, #{effects => Effects, meta => RaftMeta}),
|
||||||
|
{State, Result, Effects};
|
||||||
apply(
|
apply(
|
||||||
_RaftMeta,
|
_RaftMeta,
|
||||||
#{?tag := drop_generation, ?generation := GenId},
|
#{?tag := drop_generation, ?generation := GenId},
|
||||||
|
@ -811,7 +821,7 @@ apply(
|
||||||
) ->
|
) ->
|
||||||
?tp(
|
?tp(
|
||||||
info,
|
info,
|
||||||
ds_replication_layer_drop_generation,
|
ds_ra_drop_generation,
|
||||||
#{
|
#{
|
||||||
shard => DBShard,
|
shard => DBShard,
|
||||||
generation => GenId
|
generation => GenId
|
||||||
|
@ -828,7 +838,7 @@ apply(
|
||||||
set_ts(DBShard, Latest),
|
set_ts(DBShard, Latest),
|
||||||
?tp(
|
?tp(
|
||||||
debug,
|
debug,
|
||||||
emqx_ds_replication_layer_storage_event,
|
ds_ra_storage_event,
|
||||||
#{
|
#{
|
||||||
shard => DBShard, payload => CustomEvent, latest => Latest
|
shard => DBShard, payload => CustomEvent, latest => Latest
|
||||||
}
|
}
|
||||||
|
@ -836,6 +846,44 @@ apply(
|
||||||
Effects = handle_custom_event(DBShard, Latest, CustomEvent),
|
Effects = handle_custom_event(DBShard, Latest, CustomEvent),
|
||||||
{State#{latest => Latest}, ok, Effects}.
|
{State#{latest => Latest}, ok, Effects}.
|
||||||
|
|
||||||
|
try_release_log(RaftMeta = #{index := CurrentIdx}, State) ->
|
||||||
|
%% NOTE
|
||||||
|
%% Release everything up to the last log entry, but only if there were more than
|
||||||
|
%% `?RA_RELEASE_LOG_FREQ` new entries since the last release.
|
||||||
|
case get_log_need_release(RaftMeta) of
|
||||||
|
undefined ->
|
||||||
|
[];
|
||||||
|
PrevIdx when ?RA_RELEASE_LOG_FREQ > CurrentIdx - PrevIdx ->
|
||||||
|
[];
|
||||||
|
_PrevIdx ->
|
||||||
|
%% TODO
|
||||||
|
%% Number of log entries is not the best metric. Because cursor release
|
||||||
|
%% means storage flush (see `emqx_ds_replication_snapshot:write/3`), we
|
||||||
|
%% should do that not too often (so the storage is happy with L0 SST size)
|
||||||
|
%% and not too rarely (so we don't accumulate huge Raft logs).
|
||||||
|
release_log(RaftMeta, State)
|
||||||
|
end.
|
||||||
|
|
||||||
|
release_log(RaftMeta = #{index := CurrentIdx}, State) ->
|
||||||
|
%% NOTE
|
||||||
|
%% Release everything up to the last log entry. This is important: any log entries
|
||||||
|
%% following `CurrentIdx` should not contribute to `State` (that will be recovered
|
||||||
|
%% from a snapshot).
|
||||||
|
update_log_need_release(RaftMeta),
|
||||||
|
{release_cursor, CurrentIdx, State}.
|
||||||
|
|
||||||
|
get_log_need_release(RaftMeta) ->
|
||||||
|
case erlang:get(?pd_ra_idx_need_release) of
|
||||||
|
undefined ->
|
||||||
|
update_log_need_release(RaftMeta),
|
||||||
|
undefined;
|
||||||
|
LastIdx ->
|
||||||
|
LastIdx
|
||||||
|
end.
|
||||||
|
|
||||||
|
update_log_need_release(#{index := CurrentIdx}) ->
|
||||||
|
erlang:put(?pd_ra_idx_need_release, CurrentIdx).
|
||||||
|
|
||||||
-spec tick(integer(), ra_state()) -> ra_machine:effects().
|
-spec tick(integer(), ra_state()) -> ra_machine:effects().
|
||||||
tick(TimeMs, #{db_shard := DBShard = {DB, Shard}, latest := Latest}) ->
|
tick(TimeMs, #{db_shard := DBShard = {DB, Shard}, latest := Latest}) ->
|
||||||
%% Leader = emqx_ds_replication_layer_shard:lookup_leader(DB, Shard),
|
%% Leader = emqx_ds_replication_layer_shard:lookup_leader(DB, Shard),
|
||||||
|
|
Loading…
Reference in New Issue