Skip to content

Commit 3c1f7cd

Browse files
committed
fix: add remove from cache after complete
1 parent 33be0e5 commit 3c1f7cd

File tree

3 files changed

+60
-40
lines changed

3 files changed

+60
-40
lines changed

Storage/Extensions/HttpClientProgress.cs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ public static Task<HttpResponseMessage> UploadOrContinueFileAsync(
201201
this HttpClient client,
202202
Uri uri,
203203
string filePath,
204+
MetadataCollection metadata,
204205
Dictionary<string, string>? headers = null,
205-
MetadataCollection? metadata = null,
206206
Progress<float>? progress = null,
207207
CancellationToken cancellationToken = default
208208
)
@@ -212,8 +212,8 @@ public static Task<HttpResponseMessage> UploadOrContinueFileAsync(
212212
client,
213213
uri,
214214
fileStream,
215-
headers,
216215
metadata,
216+
headers,
217217
progress,
218218
cancellationToken
219219
);
@@ -223,8 +223,8 @@ public static Task<HttpResponseMessage> UploadOrContinueByteAsync(
223223
this HttpClient client,
224224
Uri uri,
225225
byte[] data,
226+
MetadataCollection metadata,
226227
Dictionary<string, string>? headers = null,
227-
MetadataCollection? metadata = null,
228228
Progress<float>? progress = null,
229229
CancellationToken cancellationToken = default
230230
)
@@ -234,8 +234,8 @@ public static Task<HttpResponseMessage> UploadOrContinueByteAsync(
234234
client,
235235
uri,
236236
stream,
237-
headers,
238237
metadata,
238+
headers,
239239
progress,
240240
cancellationToken
241241
);
@@ -245,8 +245,8 @@ private static async Task<HttpResponseMessage> ResumableUploadAsync(
245245
this HttpClient client,
246246
Uri uri,
247247
Stream fileStream,
248+
MetadataCollection metadata,
248249
Dictionary<string, string>? headers = null,
249-
MetadataCollection? metadata = null,
250250
IProgress<float>? progress = null,
251251
CancellationToken cancellationToken = default
252252
)
@@ -268,10 +268,8 @@ private static async Task<HttpResponseMessage> ResumableUploadAsync(
268268
}
269269
}
270270

271-
string? cacheKey = null;
272-
if (metadata != null)
273-
cacheKey =
274-
$"{metadata["bucketName"]}/{metadata["objectName"]}/{metadata["contentType"]}";
271+
var cacheKey =
272+
$"{metadata["bucketName"]}/{metadata["objectName"]}/{metadata["contentType"]}";
275273

276274
UploadMemoryCache.TryGet(cacheKey, out var upload);
277275
Uri? fileLocation = null;
@@ -284,13 +282,15 @@ private static async Task<HttpResponseMessage> ResumableUploadAsync(
284282
UploadLength = fileStream.Length,
285283
};
286284

