From a0b8ea54ebbedab9ec3ee55faae5e0ae8c15fa05 Mon Sep 17 00:00:00 2001 From: Nuclearist Date: Tue, 12 Mar 2024 13:57:16 +0300 Subject: [PATCH] Fixed false download cancellation and a race condition --- src/CDNClient.cs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/CDNClient.cs b/src/CDNClient.cs index 28b5fa2..25b444f 100644 --- a/src/CDNClient.cs +++ b/src/CDNClient.cs @@ -100,21 +100,11 @@ private static void DownloadThreadProcedure(object? arg) int bytesRead; using var cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(60000); - try - { - var task = stream.ReadAtLeastAsync(downloadBuffer, compressedSize, false, cts.Token); - if (task.IsCompletedSuccessfully) - bytesRead = task.GetAwaiter().GetResult(); - else - bytesRead = task.AsTask().GetAwaiter().GetResult(); - } - catch (OperationCanceledException oce) - { - if (oce.CancellationToken == token) - return; - exception = new TimeoutException(); - continue; - } + var task = stream.ReadAtLeastAsync(downloadBuffer, compressedSize, false, cts.Token); + if (task.IsCompletedSuccessfully) + bytesRead = task.GetAwaiter().GetResult(); + else + bytesRead = task.AsTask().GetAwaiter().GetResult(); if (bytesRead != compressedSize) { exception = new InvalidDataException($"Downloaded chunk data size doesn't match expected [URL: {httpClient.BaseAddress}/{request.RequestUri}]"); @@ -136,7 +126,12 @@ private static void DownloadThreadProcedure(object? arg) } exception = null; } - catch (OperationCanceledException) { return; } + catch (OperationCanceledException oce) + { + if (oce.CancellationToken == token) + return; + exception = oce; + } catch (HttpRequestException hre) when (hre.StatusCode > HttpStatusCode.InternalServerError) { if (fallbackServerIndex is 0) @@ -533,13 +528,13 @@ public static ChunkContext LoadFromBuffer(ReadOnlySpan buffer, ref nint of private class LimitedUseFileHandle(SafeFileHandle fileHandle, int numChunks) { /// The number of chunks left to be written to the file. - public int ChunksLeft { get; private set; } = numChunks; + private int _chunksLeft = numChunks; /// File handle. public SafeFileHandle Handle { get; } = fileHandle; /// Decrements the number of chunks left to write and releases the handle if it becomes zero. public void Release() { - if (--ChunksLeft is 0) + if (Interlocked.Decrement(ref _chunksLeft) is 0) Handle.Dispose(); } }