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();
        }