Skip to content

Commit 02a1f91

Browse files
committed
examples/large-file-upload: ignore reuploaded block errors when resuming
Because we upload blocks in parallel, we may hit an error on a block but still upload some blocks after that one. Then when resuming, we can hit an error when the API complains that we already have data at an offset we're trying to upload to. If we're resuming, assume that this is fine and keep going. (Ideally the API would see that the data in question matches the already-uploaded block and not raise this error, but it doesn't...)
1 parent 8f4dce3 commit 02a1f91

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

examples/large-file-upload.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct Args {
4848
resume: Option<Resume>,
4949
}
5050

51-
#[derive(Debug)]
51+
#[derive(Debug, Clone)]
5252
struct Resume {
5353
start_offset: u64,
5454
session_id: String,
@@ -312,10 +312,10 @@ fn upload_file(
312312

313313
let (source_mtime, source_len) = get_file_mtime_and_size(&source_file)?;
314314

315-
let session = Arc::new(if let Some(resume) = resume {
315+
let session = Arc::new(if let Some(ref resume) = resume {
316316
source_file.seek(SeekFrom::Start(resume.start_offset))
317317
.map_err(|e| format!("Seek error: {}", e))?;
318-
UploadSession::resume(resume, source_len)
318+
UploadSession::resume(resume.clone(), source_len)
319319
} else {
320320
UploadSession::new(client.as_ref(), source_len)?
321321
});
@@ -343,6 +343,7 @@ fn upload_file(
343343
data,
344344
start_time,
345345
session.as_ref(),
346+
resume.as_ref(),
346347
);
347348
if result.is_ok() {
348349
session.mark_block_uploaded(block_offset, data.len() as u64);
@@ -388,13 +389,20 @@ fn upload_block_with_retry(
388389
buf: &[u8],
389390
start_time: Instant,
390391
session: &UploadSession,
392+
resume: Option<&Resume>,
391393
) -> Result<(), String> {
392394
let block_start_time = Instant::now();
393395
let mut errors = 0;
396+
const BLOCK_UPLOADED_MSG: &str = "Different data already uploaded at offset ";
394397
loop {
395398
match files::upload_session_append_v2(client, arg, buf) {
396-
Ok(Ok(())) => {
397-
break;
399+
Ok(Ok(())) => { break; }
400+
Err(dropbox_sdk::Error::BadRequest(msg))
401+
if resume.is_some() && msg.contains(BLOCK_UPLOADED_MSG) =>
402+
{
403+
let i = msg.find(BLOCK_UPLOADED_MSG).unwrap();
404+
eprintln!("already uploaded block at {}", &msg[i + BLOCK_UPLOADED_MSG.len() ..]);
405+
return Ok(());
398406
}
399407
Err(dropbox_sdk::Error::RateLimited { reason, retry_after_seconds }) => {
400408
eprintln!("rate-limited ({}), waiting {} seconds", reason, retry_after_seconds);
@@ -421,7 +429,8 @@ fn upload_block_with_retry(
421429
let block_bytes = buf.len() as u64;
422430
let bytes_sofar = session.bytes_transferred.fetch_add(block_bytes, SeqCst) + block_bytes;
423431

424-
let percent = bytes_sofar as f64 / session.file_size as f64 * 100.;
432+
let percent = (resume.map(|r| r.start_offset).unwrap_or(0) + bytes_sofar) as f64
433+
/ session.file_size as f64 * 100.;
425434

426435
// This assumes that we have `PARALLELISM` uploads going at the same time and at roughly the
427436
// same upload speed:

0 commit comments

Comments
 (0)