Skip to content

Commit 8c12ed6

Browse files
committed
feat(services/swift): support SLO multipart upload via MultipartWrite
Implement oio::MultipartWrite for SwiftWriter using Swift's Static Large Object (SLO) mechanism, removing the 5GB single-upload ceiling. SLO flow: - initiate_part: generate a local UUID (no server call needed) - write_part: PUT segment to .segments/{path}/{upload_id}/{part:08} - complete_part: PUT JSON manifest to {path}?multipart-manifest=put - abort_part: list and delete all segments under the upload_id prefix Changes: - Add swift_put_segment, swift_put_slo_manifest, swift_delete_slo, slo_segment_path to SwiftCore - Add SloManifestEntry serde struct for manifest JSON - Replace OneShotWrite with MultipartWrite on SwiftWriter - Track per-part sizes in Arc<Mutex<HashMap>> for manifest assembly - Change Writer type from OneShotWriter to MultipartWriter - Declare write_can_multi, write_multi_min_size (5MB), write_multi_max_size (5GB) capabilities - Add uuid dependency for upload ID generation
1 parent ec8ff52 commit 8c12ed6

File tree

14 files changed

+268
-5
lines changed

14 files changed

+268
-5
lines changed

core/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/core/src/raw/oio/write/multipart_write.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ pub struct MultipartPart {
118118
pub etag: String,
119119
/// The checksum of the part.
120120
pub checksum: Option<String>,
121+
/// The size of the part in bytes.
122+
pub size: Option<u64>,
121123
}
122124

123125
struct WriteInput<W: MultipartWrite> {
@@ -391,6 +393,7 @@ mod tests {
391393
part_number,
392394
etag: "etag".to_string(),
393395
checksum: None,
396+
size: None,
394397
})
395398
}
396399

core/services/b2/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl oio::MultipartWrite for B2Writer {
133133
etag: result.content_sha1,
134134
part_number,
135135
checksum: None,
136+
size: None,
136137
})
137138
}
138139
_ => Err(parse_error(resp)),

core/services/cos/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ impl oio::MultipartWrite for CosWriter {
141141
part_number,
142142
etag,
143143
checksum: None,
144+
size: None,
144145
})
145146
}
146147
_ => Err(parse_error(resp)),

core/services/gcs/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ impl oio::MultipartWrite for GcsWriter {
119119
part_number,
120120
etag,
121121
checksum: None,
122+
size: None,
122123
})
123124
}
124125

core/services/obs/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ impl oio::MultipartWrite for ObsWriter {
136136
part_number,
137137
etag,
138138
checksum: None,
139+
size: None,
139140
})
140141
}
141142
_ => Err(parse_error(resp)),

core/services/oss/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ impl oio::MultipartWrite for OssWriter {
138138
part_number,
139139
etag,
140140
checksum: None,
141+
size: None,
141142
})
142143
}
143144
_ => Err(parse_error(resp)),

core/services/s3/src/writer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ impl oio::MultipartWrite for S3Writer {
143143
part_number,
144144
etag,
145145
checksum,
146+
size: None,
146147
})
147148
}
148149
_ => Err(parse_error(resp)),

core/services/swift/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ opendal-core = { path = "../../core", version = "0.55.0", default-features = fal
3838
quick-xml = { workspace = true, features = ["serialize", "overlapped-lists"] }
3939
serde = { workspace = true, features = ["derive"] }
4040
serde_json = { workspace = true }
41+
uuid = { workspace = true, features = ["v4"] }
4142

4243
[dev-dependencies]
4344
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }

core/services/swift/src/backend.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ impl Builder for SwiftBuilder {
157157

158158
write: true,
159159
write_can_empty: true,
160+
write_can_multi: true,
161+
write_multi_min_size: Some(5 * 1024 * 1024),
162+
write_multi_max_size: if cfg!(target_pointer_width = "64") {
163+
Some(5 * 1024 * 1024 * 1024)
164+
} else {
165+
Some(usize::MAX)
166+
},
160167
write_with_content_type: true,
161168
write_with_content_disposition: true,
162169
write_with_content_encoding: true,
@@ -194,7 +201,7 @@ pub struct SwiftBackend {
194201

195202
impl Access for SwiftBackend {
196203
type Reader = HttpBody;
197-
type Writer = oio::OneShotWriter<SwiftWriter>;
204+
type Writer = oio::MultipartWriter<SwiftWriter>;
198205
type Lister = oio::PageLister<SwiftLister>;
199206
type Deleter = oio::BatchDeleter<SwiftDeleter>;
200207

@@ -236,9 +243,9 @@ impl Access for SwiftBackend {
236243
}
237244

238245
async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
246+
let concurrent = args.concurrent();
239247
let writer = SwiftWriter::new(self.core.clone(), args.clone(), path.to_string());
240-
241-
let w = oio::OneShotWriter::new(writer);
248+
let w = oio::MultipartWriter::new(self.core.info.clone(), writer, concurrent);
242249

243250
Ok((RpWrite::default(), w))
244251
}

0 commit comments

Comments
 (0)