void MakeWrittable() { if (_writting) { return; } if (_preapprovedWritting) { _writting = true; _preapprovedWritting = false; _keyValueDB.WriteStartTransaction(); return; } if (_readOnly) { throw new BTDBTransactionRetryException("Cannot write from readOnly transaction"); } var oldBTreeRoot = BtreeRoot; _btreeRoot = _keyValueDB.MakeWrittableTransaction(this, oldBTreeRoot); _keyValueDB.StartedUsingBTreeRoot(_btreeRoot); _keyValueDB.FinishedUsingBTreeRoot(oldBTreeRoot); _btreeRoot.DescriptionForLeaks = _descriptionForLeaks; _writting = true; InvalidateCurrentKey(); _keyValueDB.WriteStartTransaction(); }
void CalculateFileUsefullness(IBTreeRootNode root) { root.Iterate((valueFileId, valueOfs, valueSize) => { _cancellation.ThrowIfCancellationRequested(); _fileStats.GetOrFakeValueRef(valueFileId).AddLength((uint)Math.Abs(valueSize)); }); }
void ForbidDeleteOfFilesUsedByStillRunningOldTransaction(IBTreeRootNode root) { root.Iterate((valueFileId, valueOfs, valueSize) => { _cancellation.ThrowIfCancellationRequested(); _fileStats.GetOrFakeValueRef(valueFileId).MarkForbidToDelete(); }); }
internal void CommitWrittingTransaction(IBTreeRootNode btreeRoot) { lock (_writeLock) { _writingTransaction = null; _lastCommited = btreeRoot; TryDequeWaiterForWrittingTransaction(); } }
public InMemoryKeyValueDBTransaction(InMemoryKeyValueDB keyValueDB, IBTreeRootNode btreeRoot, bool writing, bool readOnly) { _preapprovedWriting = writing; _readOnly = readOnly; _keyValueDB = keyValueDB; _btreeRoot = btreeRoot; _keyIndex = -1; _cursorMovedCounter = 0; }
public KeyValueDBTransaction(KeyValueDB keyValueDB, IBTreeRootNode btreeRoot, bool writing, bool readOnly) { _preapprovedWriting = writing; _readOnly = readOnly; _keyValueDB = keyValueDB; _btreeRoot = btreeRoot; _keyIndex = -1; _cursorMovedCounter = 0; _keyValueDB.StartedUsingBTreeRoot(_btreeRoot); }
public void Dispose() { if (_writting || _preapprovedWritting) { _keyValueDB.RevertWrittingTransaction(); _writting = false; _preapprovedWritting = false; } _btreeRoot = null; }
internal IBTreeRootNode MakeWrittableTransaction(InMemoryKeyValueDBTransaction keyValueDBTransaction, IBTreeRootNode btreeRoot) { lock (_writeLock) { if (_writingTransaction != null) throw new BTDBTransactionRetryException("Another writting transaction already running"); if (LastCommited != btreeRoot) throw new BTDBTransactionRetryException("Another writting transaction already finished"); _writingTransaction = keyValueDBTransaction; return btreeRoot.NewTransactionRoot(); } }
uint CreateKeyIndexFile(IBTreeRootNode root, CancellationToken cancellation) { var start = DateTime.UtcNow; var file = FileCollection.AddFile("kvi"); var writer = file.GetAppenderWriter(); var keyCount = root.CalcKeyCount(); if (root.TrLogFileId != 0) { FileCollection.ConcurentTemporaryTruncate(root.TrLogFileId, root.TrLogOffset); } var keyIndex = new FileKeyIndex(FileCollection.NextGeneration(), FileCollection.Guid, root.TrLogFileId, root.TrLogOffset, keyCount, root.CommitUlong, KeyIndexCompression.None); keyIndex.WriteHeader(writer); if (keyCount > 0) { var stack = new List <NodeIdxPair>(); var prevKey = ByteBuffer.NewEmpty(); root.FillStackByIndex(stack, 0); do { cancellation.ThrowIfCancellationRequested(); var nodeIdxPair = stack[stack.Count - 1]; var memberValue = ((IBTreeLeafNode)nodeIdxPair.Node).GetMemberValue(nodeIdxPair.Idx); var key = ((IBTreeLeafNode)nodeIdxPair.Node).GetKey(nodeIdxPair.Idx); var prefixLen = 0; var minLen = Math.Min(prevKey.Length, key.Length); for (int i = 0; i < minLen; i++) { if (prevKey[i] != key[i]) { prefixLen = i; break; } } writer.WriteVUInt32((uint)prefixLen); writer.WriteVUInt32((uint)(key.Length - prefixLen)); writer.WriteBlock(key.SubBuffer(prefixLen)); writer.WriteVUInt32(memberValue.ValueFileId); writer.WriteVUInt32(memberValue.ValueOfs); writer.WriteVInt32(memberValue.ValueSize); prevKey = key; } while (root.FindNextKey(stack)); } writer.FlushBuffer(); file.HardFlush(); writer.WriteInt32(EndOfIndexFileMarker); writer.FlushBuffer(); file.HardFlush(); file.Truncate(); FileCollection.SetInfo(file.Index, keyIndex); Logger?.KeyValueIndexCreated(file.Index, keyIndex.KeyValueCount, file.GetSize(), DateTime.UtcNow - start); return(file.Index); }
public InMemoryKeyValueDBTransaction(InMemoryKeyValueDB keyValueDB, IBTreeRootNode btreeRoot, bool writting, bool readOnly) { _preapprovedWritting = writting; _readOnly = readOnly; _keyValueDB = keyValueDB; _btreeRoot = btreeRoot; _prefix = BitArrayManipulation.EmptyByteArray; _prefixKeyStart = 0; _prefixKeyCount = -1; _keyIndex = -1; }
public KeyValueDBTransaction(KeyValueDB keyValueDB, IBTreeRootNode btreeRoot, bool writing, bool readOnly) { _preapprovedWriting = writing; _readOnly = readOnly; _keyValueDB = keyValueDB; _btreeRoot = btreeRoot; _prefix = Array.Empty <byte>(); _prefixKeyStart = 0; _prefixKeyCount = -1; _keyIndex = -1; _keyValueDB.StartedUsingBTreeRoot(_btreeRoot); }
void CalculateFileUsefullness(IBTreeRootNode root, bool uptodate) { root.Iterate((valueFileId, valueOfs, valueSize) => { var id = valueFileId; var fileStats = _fileStats; _cancellation.ThrowIfCancellationRequested(); if (id < fileStats.Length) { fileStats[id].AddLength((uint)Math.Abs(valueSize), uptodate); } }); }
internal void StartedUsingBTreeRoot(IBTreeRootNode btreeRoot) { lock (_usedBTreeRootNodesLock) { var uses = btreeRoot.UseCount; uses++; btreeRoot.UseCount = uses; if (uses == 1) { _usedBTreeRootNodes.Add(btreeRoot); } } }
internal long AtomicallyChangeBTree(Action <IBTreeRootNode> action) { using (var tr = StartWritingTransaction().Result) { var newRoot = (tr as KeyValueDBTransaction).BtreeRoot; action(newRoot); lock (_writeLock) { _lastCommited = newRoot; } return(newRoot.TransactionId); } }
internal void FastStartCleanUp() { if (_keyValueDB.FileCollection.GetCount() == 0) { return; } _root = _keyValueDB.LastCommited; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(); MarkTotallyUselessFilesAsUnknown(); }
internal void FinishedUsingBTreeRoot(IBTreeRootNode btreeRoot) { lock (_usedBTreeRootNodesLock) { var uses = btreeRoot.UseCount; uses--; btreeRoot.UseCount = uses; if (uses == 0) { _usedBTreeRootNodes.Remove(btreeRoot); } } }
private void ForbidDeleteOfFilesUsedByStillRunningOldTransaction(IBTreeRootNode root) { root.Iterate((valueFileId, valueOfs, valueSize) => { var id = valueFileId; var fileStats = _fileStats; _cancellation.ThrowIfCancellationRequested(); if (id < fileStats.Length) { fileStats[id].MarkForbidToDelete(); } }); }
internal void FastStartCleanUp() { if (_keyValueDB.FileCollection.GetCount() == 0) { return; } _root = _keyValueDB.LastCommited; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(_root, false); // useless files are calculated from "old" values, but they are uptodate MarkTotallyUselessFilesAsUnknown(); }
internal void FastStartCleanUp() { if (_keyValueDB.FileCollection.GetCount() == 0) return; _root = _keyValueDB.LastCommited; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(); var toRemoveFileIds = new List<uint>(); for (var i = 0; i < _fileStats.Length; i++) { if (_fileStats[i].Useless()) toRemoveFileIds.Add((uint) i); } _keyValueDB.MarkAsUnknown(toRemoveFileIds); }
public void Dispose() { if (_writting || _preapprovedWritting) { _keyValueDB.RevertWrittingTransaction(_preapprovedWritting); _writting = false; _preapprovedWritting = false; } if (_btreeRoot == null) { return; } _keyValueDB.FinishedUsingBTreeRoot(_btreeRoot); _btreeRoot = null; }
void UpdateTransactionLogInBTreeRoot(IBTreeRootNode btreeRoot) { if (btreeRoot.TrLogFileId != _fileIdWithTransactionLog && btreeRoot.TrLogFileId != 0) { _compactorScheduler?.AdviceRunning(); } btreeRoot.TrLogFileId = _fileIdWithTransactionLog; if (_writerWithTransactionLog != null) { btreeRoot.TrLogOffset = (uint)_writerWithTransactionLog.GetCurrentPosition(); } else { btreeRoot.TrLogOffset = 0; } }
internal bool Run() { if (_keyValueDB.FileCollection.GetCount() == 0) return false; _root = _keyValueDB.LastCommited; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(); var totalWaste = CalcTotalWaste(); if (totalWaste < (ulong)_keyValueDB.MaxTrLogFileSize / 4) { if (_keyValueDB.DistanceFromLastKeyIndex(_root) < (ulong)_keyValueDB.MaxTrLogFileSize / 4) return false; _keyValueDB.CreateIndexFile(_cancellation); _keyValueDB.FileCollection.DeleteAllUnknownFiles(); return false; } _cancellation.ThrowIfCancellationRequested(); uint valueFileId; var writer = _keyValueDB.StartPureValuesFile(out valueFileId); _newPositionMap = new Dictionary<ulong, uint>(); var toRemoveFileIds = new List<uint>(); while (true) { var wastefullFileId = FindMostWastefullFile(_keyValueDB.MaxTrLogFileSize - writer.GetCurrentPosition()); if (wastefullFileId == 0) break; MoveValuesContent(writer, wastefullFileId); _fileStats[wastefullFileId] = new FileStat(0); toRemoveFileIds.Add(wastefullFileId); } var valueFile = _keyValueDB.FileCollection.GetFile(valueFileId); valueFile.HardFlush(); valueFile.Truncate(); var btreesCorrectInTransactionId = _keyValueDB.AtomicallyChangeBTree(root => root.RemappingIterate((uint oldFileId, uint oldOffset, out uint newFileId, out uint newOffset) => { newFileId = valueFileId; _cancellation.ThrowIfCancellationRequested(); return _newPositionMap.TryGetValue(((ulong)oldFileId << 32) | oldOffset, out newOffset); })); _keyValueDB.CreateIndexFile(_cancellation); _keyValueDB.WaitForFinishingTransactionsBefore(btreesCorrectInTransactionId, _cancellation); if (_newPositionMap.Count == 0) { toRemoveFileIds.Add(valueFileId); } _keyValueDB.MarkAsUnknown(toRemoveFileIds); _keyValueDB.FileCollection.DeleteAllUnknownFiles(); return true; }
public void Commit() { if (BtreeRoot == null) throw new BTDBException("Transaction already commited or disposed"); InvalidateCurrentKey(); var currentBtreeRoot = _btreeRoot; _btreeRoot = null; if (_preapprovedWritting) { _preapprovedWritting = false; _keyValueDB.RevertWrittingTransaction(); } else if (_writting) { _keyValueDB.CommitWrittingTransaction(currentBtreeRoot); _writting = false; } }
internal ulong DistanceFromLastKeyIndex(IBTreeRootNode root) { var keyIndex = FileCollection.FileInfos.Where(p => p.Value.FileType == KVFileType.KeyIndex).Select(p => (IKeyIndex)p.Value).FirstOrDefault(); if (keyIndex == null) { if (FileCollection.FileInfos.Count(p => p.Value.SubDBId == 0) > 1) { return(ulong.MaxValue); } return(root.TrLogOffset); } if (root.TrLogFileId != keyIndex.TrLogFileId) { return(ulong.MaxValue); } return(root.TrLogOffset - keyIndex.TrLogOffset); }
public void Commit() { if (BtreeRoot == null) { throw new BTDBException("Transaction already commited or disposed"); } InvalidateCurrentKey(); var currentBtreeRoot = _btreeRoot; _btreeRoot = null; if (_preapprovedWritting) { _preapprovedWritting = false; _keyValueDB.RevertWrittingTransaction(); } else if (_writting) { _keyValueDB.CommitWrittingTransaction(currentBtreeRoot); _writting = false; } }
void MakeWrittable() { if (_writting) { return; } if (_preapprovedWritting) { _writting = true; _preapprovedWritting = false; return; } if (_readOnly) { throw new BTDBTransactionRetryException("Cannot write from readOnly transaction"); } var oldBTreeRoot = BtreeRoot; _btreeRoot = _keyValueDB.MakeWrittableTransaction(this, oldBTreeRoot); _writting = true; InvalidateCurrentKey(); }
internal void CommitWrittingTransaction(IBTreeRootNode btreeRoot, bool temporaryCloseTransactionLog) { var deltaUlong = unchecked (btreeRoot.CommitUlong - _lastCommited.CommitUlong); if (deltaUlong != 0) { _writerWithTransactionLog.WriteUInt8((byte)KVCommandType.CommitWithDeltaUlong); _writerWithTransactionLog.WriteVUInt64(deltaUlong); } else { _writerWithTransactionLog.WriteUInt8((byte)KVCommandType.Commit); } if (DurableTransactions || !temporaryCloseTransactionLog) { _writerWithTransactionLog.FlushBuffer(); } UpdateTransactionLogInBTreeRoot(btreeRoot); if (DurableTransactions) { _fileWithTransactionLog.HardFlush(); } if (temporaryCloseTransactionLog) { _writerWithTransactionLog.WriteUInt8((byte)KVCommandType.TemporaryEndOfFile); _writerWithTransactionLog.FlushBuffer(); if (DurableTransactions) { _fileWithTransactionLog.HardFlush(); } _fileWithTransactionLog.Truncate(); } lock (_writeLock) { _writingTransaction = null; _lastCommited = btreeRoot; TryDequeWaiterForWrittingTransaction(); } }
internal void FastStartCleanUp() { if (_keyValueDB.FileCollection.GetCount() == 0) { return; } _root = _keyValueDB.LastCommited; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(); var toRemoveFileIds = new List <uint>(); for (var i = 0; i < _fileStats.Length; i++) { if (_fileStats[i].Useless()) { toRemoveFileIds.Add((uint)i); } } _keyValueDB.MarkAsUnknown(toRemoveFileIds); }
internal void RevertWrittingTransaction(bool nothingWrittenToTransactionLog) { if (!nothingWrittenToTransactionLog) { _writerWithTransactionLog.WriteUInt8((byte)KVCommandType.Rollback); var newRoot = _lastCommited.CloneRoot(); UpdateTransactionLogInBTreeRoot(newRoot); lock (_writeLock) { _writingTransaction = null; _lastCommited = newRoot; TryDequeWaiterForWrittingTransaction(); } } else { lock (_writeLock) { _writingTransaction = null; TryDequeWaiterForWrittingTransaction(); } } }
public void Commit() { if (BtreeRoot == null) { throw new BTDBException("Transaction already commited or disposed"); } InvalidateCurrentKey(); var currentBtreeRoot = _btreeRoot; _keyValueDB.FinishedUsingBTreeRoot(_btreeRoot); _btreeRoot = null; GC.SuppressFinalize(this); if (_preapprovedWritting) { _preapprovedWritting = false; _keyValueDB.RevertWrittingTransaction(true); } else if (_writting) { _keyValueDB.CommitWrittingTransaction(currentBtreeRoot, _temporaryCloseTransactionLog); _writting = false; } }
public KeyValueDB(IFileCollection fileCollection, ICompressionStrategy compression, uint fileSplitSize, ICompactorScheduler compactorScheduler) { if (fileCollection == null) { throw new ArgumentNullException(nameof(fileCollection)); } if (compression == null) { throw new ArgumentNullException(nameof(compression)); } if (fileSplitSize < 1024 || fileSplitSize > int.MaxValue) { throw new ArgumentOutOfRangeException(nameof(fileSplitSize), "Allowed range 1024 - 2G"); } _compactorScheduler = compactorScheduler; MaxTrLogFileSize = fileSplitSize; _compression = compression; DurableTransactions = false; _fileCollection = new FileCollectionWithFileInfos(fileCollection); _lastCommited = new BTreeRoot(0); LoadInfoAboutFiles(); _compactFunc = _compactorScheduler?.AddCompactAction(Compact); _compactorScheduler?.AdviceRunning(); }
internal IBTreeRootNode MakeWrittableTransaction(InMemoryKeyValueDBTransaction keyValueDBTransaction, IBTreeRootNode btreeRoot) { lock (_writeLock) { if (_writingTransaction != null) { throw new BTDBTransactionRetryException("Another writting transaction already running"); } if (LastCommited != btreeRoot) { throw new BTDBTransactionRetryException("Another writting transaction already finished"); } _writingTransaction = keyValueDBTransaction; return(btreeRoot.NewTransactionRoot()); } }
public InMemoryKeyValueDB() { _lastCommited = new BTreeRoot(0); }
public void Dispose() { if (_writting || _preapprovedWritting) { _keyValueDB.RevertWrittingTransaction(_preapprovedWritting); _writting = false; _preapprovedWritting = false; } if (_btreeRoot == null) return; _keyValueDB.FinishedUsingBTreeRoot(_btreeRoot); _btreeRoot = null; }
internal bool Run() { if (_keyValueDB.FileCollection.GetCount() == 0) { return(false); } _root = _keyValueDB.OldestRoot; var dontTouchGeneration = _keyValueDB.GetGeneration(_root.TrLogFileId); InitFileStats(dontTouchGeneration); CalculateFileUsefullness(); MarkTotallyUselessFilesAsUnknown(); var totalWaste = CalcTotalWaste(); _keyValueDB.Logger?.CompactionStart(totalWaste); if (IsWasteSmall(totalWaste)) { if (_keyValueDB.DistanceFromLastKeyIndex(_root) > (ulong)(_keyValueDB.MaxTrLogFileSize / 4)) { _keyValueDB.CreateIndexFile(_cancellation); } _keyValueDB.FileCollection.DeleteAllUnknownFiles(); return(false); } _cancellation.ThrowIfCancellationRequested(); uint valueFileId; var writer = _keyValueDB.StartPureValuesFile(out valueFileId); var toRemoveFileIds = new List <uint>(); _newPositionMap = new Dictionary <ulong, uint>(); while (true) { var wastefullFileId = FindMostWastefullFile(_keyValueDB.MaxTrLogFileSize - writer.GetCurrentPosition()); if (wastefullFileId == 0) { break; } MoveValuesContent(writer, wastefullFileId); _fileStats[wastefullFileId] = new FileStat(0); toRemoveFileIds.Add(wastefullFileId); } var valueFile = _keyValueDB.FileCollection.GetFile(valueFileId); valueFile.HardFlush(); valueFile.Truncate(); _keyValueDB.Logger?.CompactionCreatedPureValueFile(valueFileId, valueFile.GetSize()); var btreesCorrectInTransactionId = _keyValueDB.AtomicallyChangeBTree(root => root.RemappingIterate((uint oldFileId, uint oldOffset, out uint newFileId, out uint newOffset) => { newFileId = valueFileId; _cancellation.ThrowIfCancellationRequested(); return(_newPositionMap.TryGetValue(((ulong)oldFileId << 32) | oldOffset, out newOffset)); })); _keyValueDB.CreateIndexFile(_cancellation); if (_newPositionMap.Count == 0) { toRemoveFileIds.Add(valueFileId); } if (_keyValueDB.AreAllTransactionsBeforeFinished(btreesCorrectInTransactionId)) { _keyValueDB.MarkAsUnknown(toRemoveFileIds); } _keyValueDB.FileCollection.DeleteAllUnknownFiles(); return(true); }
void MakeWrittable() { if (_writting) return; if (_preapprovedWritting) { _writting = true; _preapprovedWritting = false; return; } if (_readOnly) { throw new BTDBTransactionRetryException("Cannot write from readOnly transaction"); } var oldBTreeRoot = BtreeRoot; _btreeRoot = _keyValueDB.MakeWrittableTransaction(this, oldBTreeRoot); _writting = true; InvalidateCurrentKey(); }