/// <summary> /// Virtual Cache Constructor. Virtual Cache now defaults to being a Memory Extender. /// I.e. - Persisted static property defaults to false. Set VirtualCache.Persisted to true /// if wanting to persist the cached data across application runs. /// </summary> /// <param name="storePath">Data Store URI path or the Store name.</param> /// <param name="clusteredData">true (default) will configure the Store to save /// data together with the Keys in the Key Segment (a.k.a. - clustered), /// false will configure Store to save data in its own Data Segment. For small to medium sized /// data, Clustered is recommended, otherwise set this to false.</param> /// <param name="storeFileName">Valid complete file path where to create the File to contain the data Store. /// It will be created if it does not exist yet. Leaving this blank will create the Store within the default /// SOP SystemFile, or in the referenced File portion of the storePath, if storePath has a directory path.</param> /// <param name="fileConfig">File Config should contain description how to manage data allocations on disk and B-Tree /// settings for all the Data Stores of the File. If not set, SOP will use the default configuration.</param> public VirtualCacheWithBackgroundRefresh(string storePath, bool clusteredData = true, string storeFileName = null, Sop.Profile fileConfig = null) : base(storePath, clusteredData, storeFileName, fileConfig) { Server.SystemFile.Store.Locker.Invoke(() => { var storeTimeStampPath = string.Format("{0}ByDate", storePath); Logger.Verbose("Creating/retrieving store {0}.", storeTimeStampPath); _storeKeysByDate = Server.StoreNavigator.GetStore <long, CacheEntryReference>( storeTimeStampPath, new StoreParameters <long> { IsDataInKeySegment = clusteredData, AutoFlush = !clusteredData, MruManaged = false }); }); if (isMultiThreaded) { Processor.Register(this); } }
/// <summary> /// Dispose this Virtual Cache instance. Update and On Idle tasks are waited for completion if /// ongoing during time of Dispose. Transaction is committed if pending and Virtual Cache is /// set to persist cached items to disk (parameter persisted was set to true on ctor). /// /// The cache entries' data Stores are closed then disposed off as well. /// </summary> override public void Dispose() { bool needsCommit = false; if (Processor != null) { needsCommit = Processor.Unregister(this); } #region wait for ongoing tasks to finish & dispose them after. if (!Persisted) { ExitSignal = true; } if (_updateTimeStampTask != null) { // this is a quick task, no need to set a timeout. if (_updateTimeStampTask.Status == TaskStatus.Running) { _updateTimeStampTask.Wait(); } _updateTimeStampTask.Dispose(); _updateTimeStampTask = null; } if (_onIdleTask != null) { // this is a quick task, no need to set a timeout. if (_onIdleTask.Status == TaskStatus.Running || _onIdleTask.Status == TaskStatus.WaitingToRun) { _onIdleTask.Wait(); } _onIdleTask.Dispose(); _onIdleTask = null; } // flush all in-flight changes if persisted... if (!_store.Locker.TransactionRollback && Persisted) { ProcessBatch(true); ProcessExpiredEntries(); } #endregion if (_storeKeysByDate != null) { Logger.Verbose("Disposing Store {0}.", _storeKeysByDate.Name); if (!Persisted) { ((OnDisk.Algorithm.SortedDictionary.ISortedDictionaryOnDisk)_storeKeysByDate.RealObject).IsUnloading = true; } _storeKeysByDate.Dispose(); _storeKeysByDate = null; } if (_store != null) { Logger.Verbose("Disposing Store {0}.", _store.Name); if (!Persisted) { ((OnDisk.Algorithm.SortedDictionary.ISortedDictionaryOnDisk)_store.RealObject).IsUnloading = true; } _store.Dispose(); _store = null; } if (needsCommit) { if (Persisted) { // commit if Persisted is true. Commit(true); } else { // if in memextender, destroy Server to cause removal of data file. lock (_serverLocker) { // unload any inflight changes in memory, no need to save on dispose. ((OnDisk.ObjectServer)((Sop.ObjectServer)_server).RealObjectServer).Unload(); _server.Dispose(); _server = null; } } } if (Logger != null) { Logger.Dispose(); Logger = null; } }