Persistent Cache

PersistentCache is a system for storing data on disk that persists between application runs. It manages cache size limits, automatically evicts old entries when space is needed, and provides thread-safe access to cached data.

Creating and initializing

Creating a cache

Use PersistentCache::Create to create a new cache instance:

SPtr<PersistentCache> cache = PersistentCache::Create();

Initializing the cache

Use PersistentCache::Initialize to set the cache folder location:

Path cacheFolder = FileSystem::GetWorkingDirectoryPath() + "Cache/";
cache->Initialize(cacheFolder);

The cache folder will be created if it doesn't exist. All cache data will be stored within this folder.

Setting cache size limit

Use PersistentCache::SetMaximumCacheSize to configure the maximum cache size in megabytes:

// Set cache limit to 1024 MB (1 GB)
cache->SetMaximumCacheSize(1024);

The cache will automatically evict entries when it exceeds this limit, starting with the lowest priority entries that were least recently used.

Adding entries

Basic usage

Use PersistentCache::SetEntry to add or update cache entries:

SPtr<MyData> data = B3DMakeShared<MyData>();
data->Value = 42;

Path entryPath = "MyCache/ComputedResult.dat";
cache->SetEntry(entryPath, data);

The path is relative to the cache folder. Subdirectories will be created automatically.

Priority levels

Entries can be assigned different priorities using PersistentCachePriority:

// Low priority - evicted first
cache->SetEntry("Temp/PreviewData.dat", previewData, PersistentCachePriority::Low);

// Normal priority - default
cache->SetEntry("Cache/ProcessedTexture.dat", textureData, PersistentCachePriority::Normal);

// High priority - evicted after normal and low
cache->SetEntry("Cache/ImportantData.dat", importantData, PersistentCachePriority::High);

// Critical priority - evicted last
cache->SetEntry("Cache/EssentialConfig.dat", configData, PersistentCachePriority::Critical);

When the cache reaches its size limit, entries with lower priority are evicted before entries with higher priority.

Non-blocking writes

By default, SetEntry blocks until any existing operations on that entry complete. You can disable blocking:

bool success = cache->SetEntry("Cache/Data.dat", data, PersistentCachePriority::Normal, false);

if(!success)
{
	B3D_LOG(Warning, LogGeneric, "Entry is currently in use, cannot update");
}

Clearing entries

Pass nullptr as the data to remove an entry:

cache->SetEntry("Cache/OldData.dat", nullptr);

Retrieving entries

Basic retrieval

Use PersistentCache::TryGetEntry to retrieve cached data:

Path entryPath = "MyCache/ComputedResult.dat";
SPtr<IReflectable> data = cache->TryGetEntry(entryPath);

if(data)
{
	B3D_LOG(Info, LogGeneric, "Cache hit");
	ProcessData(data);
}
else
{
	B3D_LOG(Info, LogGeneric, "Cache miss");
	// Compute and cache the data
}

Returns nullptr if the entry doesn't exist in the cache.

Type-safe retrieval

Use the template version to automatically cast to a specific type:

SPtr<MyData> data = cache->TryGetEntry<MyData>("MyCache/ComputedResult.dat");

if(data)
{
	B3D_LOG(Info, LogGeneric, "Value: {0}", data->Value);
}

Cache management

Manual eviction

Force eviction to a target size with PersistentCache::RunEviction:

// Evict entries until cache is below 512 MB
cache->RunEviction(512);

Automatic eviction

The cache automatically runs eviction when needed. Use PersistentCache::RunEvictionIfRequired to check and evict:

cache->RunEvictionIfRequired();

Updating the cache

Call PersistentCache::Update every frame to process pending operations:

void GameLoop()
{
	while(IsRunning())
	{
		cache->Update();

		// Rest of game loop
	}
}