private void UpdateActivePartition() { lock (_activePartitionUpdateLock) { if (_activePartition == null || DateTimeOffset.UtcNow - _activePartition.Created >= _partitionInterval) { // Update the active partition. _activePartition = new TemporalPartition(_partitionBasePath, _partitionOpenOrCreateCallback); _partitions.Enqueue(_activePartition); } } }
/// <summary> /// Initializes a new instance of the <see cref="T:LibWhipLru.Cache.PartitionedTemporalGuidCache"/> class. /// </summary> public PartitionedTemporalGuidCache( string partitionBasePath, TimeSpan partitionInterval, Action <string> partitionOpenOrCreateCallback, Action <string> partitionDeletionCallback, Action <Guid, string, string> partitionTransferAssetCallback, Func <string, Dictionary <Guid, uint> > partitionFoundCallback ) { if (string.IsNullOrWhiteSpace(partitionBasePath)) { throw new ArgumentNullException(nameof(partitionBasePath), "Cannot be null, empty, or whitespace."); } if (partitionInterval < MIN_PARTITION_INTERVAL) { throw new ArgumentOutOfRangeException(nameof(partitionInterval), $"Cannot be less than {MIN_PARTITION_INTERVAL.TotalSeconds} seconds."); } _partitionBasePath = partitionBasePath; _partitionInterval = partitionInterval; _partitionOpenOrCreateCallback = partitionOpenOrCreateCallback ?? throw new ArgumentNullException(nameof(partitionOpenOrCreateCallback)); _partitionDeletionCallback = partitionDeletionCallback ?? throw new ArgumentNullException(nameof(partitionDeletionCallback)); _partitionTransferAssetCallback = partitionTransferAssetCallback ?? throw new ArgumentNullException(nameof(partitionTransferAssetCallback)); if (partitionFoundCallback == null) { throw new ArgumentNullException(nameof(partitionFoundCallback)); } _cache = new ConcurrentDictionary <Guid, MetaAsset>(); _partitions = new ConcurrentQueue <TemporalPartition>(); // Restore from disk, if there's something to restore from. foreach (var dbPath in Directory.EnumerateFileSystemEntries(partitionBasePath, "*", SearchOption.TopDirectoryOnly)) { var assetsFound = partitionFoundCallback(dbPath); if ((assetsFound?.Count ?? 0) > 0) { var partition = new TemporalPartition(dbPath); _partitions.Enqueue(partition); // Will wind up restoring assets that were previously "purged" as the per-item purge operation only removes the ID from active memory. // Currently this is acceptible behavior as the per-item purge is only expectd to be used to clean up inconsistencies by purging the ID then adding a fresh copy. // Everything else will just eventually fall out the LRU process. foreach (var asset in assetsFound) { _cache.AddOrUpdate( asset.Key, assetId => new MetaAsset { // add Id = assetId, Partition = partition, Size = asset.Value }, (assetId, oldMeta) => { // update oldMeta.Partition = partition; oldMeta.Size = asset.Value; return(oldMeta); } ); } } } UpdateActivePartition(); }