Enhance caching mechanisms and introduce adaptive features

- Updated caching logic to support size-based promotion filtering, ensuring that not all files may be promoted based on size constraints.
- Implemented adaptive caching strategies with a new AdaptiveCacheManager to analyze access patterns and adjust caching strategies dynamically.
- Introduced predictive caching features with a PredictiveCacheManager to prefetch content based on access patterns.
- Added a CacheWarmer to preload popular content into the cache, improving access times for frequently requested files.
- Refactored memory management with a DynamicCacheManager to adjust cache sizes based on system memory usage.
- Enhanced VFS interface and file metadata handling to support new features and improve performance.
- Updated tests to validate new caching behaviors and ensure reliability of the caching system.
This commit is contained in:
2025-09-21 22:47:13 -05:00
parent bbe014e334
commit 45ae234694
12 changed files with 2212 additions and 189 deletions

View File

@@ -5,7 +5,7 @@ import (
"bytes"
"container/list"
"io"
"s1d3sw1ped/SteamCache2/vfs"
"s1d3sw1ped/SteamCache2/vfs/types"
"s1d3sw1ped/SteamCache2/vfs/vfserror"
"sort"
"strings"
@@ -13,19 +13,43 @@ import (
"time"
)
// VFS defines the interface for virtual file systems
type VFS interface {
// Create creates a new file at the given key
Create(key string, size int64) (io.WriteCloser, error)
// Open opens the file at the given key for reading
Open(key string) (io.ReadCloser, error)
// Delete removes the file at the given key
Delete(key string) error
// Stat returns information about the file at the given key
Stat(key string) (*types.FileInfo, error)
// Name returns the name of this VFS
Name() string
// Size returns the current size of the VFS
Size() int64
// Capacity returns the maximum capacity of the VFS
Capacity() int64
}
// Ensure MemoryFS implements VFS.
var _ vfs.VFS = (*MemoryFS)(nil)
var _ VFS = (*MemoryFS)(nil)
// MemoryFS is an in-memory virtual file system
type MemoryFS struct {
data map[string]*bytes.Buffer
info map[string]*vfs.FileInfo
info map[string]*types.FileInfo
capacity int64
size int64
mu sync.RWMutex
keyLocks []sync.Map // Sharded lock pools for better concurrency
LRU *lruList
timeUpdater *vfs.BatchedTimeUpdate // Batched time updates for better performance
timeUpdater *types.BatchedTimeUpdate // Batched time updates for better performance
}
// Number of lock shards for reducing contention
@@ -44,25 +68,25 @@ func newLruList() *lruList {
}
}
func (l *lruList) Add(key string, fi *vfs.FileInfo) {
func (l *lruList) Add(key string, fi *types.FileInfo) {
elem := l.list.PushFront(fi)
l.elem[key] = elem
}
func (l *lruList) MoveToFront(key string, timeUpdater *vfs.BatchedTimeUpdate) {
func (l *lruList) MoveToFront(key string, timeUpdater *types.BatchedTimeUpdate) {
if elem, exists := l.elem[key]; exists {
l.list.MoveToFront(elem)
// Update the FileInfo in the element with new access time
if fi := elem.Value.(*vfs.FileInfo); fi != nil {
if fi := elem.Value.(*types.FileInfo); fi != nil {
fi.UpdateAccessBatched(timeUpdater)
}
}
}
func (l *lruList) Remove(key string) *vfs.FileInfo {
func (l *lruList) Remove(key string) *types.FileInfo {
if elem, exists := l.elem[key]; exists {
delete(l.elem, key)
if fi := l.list.Remove(elem).(*vfs.FileInfo); fi != nil {
if fi := l.list.Remove(elem).(*types.FileInfo); fi != nil {
return fi
}
}
@@ -84,12 +108,12 @@ func New(capacity int64) *MemoryFS {
return &MemoryFS{
data: make(map[string]*bytes.Buffer),
info: make(map[string]*vfs.FileInfo),
info: make(map[string]*types.FileInfo),
capacity: capacity,
size: 0,
keyLocks: keyLocks,
LRU: newLruList(),
timeUpdater: vfs.NewBatchedTimeUpdate(100 * time.Millisecond), // Update time every 100ms
timeUpdater: types.NewBatchedTimeUpdate(100 * time.Millisecond), // Update time every 100ms
}
}
@@ -110,6 +134,35 @@ func (m *MemoryFS) Capacity() int64 {
return m.capacity
}
// GetFragmentationStats returns memory fragmentation statistics
func (m *MemoryFS) GetFragmentationStats() map[string]interface{} {
m.mu.RLock()
defer m.mu.RUnlock()
var totalCapacity int64
var totalUsed int64
var bufferCount int
for _, buffer := range m.data {
totalCapacity += int64(buffer.Cap())
totalUsed += int64(buffer.Len())
bufferCount++
}
fragmentationRatio := float64(0)
if totalCapacity > 0 {
fragmentationRatio = float64(totalCapacity-totalUsed) / float64(totalCapacity)
}
return map[string]interface{}{
"buffer_count": bufferCount,
"total_capacity": totalCapacity,
"total_used": totalUsed,
"fragmentation_ratio": fragmentationRatio,
"average_buffer_size": float64(totalUsed) / float64(bufferCount),
}
}
// getShardIndex returns the shard index for a given key
func getShardIndex(key string) int {
// Use FNV-1a hash for good distribution
@@ -159,7 +212,7 @@ func (m *MemoryFS) Create(key string, size int64) (io.WriteCloser, error) {
buffer := &bytes.Buffer{}
m.data[key] = buffer
fi := vfs.NewFileInfo(key, size)
fi := types.NewFileInfo(key, size)
m.info[key] = fi
m.LRU.Add(key, fi)
// Initialize access time with current time
@@ -230,23 +283,39 @@ func (m *MemoryFS) Open(key string) (io.ReadCloser, error) {
return nil, vfserror.ErrNotFound
}
// Create a copy of the buffer for reading
data := make([]byte, buffer.Len())
copy(data, buffer.Bytes())
// Use zero-copy approach - return reader that reads directly from buffer
m.mu.Unlock()
return &memoryReadCloser{
reader: bytes.NewReader(data),
buffer: buffer,
offset: 0,
}, nil
}
// memoryReadCloser implements io.ReadCloser for memory files
// memoryReadCloser implements io.ReadCloser for memory files with zero-copy optimization
type memoryReadCloser struct {
reader *bytes.Reader
buffer *bytes.Buffer
offset int64
}
func (mrc *memoryReadCloser) Read(p []byte) (n int, err error) {
return mrc.reader.Read(p)
if mrc.offset >= int64(mrc.buffer.Len()) {
return 0, io.EOF
}
// Zero-copy read directly from buffer
available := mrc.buffer.Len() - int(mrc.offset)
toRead := len(p)
if toRead > available {
toRead = available
}
// Read directly from buffer without copying
data := mrc.buffer.Bytes()
copy(p, data[mrc.offset:mrc.offset+int64(toRead)])
mrc.offset += int64(toRead)
return toRead, nil
}
func (mrc *memoryReadCloser) Close() error {
@@ -286,7 +355,7 @@ func (m *MemoryFS) Delete(key string) error {
}
// Stat returns file information
func (m *MemoryFS) Stat(key string) (*vfs.FileInfo, error) {
func (m *MemoryFS) Stat(key string) (*types.FileInfo, error) {
if key == "" {
return nil, vfserror.ErrInvalidKey
}
@@ -327,7 +396,7 @@ func (m *MemoryFS) EvictLRU(bytesNeeded uint) uint {
break
}
fi := elem.Value.(*vfs.FileInfo)
fi := elem.Value.(*types.FileInfo)
key := fi.Key
// Remove from LRU
@@ -355,7 +424,7 @@ func (m *MemoryFS) EvictBySize(bytesNeeded uint, ascending bool) uint {
defer m.mu.Unlock()
var evicted uint
var candidates []*vfs.FileInfo
var candidates []*types.FileInfo
// Collect all files
for _, fi := range m.info {
@@ -403,7 +472,7 @@ func (m *MemoryFS) EvictFIFO(bytesNeeded uint) uint {
defer m.mu.Unlock()
var evicted uint
var candidates []*vfs.FileInfo
var candidates []*types.FileInfo
// Collect all files
for _, fi := range m.info {