Skip to content

Commit 611cdcc

Browse files
authored
Merge pull request #293 from amazon-mq/md/manifest-resolved-counters
Set first offset/timestamp counters when a manifest is resolved
2 parents a5e6a7e + d1c8cf0 commit 611cdcc

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

src/rabbitmq_stream_s3_manifest_replica.erl

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,12 @@ init([]) ->
205205
handle_call({put_manifest, StreamId, Manifest, Epoch}, _From, State) ->
206206
write_manifest(StreamId, Manifest, Epoch),
207207
{reply, ok, State};
208-
handle_call({sync, StreamId, Seq, Epoch, Manifest, WriterNode}, _From, #state{seqs = Seqs} = State) ->
209-
Seqs1 = maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs),
208+
handle_call(
209+
{sync, StreamId, Seq, Epoch, Manifest, WriterNode},
210+
_From,
211+
#state{seqs = Seqs, contexts = Ctxs} = State
212+
) ->
213+
Seqs1 = maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs, Ctxs),
210214
{reply, ok, State#state{seqs = Seqs1}};
211215
handle_call(
212216
{apply_edits, StreamId, Edits, Seq, Epoch, WriterNode}, _From, #state{seqs = Seqs} = State
@@ -281,8 +285,11 @@ handle_cast({apply_edit, StreamId, Edit}, State) ->
281285
ok
282286
end,
283287
{noreply, State};
284-
handle_cast({sync, StreamId, Seq, Epoch, Manifest, WriterNode}, #state{seqs = Seqs} = State) ->
285-
Seqs1 = maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs),
288+
handle_cast(
289+
{sync, StreamId, Seq, Epoch, Manifest, WriterNode},
290+
#state{seqs = Seqs, contexts = Ctxs} = State
291+
) ->
292+
Seqs1 = maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs, Ctxs),
286293
{noreply, State#state{seqs = Seqs1}};
287294
handle_cast({apply_edits, StreamId, Edits, Seq, Epoch, WriterNode}, #state{seqs = Seqs} = State) ->
288295
case maps:get(StreamId, Seqs, undefined) of
@@ -367,7 +374,7 @@ apply_edits_catching(StreamId, Edits, Manifest0) ->
367374
%% next gap triggers a re-sync. Drop any sync that is not at least as new as
368375
%% what is recorded, comparing epoch first and then sequence so a higher epoch
369376
%% always wins regardless of where its sequence restarted.
370-
maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs) ->
377+
maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs, Ctxs) ->
371378
Recorded = maps:get(StreamId, Seqs, undefined),
372379
case is_stale_sync(Epoch, Seq, Recorded) of
373380
true ->
@@ -382,6 +389,7 @@ maybe_apply_sync(StreamId, Seq, Epoch, Manifest, WriterNode, Seqs) ->
382389
Seqs;
383390
false ->
384391
write_manifest(StreamId, Manifest, Epoch),
392+
seed_first_offset_counter(StreamId, Manifest, Ctxs),
385393
Seqs#{StreamId => {Seq, Epoch, WriterNode}}
386394
end.
387395

@@ -475,6 +483,25 @@ maybe_evaluate_retention(
475483
) ->
476484
ok.
477485

486+
%% Seed the osiris first-offset and first-timestamp counters from the manifest
487+
%% on sync. Without this, the counters reflect only the local tier until the
488+
%% first retention evaluation or edit arrives, which may never happen on an idle
489+
%% stream.
490+
seed_first_offset_counter(_StreamId, #manifest{entries = <<>>}, _Ctxs) ->
491+
ok;
492+
seed_first_offset_counter(
493+
StreamId, #manifest{first_offset = ManifestFirst, first_timestamp = ManifestFirstTs}, Ctxs
494+
) ->
495+
case maps:get(StreamId, Ctxs, undefined) of
496+
#replica_ctx{counter = Cnt} ->
497+
LocalFirst = counters:get(Cnt, ?C_OSIRIS_LOG_FIRST_OFFSET),
498+
counters:put(Cnt, ?C_OSIRIS_LOG_FIRST_OFFSET, min(LocalFirst, ManifestFirst)),
499+
LocalFirstTs = counters:get(Cnt, ?C_OSIRIS_LOG_FIRST_TIMESTAMP),
500+
counters:put(Cnt, ?C_OSIRIS_LOG_FIRST_TIMESTAMP, min(LocalFirstTs, ManifestFirstTs));
501+
undefined ->
502+
ok
503+
end.
504+
478505
-ifdef(TEST).
479506
-include_lib("eunit/include/eunit.hrl").
480507

src/rabbitmq_stream_s3_replica_reader.erl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2210,9 +2210,20 @@ on_manifest_resolved(#manifest{next_offset = 0}, State) ->
22102210
inc(State, ?C_MANIFESTS_RESOLVED_EMPTY, 1),
22112211
update_manifest_gauges(#manifest{}, State),
22122212
State;
2213-
on_manifest_resolved(#manifest{} = Manifest, State) ->
2213+
on_manifest_resolved(
2214+
#manifest{first_offset = ManifestFirst, first_timestamp = ManifestFirstTs} = Manifest,
2215+
#state{cfg = #cfg{counter = Cnt}} = State
2216+
) ->
22142217
inc(State, ?C_MANIFESTS_RESOLVED, 1),
22152218
update_manifest_gauges(Manifest, State),
2219+
%% Seed the osiris first-offset and first-timestamp counters immediately so
2220+
%% the management UI reflects the remote tier's range without waiting for the
2221+
%% first retention evaluation or manifest edit. Without this, an idle stream
2222+
%% (or one that hasn't persisted yet) reports only the local segment window.
2223+
LocalFirst = counters:get(Cnt, ?C_OSIRIS_LOG_FIRST_OFFSET),
2224+
counters:put(Cnt, ?C_OSIRIS_LOG_FIRST_OFFSET, min(LocalFirst, ManifestFirst)),
2225+
LocalFirstTs = counters:get(Cnt, ?C_OSIRIS_LOG_FIRST_TIMESTAMP),
2226+
counters:put(Cnt, ?C_OSIRIS_LOG_FIRST_TIMESTAMP, min(LocalFirstTs, ManifestFirstTs)),
22162227
State.
22172228

22182229
on_remote_retention_deleted(Refs, StreamId, State) ->

0 commit comments

Comments
 (0)