Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using ByteSync.Common.Business.Communications.Transfers;

namespace ByteSync.Interfaces.Controls.Communications;

public interface IAdaptiveUploadController
Expand All @@ -8,6 +10,5 @@ public interface IAdaptiveUploadController

int GetNextChunkSizeBytes();

void RecordUploadResult(TimeSpan elapsed, bool isSuccess, int partNumber, int? statusCode = null,
Exception? exception = null, string? fileId = null, long actualBytes = -1);
void RecordUploadResult(UploadResult uploadResult);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
var blob = new BlobClient(new Uri(storageLocation.Url), options);
var response = await blob.UploadAsync(slice.MemoryStream, cancellationToken);

_logger.LogDebug("UploadAvailableSlice: slice {number} is uploaded", slice.PartNumber);
_logger.LogDebug("UploadAvailableSlice: slice {PartNumber} is uploaded", slice.PartNumber);

Check warning on line 30 in src/ByteSync.Client/Services/Communications/Transfers/Strategies/AzureBlobStorageUploadStrategy.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmUeqpstt_9MwmZn&open=AZ3CgmUeqpstt_9MwmZn&pullRequest=290

var rawResponse = response.GetRawResponse();

Expand All @@ -45,10 +45,15 @@
);
}
}
catch (OperationCanceledException ex)
{
_logger.LogWarning(ex, "Upload of slice {PartNumber} was canceled or timed out", slice.PartNumber);
return UploadFailureClassifier.Classify(ex, cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to upload slice {number}", slice.PartNumber);
return UploadFileResponse.Failure(500, ex);
_logger.LogError(ex, "Failed to upload slice {PartNumber}", slice.PartNumber);
return UploadFailureClassifier.Classify(ex, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
};
request.Headers.ExpectContinue = false;

_logger.LogDebug("R2 PUT start: part {Part} sizeKB {SizeKb} host {Host}",
slice.PartNumber, Math.Round(rom.Length / 1024d), new Uri(storageLocation.Url).Host);

Check warning on line 58 in src/ByteSync.Client/Services/Communications/Transfers/Strategies/CloudflareR2UploadStrategy.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmUPqpstt_9MwmZk&open=AZ3CgmUPqpstt_9MwmZk&pullRequest=290

using var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

Expand All @@ -76,10 +76,15 @@
);
}
}
catch (OperationCanceledException ex)
{
_logger.LogWarning(ex, "Upload of slice {PartNumber} was canceled or timed out", slice.PartNumber);
return UploadFailureClassifier.Classify(ex, cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to upload slice {number}", slice.PartNumber);
return UploadFileResponse.Failure(500, ex);
_logger.LogError(ex, "Failed to upload slice {PartNumber}", slice.PartNumber);
return UploadFailureClassifier.Classify(ex, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Threading;
using ByteSync.Common.Business.Communications.Transfers;

namespace ByteSync.Services.Communications.Transfers.Strategies;

public static class UploadFailureClassifier
{
public static UploadFileResponse Classify(Exception exception, CancellationToken cancellationToken)
{
if (exception is OperationCanceledException && cancellationToken.IsCancellationRequested)
{
return UploadFileResponse.ClientCancellation(exception);
}

if (exception is OperationCanceledException)
{
return UploadFileResponse.ClientTimeout(exception);
}

return UploadFileResponse.Failure(500, exception);
}
Comment thread
paul-fresquet marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reactive.Linq;
using ByteSync.Business.Sessions;
using ByteSync.Common.Business.Communications.Transfers;
using ByteSync.Interfaces.Controls.Communications;
using ByteSync.Interfaces.Services.Sessions;

Expand Down Expand Up @@ -81,14 +82,18 @@
}
}

public void RecordUploadResult(TimeSpan elapsed, bool isSuccess, int partNumber, int? statusCode = null,
Exception? exception = null, string? fileId = null, long actualBytes = -1)
public void RecordUploadResult(UploadResult uploadResult)
{
lock (_syncRoot)
{
EnqueueSample(elapsed, isSuccess, actualBytes);
if (IsClientSideFailure(uploadResult.FailureKind))
{
return;
}

EnqueueSample(uploadResult.Elapsed, uploadResult.IsSuccess, uploadResult.ActualBytes);

if (HandleBandwidthReset(isSuccess, statusCode))
if (HandleBandwidthReset(uploadResult.IsSuccess, uploadResult.StatusCode))
{
return;
}
Expand All @@ -100,20 +105,20 @@

var maxElapsed = GetMaxElapsedInWindow();

_logger.LogDebug(
"Adaptive: file {FileId} maxElapsed={MaxElapsedMs} ms, window={Window}, parallelism={Parallelism}, chunkSize={ChunkKb} KB",
fileId ?? "-",
uploadResult.FileId ?? "-",
maxElapsed.TotalMilliseconds,
_windowSize,
_currentParallelism,
Math.Round(_currentChunkSizeBytes / 1024d));

Check warning on line 114 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZb&open=AZ3CgmT8qpstt_9MwmZb&pullRequest=290

if (TryHandleDownscale(maxElapsed, fileId))
if (TryHandleDownscale(maxElapsed, uploadResult.FileId))
{
return;
}

TryHandleUpscale(fileId);
TryHandleUpscale(uploadResult.FileId);
}
}

Expand Down Expand Up @@ -146,6 +151,11 @@
}
}

private static bool IsClientSideFailure(UploadFailureKind failureKind)
{
return failureKind is UploadFailureKind.ClientCancellation or UploadFailureKind.ClientTimeout;
}

private bool HandleBandwidthReset(bool isSuccess, int? statusCode)
{
if (!isSuccess && statusCode != null)
Expand Down Expand Up @@ -184,11 +194,11 @@
{
if (_currentParallelism > MIN_PARALLELISM)
{
_logger.LogInformation(
"Adaptive: file {FileId} Downscale. Reducing parallelism {Prev} -> {Next}. Resetting window (window before {WindowBefore})",
fileId ?? "-",
_currentParallelism, _currentParallelism - 1,
_windowSize);

Check warning on line 201 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZc&open=AZ3CgmT8qpstt_9MwmZc&pullRequest=290
_currentParallelism -= 1;
_windowSize = _currentParallelism;
ResetWindow();
Expand All @@ -200,12 +210,12 @@
if (reduced != _currentChunkSizeBytes)
{
_currentChunkSizeBytes = reduced;
_logger.LogInformation(
"Adaptive: file {FileId} Downscale. maxElapsed={MaxElapsedMs} ms > {ThresholdMs} ms. New chunkSize={ChunkKb} KB",
fileId ?? "-",
maxElapsed.TotalMilliseconds,
_downscaleThreshold.TotalMilliseconds,
Math.Round(_currentChunkSizeBytes / 1024d));

Check warning on line 218 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZd&open=AZ3CgmT8qpstt_9MwmZd&pullRequest=290
}

ResetWindow();
Expand Down Expand Up @@ -263,12 +273,12 @@
var increased = (int)Math.Round(_currentChunkSizeBytes * multiplier);
_currentChunkSizeBytes = Math.Clamp(increased, MIN_CHUNK_SIZE_BYTES, MAX_CHUNK_SIZE_BYTES);

_logger.LogInformation(
"Adaptive: file {FileId} Upscale. maxElapsed={MaxElapsedMs} ms <= {ThresholdMs} ms. New chunkSize={ChunkKb} KB",
fileId ?? "-",
maxElapsedEligible.TotalMilliseconds,
_upscaleThreshold.TotalMilliseconds,
Math.Round(_currentChunkSizeBytes / 1024d));

Check warning on line 281 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZe&open=AZ3CgmT8qpstt_9MwmZe&pullRequest=290

UpdateParallelismOnUpscale(fileId);
_currentParallelism = Math.Min(_currentParallelism, MAX_PARALLELISM);
Expand All @@ -278,7 +288,7 @@
}
}

private double GetUpscaleMultiplier(TimeSpan maxElapsedEligible)
private static double GetUpscaleMultiplier(TimeSpan maxElapsedEligible)
{
if (maxElapsedEligible < TimeSpan.FromSeconds(1))
{
Expand Down Expand Up @@ -306,8 +316,8 @@
_currentParallelism = Math.Max(_currentParallelism, 4);
if (_currentParallelism != prev)
{
_logger.LogInformation("Adaptive: file {FileId} Upscale. Increasing parallelism {Prev} -> {Next} due to chunk>=8MB",
fileId ?? "-", prev, _currentParallelism);

Check warning on line 320 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZf&open=AZ3CgmT8qpstt_9MwmZf&pullRequest=290
}
}
else if (_currentChunkSizeBytes >= FOUR_MB)
Expand All @@ -316,8 +326,8 @@
_currentParallelism = Math.Max(_currentParallelism, 3);
if (_currentParallelism != prev)
{
_logger.LogInformation("Adaptive: file {FileId} Upscale. Increasing parallelism {Prev} -> {Next} due to chunk>=4MB",
fileId ?? "-", prev, _currentParallelism);

Check warning on line 330 in src/ByteSync.Client/Services/Communications/Transfers/Uploading/AdaptiveUploadController.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Evaluation of this argument may be expensive and unnecessary if logging is disabled

See more on https://sonarcloud.io/project/issues?id=POW-Software_ByteSync&issues=AZ3CgmT8qpstt_9MwmZg&open=AZ3CgmT8qpstt_9MwmZg&pullRequest=290
}
}
}
Expand Down
Loading
Loading