-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-organize folder structure and add size-limited cache
- Loading branch information
1 parent
c207a68
commit 06d4dfe
Showing
15 changed files
with
229 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
using System.Net.Sockets; | ||
using SimpleCDN.Helpers; | ||
using System.Net.Sockets; | ||
|
||
namespace SimpleCDN.Tests | ||
{ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
SimpleCDN/CachedIndexFile.cs → SimpleCDN/Cache/CachedIndexFile.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
namespace SimpleCDN | ||
namespace SimpleCDN.Cache | ||
{ | ||
class CachedIndexFile : CachedFile | ||
{ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using SimpleCDN.Helpers; | ||
using System.Collections; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace SimpleCDN.Cache | ||
{ | ||
/// <summary> | ||
/// A cache that limits the total size of the stored values. When the size of the cache exceeds the specified limit, the oldest (least recently accessed) values are removed. | ||
/// </summary> | ||
/// <param name="maxSize">The maximum size of the cache, in bytes</param> | ||
/// <param name="comparer">The string comparer to use for the internal dictionary</param> | ||
internal class SizeLimitedCache(long maxSize, IEqualityComparer<string>? comparer) | ||
{ | ||
public SizeLimitedCache(long maxSize) : this(maxSize, null) { } | ||
|
||
private readonly Dictionary<string, ValueWrapper> _dictionary = new(comparer); | ||
private readonly long _maxSize = maxSize; | ||
|
||
public CachedFile this[string key] | ||
{ | ||
get => GetValue(key); | ||
set => SetValue(key, value); | ||
} | ||
|
||
public int Count => _dictionary.Count; | ||
|
||
public long Size => _dictionary.Values.Sum(wrapper => wrapper.Size); | ||
|
||
public bool TryGetValue(string key, [NotNullWhen(true)] out CachedFile? value) | ||
{ | ||
if (_dictionary.TryGetValue(key, out ValueWrapper? valueWrapper)) | ||
{ | ||
value = valueWrapper.Value; | ||
return value is not null; | ||
} | ||
|
||
value = default; | ||
|
||
return false; | ||
} | ||
|
||
private void SetValue(string key, CachedFile value) | ||
{ | ||
_dictionary[key] = new ValueWrapper(value); | ||
|
||
var byOldest = _dictionary.OrderBy(p => p.Value.AccessedAt).AsEnumerable(); | ||
|
||
while (Size > _maxSize) | ||
{ | ||
(var oldest, byOldest) = byOldest.RemoveFirst(); | ||
|
||
_dictionary.Remove(oldest.Key); | ||
} | ||
} | ||
|
||
private CachedFile GetValue(string key) | ||
{ | ||
if (_dictionary.TryGetValue(key, out var wrapper)) | ||
return wrapper.Value; | ||
throw new KeyNotFoundException(); | ||
} | ||
|
||
class ValueWrapper(CachedFile value) | ||
{ | ||
private CachedFile _value = value; | ||
public CachedFile Value | ||
{ | ||
get | ||
{ | ||
AccessedAt = Stopwatch.GetTimestamp(); | ||
return _value; | ||
} | ||
set | ||
{ | ||
_value = value; | ||
AccessedAt = Stopwatch.GetTimestamp(); | ||
} | ||
} | ||
public int Size => _value.Content.Length; | ||
public long AccessedAt { get; private set; } = Stopwatch.GetTimestamp(); | ||
|
||
public static implicit operator CachedFile(ValueWrapper wrapper) => wrapper.Value; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace SimpleCDN.Configuration | ||
{ | ||
public class CDNConfiguration | ||
{ | ||
/// <summary> | ||
/// The data root path | ||
/// </summary> | ||
public string? DataRoot { get; set; } | ||
/// <summary> | ||
/// The maximum size of the in-memory cache in kB | ||
/// </summary> | ||
public uint MaxMemoryCacheSize { get; set; } = 500; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,55 @@ | ||
using System.Numerics; | ||
|
||
namespace SimpleCDN | ||
namespace SimpleCDN.Helpers | ||
{ | ||
public static class Extensions | ||
{ | ||
static readonly string[] sizeNames = ["", "k", "M", "G", "T"]; | ||
|
||
public static string FormatByteCount(this long number) | ||
{ | ||
bool isNegative = false; | ||
var isNegative = false; | ||
if (number < 0) | ||
{ | ||
isNegative = true; | ||
number = -number; | ||
} | ||
|
||
int sizeNameIndex = 0; | ||
var sizeNameIndex = 0; | ||
|
||
double result = number; | ||
|
||
for (; sizeNameIndex < sizeNames.Length - 1; sizeNameIndex++) | ||
{ | ||
var div = result / 1000; | ||
if (div < 1) | ||
{ | ||
break; | ||
} | ||
|
||
result = div; | ||
} | ||
|
||
if (isNegative) | ||
{ | ||
result = -result; | ||
} | ||
|
||
return $"{result:0.##}{sizeNames[sizeNameIndex]}B"; | ||
} | ||
|
||
public static (T left, IEnumerable<T> right) RemoveFirst<T>(this IEnumerable<T> source) | ||
{ | ||
var enumerator = source.GetEnumerator(); | ||
|
||
if (!enumerator.MoveNext()) | ||
ArgumentOutOfRangeException.ThrowIfLessThan(0, 1, nameof(source)); | ||
|
||
return (enumerator.Current, RestEnumerator(enumerator)); | ||
|
||
static IEnumerable<T> RestEnumerator(IEnumerator<T> enumerator) | ||
{ | ||
while (enumerator.MoveNext()) | ||
{ | ||
yield return enumerator.Current; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System.IO.Compression; | ||
|
||
namespace SimpleCDN.Helpers | ||
{ | ||
public class GZipHelpers | ||
{ | ||
/// <summary> | ||
/// Compresses the data using GZip. | ||
/// </summary> | ||
/// <param name="data">The data to compress</param> | ||
/// <returns><see langword="false"/> if the compressed data is not smaller than the original data. Otherwise, <see langword="true"/></returns> | ||
public static bool TryCompress(ref Span<byte> data) | ||
{ | ||
using var memoryStream = new MemoryStream(); | ||
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress); | ||
gzipStream.Write(data); | ||
gzipStream.Flush(); | ||
|
||
if (memoryStream.Length >= data.Length) | ||
return false; | ||
|
||
var read = memoryStream.Read(data); | ||
|
||
data = data[..read]; | ||
|
||
return true; | ||
} | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
SimpleCDN/MimeTypeHelpers.cs → SimpleCDN/Helpers/MimeTypeHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.