Skip to content

rc mirror S3-to-S3 does not preserve ETag, causing unchanged objects to be copied again #342

Description

@robyquin

Description

I am using rc 0.1.31 to mirror objects between two RustFS S3 endpoints:

RustFS source (remote NTFS) → RustFS destination (local NTFS)

The problem appears to be related to how rc mirror performs S3-to-S3 copies rather than to the underlying filesystem.

Observed behavior

I initially ran:

time rc mirror --overwrite --remove --json \
  remoto/archive/2026/07 \
  local/archive/2026/07

Result:

{
  "source": "remoto/archive/2026/07",
  "target": "local/archive/2026/07",
  "copied": 764,
  "removed": 0,
  "skipped": 0,
  "errors": 0,
  "dry_run": false
}

The operation took approximately 30 minutes.

Running the exact same command again, without any changes on the source, still caused all 764 objects to be copied again.

A dry run confirmed:

{
  "copied": 764,
  "removed": 0,
  "skipped": 0
}

ETag difference

For example, one object had:

Source

Size: 21375369 bytes
ETag: 513cf08fa7a370c31e6cee7beb120163-2
Date: 2026-08-04 22:11:52 UTC

Destination after rc mirror

Size: 21375369 bytes
ETag: 53d0b16993c80d285b6e681ef17ef6b3-1
Date: 2026-08-11 13:28:51 UTC

The content size is identical, but the ETag is different.

This causes the next rc mirror invocation to consider the object changed and copy it again.

Important comparison with mc --preserve

I then used mc cp --preserve on a smaller subset of the same S3-to-S3 data.

After that, the same object reported:

Source

Size: 21375369 bytes
ETag: 513cf08fa7a370c31e6cee7beb120163-2
Date: 2026-08-04 22:11:52 UTC

Destination

Size: 21375369 bytes
ETag: 513cf08fa7a370c31e6cee7beb120163-2
Date: 2026-08-11 14:17:36 UTC

Notice that the Date/mtime is still different, but the ETag is identical.

I then ran:

rc mirror --overwrite --remove --json \
  remoto/archive/2026/07/20260726/D7500 \
  local/archive/2026/07/20260726/D7500

and got:

{
  "copied": 0,
  "removed": 0,
  "skipped": 14,
  "errors": 0,
  "dry_run": false
}

The operation took only:

real    0m0.330s

This strongly indicates that rc mirror uses the ETag (rather than the object modification date) as an important part of its equality check.

Expected behavior

For an S3-to-S3 mirror, if the source object is copied without changing its content, I would expect the destination object to retain an identity that allows subsequent mirror operations to recognize it as unchanged.

Ideally:

source ETag == destination ETag

after a successful mirror operation, when the destination object contains exactly the same object data.

Otherwise, every subsequent rc mirror operation unnecessarily transfers the entire object again.

Why this matters

My use case is a RustFS server acting as a continuously updated mirror of another RustFS server.

The current behavior turns an incremental mirror into a full re-transfer.

After copying the same objects with mc --preserve, subsequent rc mirror correctly skips them.

Therefore, preserving object identity/ETag during S3-to-S3 mirroring would make a very significant difference for this use case.

Environment

rc version: 0.1.31
Source: RustFS S3 (rustfs 1.0.0-rc.1)
Source filesystem: NTFS3
Destination: RustFS S3 (rustfs 1.0.0-rc.1)
Destination filesystem: NTFS3
Transfer type: S3-to-S3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions