[!NOTE] This issue is not about backup read/dedup progress.
The read-side progress is already accurate.
The request is to expose upload progress during OpenDAL writes so
that applications can observe upload progress while a pack is still
being uploaded, instead of only after the entire pack has completed.
Background
In an application integrating rustic_core + rustic_backend, two
independent progress metrics are reported:
Metric Meaning
readBytes / readTotal / Original source data read and
readProgress deduplicated
writtenBytes Actual bytes written to the backend
(compressed/encrypted pack bytes)
The read-side metric behaves correctly.
The write-side metric only advances after an entire pack upload has
finished, making upload progress and throughput appear coarse.
Observed behavior
Example logs:
08-02 18:11:49.765 PROGRESS-DIAG readBytes=723421 readTotal=132147200 readProgress=0.0054743574 writtenBytes=0 speed=0
08-02 18:13:25.918 PROGRESS-DIAG readBytes=132147200 readTotal=132147200 readProgress=1.0 writtenBytes=45127834 speed=469336
08-02 18:14:26.931 PROGRESS-DIAG readBytes=132147200 readTotal=132147200 readProgress=1.0 writtenBytes=71746505 speed=436288
08-02 18:14:27.276 PROGRESS-DIAG readBytes=132147200 readTotal=132147200 readProgress=1.0 writtenBytes=71760889 speed=451843
08-02 18:16:23.199 PROGRESS-DIAG readBytes=80384000 readTotal=80384000 readProgress=1.0 writtenBytes=44556589 speed=388682
08-02 18:16:57.092 PROGRESS-DIAG readBytes=80384000 readTotal=80384000 readProgress=1.0 writtenBytes=58243235 speed=403820
readProgress reaches 100% long before uploads finish, while
writtenBytes advances in large steps because it is only updated after
a completed pack upload.
Analysis
1. Read progress is already correct
The backup size is determined before backup begins
(p.set_length(size)), and every processed chunk advances progress via
p.inc(size) regardless of whether it is deduplicated or uploaded.
Therefore readProgress == 100% already correctly means all source data
has been scanned and deduplicated.
No change is required on the read side.
2. Upload progress is limited by the current write path
Current upload path:
packer
↓
save()
↓
OpenDALBackend::write_bytes()
↓
Operator::write(path, buf)
The current implementation uses a whole-object write:
self.operator.write(&filename, buf)?;
From rustic_backend's perspective there are only two observable
events:
write begins
...
write returns
No intermediate progress information is exposed.
3. A Layer alone is insufficient
A custom OpenDAL Layer cannot provide incremental progress by itself.
When the complete object is passed to Operator::write(), the
underlying writer typically receives only one write operation.
Consequently, the Layer also observes only one successful write.
Incremental progress therefore requires both:
- A progress-aware Layer.
- A chunked write path that feeds the writer incrementally.
These two components are complementary.
4. Current extension points
OpenDALBackend currently assembles its Operator and Layer chain
internally, leaving no public extension point for upload progress
reporting.
Proposed enhancement
Provide an opt-in upload progress mechanism for the OpenDAL backend.
The implementation should allow:
- attaching upload progress reporting;
- using a chunked multipart-capable write path;
- preserving existing behavior for all current callers unless they
explicitly opt in.
The exact API is open for discussion.
Progress semantics
The reported progress represents bytes successfully accepted by the
underlying OpenDAL writer.
For multipart-capable services, this corresponds approximately to
multipart part submission rather than actual socket transmission.
This is sufficient for progress bars, throughput estimation and
diagnostics.
Expected result
Instead of:
progress would advance approximately once per multipart part:
0
8 MiB
16 MiB
24 MiB
...
The exact granularity depends on backend implementation and multipart
configuration.
Small objects below the multipart threshold may still complete in a
single step.
Prototype validation
A prototype implementation combining:
- a progress-aware OpenDAL Layer;
- an opt-in chunked write path;
was validated against Tencent COS.
Observed output:
PROGRESS-COS t=1786002936260 counter=0
PROGRESS-COS t=1786002936461 counter=8388608
PROGRESS-COS t=1786002937265 counter=16777216
PROGRESS-COS t=1786002937466 counter=25165824
PROGRESS-COS t=1786002937667 counter=33554432
PROGRESS-COS t=1786002938069 counter=41943040
PROGRESS-COS t=1786002938269 counter=50331648
PROGRESS-COS t=1786002938470 counter=58720256
PROGRESS-COS t=1786002938671 counter=67108864
PROGRESS-COS t=1786002941082 counter=134217728
The counter advanced incrementally during upload.
For this prototype:
- Object size: 128 MiB
- Chunk size: 8 MiB
- Backend: Tencent COS
- Observed granularity: one update per multipart part
This demonstrates the feasibility of the proposed approach.
Scope
This proposal does not change:
- backup semantics;
- deduplication;
- repository format;
- repository compatibility.
Existing callers keep the current behavior.
Applications that explicitly opt into upload progress reporting may use
a different multipart-capable write strategy to expose incremental
progress.
Motivation
The goal is observability rather than new backup functionality.
Existing users are unaffected.
Applications that opt in gain accurate upload progress, smoother
throughput reporting and improved diagnostics while maintaining
repository compatibility.
Background
In an application integrating
rustic_core+rustic_backend, twoindependent progress metrics are reported:
Metric Meaning
readBytes/readTotal/ Original source data read andreadProgressdeduplicatedwrittenBytesActual bytes written to the backend(compressed/encrypted pack bytes)
The read-side metric behaves correctly.
The write-side metric only advances after an entire pack upload has
finished, making upload progress and throughput appear coarse.
Observed behavior
Example logs:
readProgressreaches 100% long before uploads finish, whilewrittenBytesadvances in large steps because it is only updated aftera completed pack upload.
Analysis
1. Read progress is already correct
The backup size is determined before backup begins
(
p.set_length(size)), and every processed chunk advances progress viap.inc(size)regardless of whether it is deduplicated or uploaded.Therefore
readProgress == 100%already correctly means all source datahas been scanned and deduplicated.
No change is required on the read side.
2. Upload progress is limited by the current write path
Current upload path:
The current implementation uses a whole-object write:
From
rustic_backend's perspective there are only two observableevents:
No intermediate progress information is exposed.
3. A Layer alone is insufficient
A custom OpenDAL
Layercannot provide incremental progress by itself.When the complete object is passed to
Operator::write(), theunderlying writer typically receives only one write operation.
Consequently, the Layer also observes only one successful write.
Incremental progress therefore requires both:
These two components are complementary.
4. Current extension points
OpenDALBackendcurrently assembles itsOperatorand Layer chaininternally, leaving no public extension point for upload progress
reporting.
Proposed enhancement
Provide an opt-in upload progress mechanism for the OpenDAL backend.
The implementation should allow:
explicitly opt in.
The exact API is open for discussion.
Progress semantics
The reported progress represents bytes successfully accepted by the
underlying OpenDAL writer.
For multipart-capable services, this corresponds approximately to
multipart part submission rather than actual socket transmission.
This is sufficient for progress bars, throughput estimation and
diagnostics.
Expected result
Instead of:
progress would advance approximately once per multipart part:
The exact granularity depends on backend implementation and multipart
configuration.
Small objects below the multipart threshold may still complete in a
single step.
Prototype validation
A prototype implementation combining:
was validated against Tencent COS.
Observed output:
The counter advanced incrementally during upload.
For this prototype:
This demonstrates the feasibility of the proposed approach.
Scope
This proposal does not change:
Existing callers keep the current behavior.
Applications that explicitly opt into upload progress reporting may use
a different multipart-capable write strategy to expose incremental
progress.
Motivation
The goal is observability rather than new backup functionality.
Existing users are unaffected.
Applications that opt in gain accurate upload progress, smoother
throughput reporting and improved diagnostics while maintaining
repository compatibility.