185 lines
5.2 KiB
C#
185 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using EmbedIO.Files.Internal;
|
|
|
|
namespace EmbedIO.Files
|
|
{
|
|
public sealed partial class FileCache
|
|
{
|
|
internal class Section
|
|
{
|
|
private readonly object _syncRoot = new object();
|
|
private readonly Dictionary<string, FileCacheItem> _items = new Dictionary<string, FileCacheItem>(StringComparer.Ordinal);
|
|
private long _totalSize;
|
|
private string? _oldestKey;
|
|
private string? _newestKey;
|
|
|
|
public void Clear()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
ClearCore();
|
|
}
|
|
}
|
|
|
|
public void Add(string path, FileCacheItem item)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
AddItemCore(path, item);
|
|
}
|
|
}
|
|
|
|
public void Remove(string path)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
RemoveItemCore(path);
|
|
}
|
|
}
|
|
|
|
public bool TryGet(string path, out FileCacheItem item)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
if (!_items.TryGetValue(path, out item))
|
|
return false;
|
|
|
|
RefreshItemCore(path, item);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal long GetLeastRecentUseTime()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
return _oldestKey == null ? long.MaxValue : _items[_oldestKey].LastUsedAt;
|
|
}
|
|
}
|
|
|
|
// Removes least recently used item.
|
|
// Returns size of removed item.
|
|
internal long RemoveLeastRecentItem()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
return RemoveLeastRecentItemCore();
|
|
}
|
|
}
|
|
|
|
internal long GetTotalSize()
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
return _totalSize;
|
|
}
|
|
}
|
|
|
|
internal void UpdateTotalSize(long delta)
|
|
{
|
|
lock (_syncRoot)
|
|
{
|
|
_totalSize += delta;
|
|
}
|
|
}
|
|
|
|
private void ClearCore()
|
|
{
|
|
_items.Clear();
|
|
_totalSize = 0;
|
|
_oldestKey = null;
|
|
_newestKey = null;
|
|
}
|
|
|
|
// Adds an item as most recently used.
|
|
private void AddItemCore(string path, FileCacheItem item)
|
|
{
|
|
item.PreviousKey = _newestKey;
|
|
item.NextKey = null;
|
|
item.LastUsedAt = TimeBase.ElapsedTicks;
|
|
|
|
if (_newestKey != null)
|
|
_items[_newestKey].NextKey = path;
|
|
|
|
_newestKey = path;
|
|
|
|
_items[path] = item;
|
|
_totalSize += item.SizeInCache;
|
|
}
|
|
|
|
// Removes an item.
|
|
private void RemoveItemCore(string path)
|
|
{
|
|
if (!_items.TryGetValue(path, out var item))
|
|
return;
|
|
|
|
if (_oldestKey == path)
|
|
_oldestKey = item.NextKey;
|
|
|
|
if (_newestKey == path)
|
|
_newestKey = item.PreviousKey;
|
|
|
|
if (item.PreviousKey != null)
|
|
_items[item.PreviousKey].NextKey = item.NextKey;
|
|
|
|
if (item.NextKey != null)
|
|
_items[item.NextKey].PreviousKey = item.PreviousKey;
|
|
|
|
item.PreviousKey = null;
|
|
item.NextKey = null;
|
|
|
|
_items.Remove(path);
|
|
_totalSize -= item.SizeInCache;
|
|
}
|
|
|
|
// Removes the least recently used item.
|
|
// returns size of removed item.
|
|
private long RemoveLeastRecentItemCore()
|
|
{
|
|
var path = _oldestKey;
|
|
if (path == null)
|
|
return 0;
|
|
|
|
var item = _items[path];
|
|
|
|
if ((_oldestKey = item.NextKey) != null)
|
|
_items[_oldestKey].PreviousKey = null;
|
|
|
|
if (_newestKey == path)
|
|
_newestKey = null;
|
|
|
|
item.PreviousKey = null;
|
|
item.NextKey = null;
|
|
|
|
_items.Remove(path);
|
|
_totalSize -= item.SizeInCache;
|
|
return item.SizeInCache;
|
|
}
|
|
|
|
// Moves an item to most recently used.
|
|
private void RefreshItemCore(string path, FileCacheItem item)
|
|
{
|
|
item.LastUsedAt = TimeBase.ElapsedTicks;
|
|
|
|
if (_newestKey == path)
|
|
return;
|
|
|
|
if (_oldestKey == path)
|
|
_oldestKey = item.NextKey;
|
|
|
|
if (item.PreviousKey != null)
|
|
_items[item.PreviousKey].NextKey = item.NextKey;
|
|
|
|
if (item.NextKey != null)
|
|
_items[item.NextKey].PreviousKey = item.PreviousKey;
|
|
|
|
item.PreviousKey = _newestKey;
|
|
item.NextKey = null;
|
|
|
|
_items[_newestKey!].NextKey = path;
|
|
_newestKey = path;
|
|
}
|
|
}
|
|
}
|
|
} |