assert check_bucket_instance_metadata(zone.zone, test_bucket.name)
+@attr('bucket_trim')
+def test_bucket_log_trim_enoent_race_after_reshard():
+ zonegroup = realm.master_zonegroup()
+ zonegroup_conns = ZonegroupConns(zonegroup)
+
+ primary = zonegroup_conns.rw_zones[0]
+ secondary = zonegroup_conns.rw_zones[1]
+
+ all_clusters = set()
+ for zg in realm.current_period.zonegroups:
+ for zone in zg.zones:
+ all_clusters.add(zone.cluster)
+
+ def set_meta_sync_delay(delay_sec):
+ for cluster in all_clusters:
+ if delay_sec > 0:
+ cluster.ceph_admin(
+ ['config', 'set', 'client', 'rgw_inject_delay_sec', str(delay_sec)])
+ cluster.ceph_admin(
+ ['config', 'set', 'client', 'rgw_inject_delay_pattern', 'delay_meta_sync_bucket_instance_store'])
+ else:
+ cluster.ceph_admin(
+ ['config', 'rm', 'client', 'rgw_inject_delay_sec'])
+ cluster.ceph_admin(
+ ['config', 'rm', 'client', 'rgw_inject_delay_pattern'])
+
+ def make_test_bucket():
+ name = gen_bucket_name()
+ log.info('create bucket zone=%s name=%s', primary.zone.name, name)
+ bucket = primary.create_bucket(name)
+ for objname in ('a', 'b', 'c', 'd'):
+ primary.s3_client.put_object(Bucket=bucket.name, Key=objname, Body='foo')
+ zonegroup_meta_checkpoint(zonegroup)
+ zonegroup_bucket_checkpoint(zonegroup_conns, name)
+ return bucket
+
+ test_bucket = make_test_bucket()
+
+ # reshard on secondary to create a generation mismatch
+ secondary.zone.cluster.admin(['bucket', 'reshard',
+ '--bucket', test_bucket.name,
+ '--num-shards', '13',
+ '--yes-i-really-mean-it'] + secondary.zone.zone_args())
+
+ for obj in ('a', 'b', 'c', 'd'):
+ cmd = ['object', 'rm'] + primary.zone.zone_args()
+ cmd += ['--bucket', test_bucket.name]
+ cmd += ['--object', obj]
+ primary.zone.cluster.admin(cmd + primary.zone.zone_args())
+
+ log.info('setting metadata sync delay to reproduce ENOENT trim race')
+ set_meta_sync_delay(30)
+ time.sleep(10) # let the delay config reach the radosgws before deleting
+
+ try:
+ primary.s3_client.delete_bucket(Bucket=test_bucket.name)
+ zonegroup_data_checkpoint(zonegroup_conns)
+
+ # run autotrim on primary first — primary has the Deleted flag
+ # so it will fully clean up including removing its own
+ # bucket.instance metadata
+ bilog_autotrim(primary.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ time.sleep(config.checkpoint_delay)
+ bilog_autotrim(primary.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ time.sleep(config.checkpoint_delay)
+
+ # now autotrim on secondary — secondary queries primary, but
+ # primary's instance metadata is gone so primary responds -ENOENT.
+ # secondary doesn't have the Deleted flag yet (metadata sync is
+ # stalled). In #70858, this leaves StatusShards{gen=0, shards=[]}
+ # causing take_min_status() to fail with -EINVAL.
+ bilog_autotrim(secondary.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ time.sleep(config.checkpoint_delay)
+ bilog_autotrim(secondary.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ finally:
+ log.info('removing metadata sync delay')
+ set_meta_sync_delay(0)
+
+ for zonegroup in realm.current_period.zonegroups:
+ zonegroup_conns = ZonegroupConns(zonegroup)
+ zonegroup_meta_checkpoint(zonegroup)
+
+ for zone in zonegroup_conns.zones:
+ log.info('trimming on zone=%s', zone.name)
+ bilog_autotrim(zone.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ time.sleep(config.checkpoint_delay)
+
+ bilog_autotrim(secondary.zone, ['--rgw-sync-log-trim-max-buckets', '50'],)
+ time.sleep(config.checkpoint_delay)
+
+ for zonegroup in realm.current_period.zonegroups:
+ zonegroup_conns = ZonegroupConns(zonegroup)
+ for zone in zonegroup_conns.zones:
+ assert check_bucket_instance_metadata(zone.zone, test_bucket.name)
+
+
@attr('bucket_reshard')
def test_bucket_reshard_incremental():
zonegroup = realm.master_zonegroup()