287-
TusCreateResponse responseCreate;
288285
try
289286
{
290-
responseCreate = await client.TusCreateAsync(createOption, cancellationToken);
291-
287+
var responseCreate = await client.TusCreateAsync(
288+
createOption,
289+
cancellationToken
290+
);
291+
292292
fileLocation = responseCreate.FileLocation;
293-
UploadMemoryCache.Set(cacheKey, fileLocation.ToString());
293+
UploadMemoryCache.Set(cacheKey, fileLocation.ToString());
294294
}
295295
catch (TusException error)
296296
{
@@ -308,7 +308,11 @@ private static async Task<HttpResponseMessage> ResumableUploadAsync(
308308
UploadBufferSize = 6 * 1024 * 1024,
309309
UploadType = UploadType.Chunk,
310310
OnProgressAsync = x => ReportProgressAsync(progress, x),
311-
OnCompletedAsync = _ => Task.CompletedTask,
311+
OnCompletedAsync = _ =>
312+
{
313+
UploadMemoryCache.Remove(cacheKey);
314+
return Task.CompletedTask;
315+
},
312316
OnFailedAsync = _ => Task.CompletedTask,
313317
};
314318

Storage/StorageFileApi.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,8 @@ private async Task UploadOrContinue(
744744
await Helpers.HttpUploadClient!.UploadOrContinueFileAsync(
745745
uri,
746746
localPath,
747-
headers,
748747
metadata,
748+
headers,
749749
progress,
750750
cancellationToken
751751
);
@@ -792,8 +792,8 @@ private async Task UploadOrContinue(
792792
await Helpers.HttpUploadClient!.UploadOrContinueByteAsync(
793793
uri,
794794
data,
795-
headers,
796795
metadata,
796+
headers,
797797
progress,
798798
cancellationToken
799799
);

Storage/UploadMemoryCache.cs

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
namespace Supabase.Storage;
66

7+
/// <summary>
8+
/// Provides thread-safe in-memory caching for resumable upload URLs with sliding expiration.
9+
/// </summary>
710
public class UploadMemoryCache
811
{
9-
// Thread-safe in-memory cache for resumable upload URLs keyed by an identifier (e.g., file path or upload id).
10-
// Uses simple sliding expiration.
1112
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new();
1213

13-
// Default sliding expiration for cached URLs.
1414
private static TimeSpan _defaultTtl = TimeSpan.FromMinutes(60);
1515

1616
private static long _version; // helps with testing/observability if needed
@@ -36,13 +36,23 @@ public void Touch()
3636
public bool IsExpired() => DateTimeOffset.UtcNow >= Expiration;
3737
}
3838

39-
// Sets the default time-to-live for future cache entries.
39+
/// <summary>
40+
/// Sets the default time-to-live duration for future cache entries.
41+
/// </summary>
42+
/// <param name="ttl">The time-to-live duration. If less than or equal to zero, defaults to 5 minutes.</param>
4043
public static void SetDefaultTtl(TimeSpan ttl)
4144
{
4245
_defaultTtl = ttl <= TimeSpan.Zero ? TimeSpan.FromMinutes(5) : ttl;
4346
}
4447

45-
// Store or update the resumable upload URL for the provided key.
48+
// Store or upate the resumable upload URL for the provided key.
49+
/// <summary>
50+
/// Stores or updates a resumable upload URL in the cache for the specified key.
51+
/// </summary>
52+
/// <param name="key">The unique identifier for the cached URL.</param>
53+
/// <param name="url">The resumable upload URL to cache.</param>
54+
/// <param name="ttl">Optional time-to-live duration. If not specified, uses the default TTL.</param>
55+
/// <exception cref="ArgumentException">Thrown when key or url is null, empty, or whitespace.</exception>
4656
public static void Set(string key, string url, TimeSpan? ttl = null)
4757
{
4858
if (string.IsNullOrWhiteSpace(key))
@@ -61,32 +71,36 @@ public static void Set(string key, string url, TimeSpan? ttl = null)
6171
CleanupIfNeeded();
6272
}
6373

64-
// Try to get a cached URL. Refreshes sliding expiration on successful hit.
74+
/// <summary>
75+
/// Attempts to retrieve a cached URL by its key. Updates the sliding expiration on successful retrieval.
76+
/// </summary>
77+
/// <param name="key">The unique identifier for the cached URL.</param>
78+
/// <param name="url">When this method returns, contains the cached URL if found; otherwise, null.</param>
79+
/// <returns>True if the URL was found in the cache; otherwise, false.</returns>
6580
public static bool TryGet(string key, out string? url)
6681
{
6782
url = null;
6883
if (string.IsNullOrWhiteSpace(key))
6984
return false;
7085

71-
if (_cache.TryGetValue(key, out var entry))
86+
if (!_cache.TryGetValue(key, out var entry)) return false;
87+
if (entry.IsExpired())
7288
{
73-
if (entry.IsExpired())
74-
{
75-
// Evict expired entry
76-
_cache.TryRemove(key, out _);
77-
return false;
78-
}
79-
80-
// Sliding expiration
81-
entry.Touch();
82-
url = entry.Url;
83-
return true;
89+
_cache.TryRemove(key, out _);
90+
return false;
8491
}
8592

86-
return false;
93+
entry.Touch();
94+
url = entry.Url;
95+
return true;
96+
8797
}
8898

89-
// Remove a cached URL.
99+
/// <summary>
100+
/// Removes a cached URL by its key.
101+
/// </summary>
102+
/// <param name="key">The unique identifier for the cached URL to remove.</param>
103+
/// <returns>True if the URL was successfully removed; otherwise, false.</returns>
90104
public static bool Remove(string key)
91105
{
92106
if (string.IsNullOrWhiteSpace(key))
@@ -98,20 +112,22 @@ public static bool Remove(string key)
98112
return removed;
99113
}
100114

101-
// Clear all cached URLs.
115+
/// <summary>
116+
/// Removes all cached URLs from the cache.
117+
/// </summary>
102118
public static void Clear()
103119
{
104120
_cache.Clear();
105121
Interlocked.Increment(ref _version);
106122
}
107123

108-
// Optionally expose count for diagnostics.
124+
/// <summary>
125+
/// Gets the current number of entries in the cache.
126+
/// </summary>
109127
public static int Count => _cache.Count;
110128

111-
// Simple opportunistic cleanup to remove expired entries.
112129
private static void CleanupIfNeeded()
113130
{
114-
// Cheap scan for expired entries. No need for strict guarantees.
115131
foreach (var kvp in _cache)
116132
{
117133
if (kvp.Value.IsExpired())

0 commit comments

Comments
 (0)