static void UploadImageFilePart(object state)
{
Interlocked.Increment(ref _activeUploadWorkers);
var uploadStateInfo = state as ImagePartUploadState;
if (uploadStateInfo == null)
throw new ArgumentException("Expected ImagePartUploadState instance to process");
var buffer = new byte[DefaultPartSize];
var part = uploadStateInfo.PartsList.FetchNextPartForUpload(uploadStateInfo.ImageFileStream, ref buffer);
var uploadSucceeded = true;
while (part != null && uploadSucceeded)
{
try
{
if (!part.UploadCompleted) // if we're resuming, skip what was uploaded OK
{
using (var ms = new MemoryStream(buffer, 0, (int)part.ByteRange.Extent))
{
// implement an additional retry mode above and beyond what the
// SDKs standard http handling performs, to account for uploads
// on networks with considerable jitter
const int maxRetries = 5;
var attempt = 1;
while (!part.UploadCompleted && attempt <= maxRetries)
{
try
{
uploadStateInfo.S3Client.UploadObjectFromStream(uploadStateInfo.BucketName, part.Key, ms,
new Dictionary<string, object> {{"AutoCloseStream", false}});
part.UploadCompleted = true;
}
catch (Exception)
{
attempt++;
}
}
if (!part.UploadCompleted)
throw new DiskImageImporterException(DiskImportErrorStage.UploadingImageFile,
"Failed to upload part " + part.Index + " after " + maxRetries + " retries.");
}
}
}
catch (Exception)
{
uploadSucceeded = false;
uploadStateInfo.PartsList.RegisterUploadFailure();
}
finally
{
if (uploadSucceeded)
{
uploadStateInfo.PartProcessed.Set();
part = uploadStateInfo.PartsList.FetchNextPartForUpload(uploadStateInfo.ImageFileStream, ref buffer);
}
}
}
Interlocked.Decrement(ref _activeUploadWorkers);
}