@@ -85,7 +85,7 @@ BackfillState::Initial::react(const BackfillState::Triggered& evt)
8585 ceph_assert (backfill_state ().last_backfill_started == \
8686 peering_state ().earliest_backfill ());
8787 ceph_assert (peering_state ().is_backfilling ());
88- // initialize BackfillIntervals
88+ // initialize ReplicaBackfillIntervals
8989 for (const auto & bt : peering_state ().get_backfill_targets ()) {
9090 backfill_state ().peer_backfill_info [bt].reset (
9191 peering_state ().get_peer_last_backfill (bt));
@@ -134,13 +134,52 @@ void BackfillState::Enqueuing::maybe_update_range()
134134 if (e.is_update ()) {
135135 DEBUGDPP (" maybe_update_range(lambda): {} updated to ver {}" ,
136136 pg (), e.soid , e.version );
137- primary_bi.objects .erase (e.soid );
138- primary_bi.objects .insert (std::make_pair (e.soid ,
139- e.version ));
137+ if (e.written_shards .empty ()) {
138+ // Log entry updates all shards, replace all entries for e.soid
139+ primary_bi.objects .erase (e.soid );
140+ primary_bi.objects .insert (
141+ std::make_pair (e.soid ,
142+ std::make_pair (shard_id_t ::NO_SHARD,
143+ e.version )));
144+ } else {
145+ // Update backfill interval for shards modified by log entry
146+ std::map<shard_id_t ,eversion_t > versions;
147+ // Create map from existing entries in backfill entry
148+ const auto & [begin, end] = primary_bi.objects .equal_range (e.soid );
149+ for (const auto & entry : std::ranges::subrange (begin, end)) {
150+ const auto & [shard, version] = entry.second ;
151+ versions[shard] = version;
152+ }
153+ // Update entries in map that are modified by log entry
154+ bool uses_default = false ;
155+ for (const auto & shard : peering_state ().get_backfill_targets ()) {
156+ if (e.is_written_shard (shard.shard )) {
157+ versions.erase (shard.shard );
158+ uses_default = true ;
159+ } else {
160+ if (!versions.contains (shard.shard )) {
161+ versions[shard.shard ] = e.prior_version ;
162+ }
163+ // Else: keep existing version
164+ }
165+ }
166+ if (uses_default) {
167+ versions[shard_id_t ::NO_SHARD] = e.version ;
168+ } else {
169+ versions.erase (shard_id_t ::NO_SHARD);
170+ }
171+ // Erase and recreate backfill interval for e.soid using map
172+ primary_bi.objects .erase (e.soid );
173+ for (auto & [shard, version] : versions) {
174+ primary_bi.objects .insert (
175+ std::make_pair (e.soid ,
176+ std::make_pair (shard, version)));
177+ }
178+ }
140179 } else if (e.is_delete ()) {
141180 DEBUGDPP (" maybe_update_range(lambda): {} removed" ,
142181 pg (), e.soid );
143- primary_bi.objects .erase (e.soid );
182+ primary_bi.objects .erase (e.soid ); // Erase all entries for e.soid
144183 }
145184 }
146185 };
@@ -168,8 +207,8 @@ void BackfillState::Enqueuing::trim_backfill_infos()
168207
169208/* static */ bool BackfillState::Enqueuing::all_enqueued (
170209 const PeeringFacade& peering_state,
171- const BackfillInterval & backfill_info,
172- const std::map<pg_shard_t , BackfillInterval >& peer_backfill_info)
210+ const PrimaryBackfillInterval & backfill_info,
211+ const std::map<pg_shard_t , ReplicaBackfillInterval >& peer_backfill_info)
173212{
174213 const bool all_local_enqueued = \
175214 backfill_info.extends_to_end () && backfill_info.empty ();
@@ -184,7 +223,8 @@ void BackfillState::Enqueuing::trim_backfill_infos()
184223}
185224
186225hobject_t BackfillState::Enqueuing::earliest_peer_backfill (
187- const std::map<pg_shard_t , BackfillInterval>& peer_backfill_info) const
226+ const std::map<pg_shard_t ,
227+ ReplicaBackfillInterval>& peer_backfill_info) const
188228{
189229 hobject_t e = hobject_t::get_max ();
190230 for (const pg_shard_t & bt : peering_state ().get_backfill_targets ()) {
@@ -196,8 +236,8 @@ hobject_t BackfillState::Enqueuing::earliest_peer_backfill(
196236}
197237
198238bool BackfillState::Enqueuing::should_rescan_replicas (
199- const std::map<pg_shard_t , BackfillInterval >& peer_backfill_info,
200- const BackfillInterval & backfill_info) const
239+ const std::map<pg_shard_t , ReplicaBackfillInterval >& peer_backfill_info,
240+ const PrimaryBackfillInterval & backfill_info) const
201241{
202242 const auto & targets = peering_state ().get_backfill_targets ();
203243 return std::any_of (std::begin (targets), std::end (targets),
@@ -208,8 +248,8 @@ bool BackfillState::Enqueuing::should_rescan_replicas(
208248}
209249
210250bool BackfillState::Enqueuing::should_rescan_primary (
211- const std::map<pg_shard_t , BackfillInterval >& peer_backfill_info,
212- const BackfillInterval & backfill_info) const
251+ const std::map<pg_shard_t , ReplicaBackfillInterval >& peer_backfill_info,
252+ const PrimaryBackfillInterval & backfill_info) const
213253{
214254 return backfill_info.begin <= earliest_peer_backfill (peer_backfill_info) &&
215255 !backfill_info.extends_to_end () && backfill_info.empty ();
@@ -218,7 +258,7 @@ bool BackfillState::Enqueuing::should_rescan_primary(
218258void BackfillState::Enqueuing::trim_backfilled_object_from_intervals (
219259 BackfillState::Enqueuing::result_t && result,
220260 hobject_t & last_backfill_started,
221- std::map<pg_shard_t , BackfillInterval >& peer_backfill_info)
261+ std::map<pg_shard_t , ReplicaBackfillInterval >& peer_backfill_info)
222262{
223263 std::for_each (std::begin (result.pbi_targets ), std::end (result.pbi_targets ),
224264 [&peer_backfill_info] (const auto & bt) {
@@ -257,13 +297,28 @@ BackfillState::Enqueuing::update_on_peers(const hobject_t& check)
257297 result_t result { {}, primary_bi.begin };
258298 std::map<hobject_t , std::pair<eversion_t , std::vector<pg_shard_t >>> backfills;
259299
300+ std::map<shard_id_t ,eversion_t > versions;
301+ auto it = primary_bi.objects .begin ();
302+ const hobject_t & hoid = it->first ;
303+ eversion_t obj_v;
304+ while (it != primary_bi.objects .end () && it->first == hoid) {
305+ obj_v = std::max (obj_v, it->second .second );
306+ versions[it->second .first ] = it->second .second ;
307+ ++it;
308+ }
309+
260310 for (const auto & bt : peering_state ().get_backfill_targets ()) {
261311 const auto & peer_bi = backfill_state ().peer_backfill_info .at (bt);
262312
263313 // Find all check peers that have the wrong version
264- if (const eversion_t & obj_v = primary_bi.objects .begin ()->second ;
265- check == primary_bi.begin && check == peer_bi.begin ) {
266- if (peer_bi.objects .begin ()->second != obj_v) {
314+ if (check == primary_bi.begin && check == peer_bi.begin ) {
315+ eversion_t replicaobj_v;
316+ if (versions.contains (bt.shard )) {
317+ replicaobj_v = versions.at (bt.shard );
318+ } else {
319+ replicaobj_v = versions.at (shard_id_t ::NO_SHARD);
320+ }
321+ if (peer_bi.objects .begin ()->second != replicaobj_v) {
267322 std::ignore = backfill_state ().progress_tracker ->enqueue_push (
268323 primary_bi.begin );
269324 auto &[v, peers] = backfills[primary_bi.begin ];
@@ -298,8 +353,9 @@ BackfillState::Enqueuing::update_on_peers(const hobject_t& check)
298353}
299354
300355bool BackfillState::Enqueuing::Enqueuing::all_emptied (
301- const BackfillInterval& local_backfill_info,
302- const std::map<pg_shard_t , BackfillInterval>& peer_backfill_info) const
356+ const PrimaryBackfillInterval& local_backfill_info,
357+ const std::map<pg_shard_t ,
358+ ReplicaBackfillInterval>& peer_backfill_info) const
303359{
304360 const auto & targets = peering_state ().get_backfill_targets ();
305361 const auto replicas_emptied =
@@ -459,8 +515,8 @@ BackfillState::PrimaryScanning::react(ObjectPushed evt)
459515
460516// -- ReplicasScanning
461517bool BackfillState::ReplicasScanning::replica_needs_scan (
462- const BackfillInterval & replica_backfill_info,
463- const BackfillInterval & local_backfill_info)
518+ const ReplicaBackfillInterval & replica_backfill_info,
519+ const PrimaryBackfillInterval & local_backfill_info)
464520{
465521 return replica_backfill_info.empty () && \
466522 replica_backfill_info.begin <= local_backfill_info.begin && \
0 commit comments