// Initializes a new instance of the KeyValueStore. public KeyValueStore(string baseFileName, RazorCache cache) { if (!Directory.Exists (baseFileName)) Directory.CreateDirectory (baseFileName); _manifest = new Manifest (baseFileName); _manifest.Logger = RazorDBx.C5.Logger.Log; int memTableVersion = _manifest.CurrentVersion (0); CheckForIncompleteJournalRotation (baseFileName, memTableVersion); // Check for a previously aborted journal rotation. _currentJournaledMemTable = new JournaledMemTable (_manifest.BaseFileName, memTableVersion); // Create new journal for this run (and potentially load from disk, if there was data loaded previously). _cache = cache == null ? new RazorCache () : cache; }
void CheckForIncompleteJournalRotation(string baseFileName, int currentMemTableVersion) { int previousMemTableVersion = currentMemTableVersion - 1; if (File.Exists (Config.JournalFile (baseFileName, previousMemTableVersion))) { // Is there a left-over journal from a previous rotation that was aborted while in rotation? var memTable = new JournaledMemTable (baseFileName, previousMemTableVersion); memTable.WriteToSortedBlockTable (_manifest); memTable.Close (); } }
// Rotates the mem table. public void RotateMemTable() { lock (memTableRotationLock) { if (_currentJournaledMemTable.Full) { // Double check the flag in case we have multiple threads that make it into this routine. _rotationSemaphore.WaitOne (); // Wait for the rotation gate to be open, and automatically reset once a single thread gets through. _rotatedJournaledMemTable = Interlocked.Exchange<JournaledMemTable> (ref _currentJournaledMemTable, new JournaledMemTable (_manifest.BaseFileName, _manifest.NextVersion (0))); ThreadPool.QueueUserWorkItem ((o) => { try { _rotatedJournaledMemTable.WriteToSortedBlockTable (_manifest); _rotatedJournaledMemTable = null; } finally { _rotationSemaphore.Release (); // Open the gate for the next rotation. } }); } } }
// Truncates a current database. public void Truncate() { _currentJournaledMemTable.Close (); TableManager.Default.Close (this); foreach (var pair in _secondaryIndexes) pair.Value.Close (FastClose); string basePath = Path.GetFullPath (Manifest.BaseFileName); foreach (string file in Directory.GetFiles(basePath, "*.*", SearchOption.AllDirectories)) File.Delete (file); foreach (string dir in Directory.GetDirectories(basePath, "*.*", SearchOption.AllDirectories)) Directory.Delete (dir, true); _manifest = new Manifest (basePath); _currentJournaledMemTable = new JournaledMemTable (_manifest.BaseFileName, _manifest.CurrentVersion (0)); _cache = new RazorCache (); _secondaryIndexes = new Dictionary<string, KeyValueStore> (StringComparer.OrdinalIgnoreCase); Manifest.LogMessage ("Database Truncated."); }
// Close a specified value. public void Close(bool fast = false) { // Make sure any inflight rotations have occurred before shutting down. if (!_rotationSemaphore.WaitOne (30000)) throw new TimeoutException ("Timed out waiting for table rotation to complete."); _rotationSemaphore.Release (); // Release again in case another thread tries to close it again. if (!finalizing && !fast) TableManager.Default.Close (this); if (_currentJournaledMemTable != null) { _currentJournaledMemTable.Close (); _currentJournaledMemTable = null; } if (_secondaryIndexes != null) foreach (var idx in _secondaryIndexes) idx.Value.Close (fast); GC.SuppressFinalize (this); // Don't finalize since we already closed it. }