void NewWrittingTransactionUnsafe(TaskCompletionSource <IKeyValueDBTransaction> tcs) { var newTransactionRoot = LastCommited.NewTransactionRoot(); _writingTransaction = new InMemoryKeyValueDBTransaction(this, newTransactionRoot, true, false); tcs.TrySetResult(_writingTransaction); }
InMemoryKeyValueDBTransaction NewWritingTransactionUnsafe() { var newTransactionRoot = LastCommited.NewTransactionRoot(); var tr = new InMemoryKeyValueDBTransaction(this, newTransactionRoot, true, false); _writingTransaction = tr; return(tr); }
void LoadInfoAboutFiles() { long latestGeneration = -1; uint lastestTrLogFileId = 0; var keyIndexes = new List <KeyValuePair <uint, long> >(); foreach (var fileInfo in _fileCollection.FileInfos) { var trLog = fileInfo.Value as IFileTransactionLog; if (trLog != null) { if (trLog.Generation > latestGeneration) { latestGeneration = trLog.Generation; lastestTrLogFileId = fileInfo.Key; } continue; } var keyIndex = fileInfo.Value as IKeyIndex; if (keyIndex == null) { continue; } keyIndexes.Add(new KeyValuePair <uint, long>(fileInfo.Key, keyIndex.Generation)); } if (keyIndexes.Count > 1) { keyIndexes.Sort((l, r) => Comparer <long> .Default.Compare(l.Value, r.Value)); } var firstTrLogId = LinkTransactionLogFileIds(lastestTrLogFileId); var firstTrLogOffset = 0u; var hasKeyIndex = false; while (keyIndexes.Count > 0) { var keyIndex = keyIndexes[keyIndexes.Count - 1]; keyIndexes.RemoveAt(keyIndexes.Count - 1); var info = (IKeyIndex)_fileCollection.FileInfoByIdx(keyIndex.Key); _nextRoot = LastCommited.NewTransactionRoot(); if (LoadKeyIndex(keyIndex.Key, info)) { _lastCommited = _nextRoot; _nextRoot = null; firstTrLogId = info.TrLogFileId; firstTrLogOffset = info.TrLogOffset; hasKeyIndex = true; break; } _fileCollection.MakeIdxUnknown(keyIndex.Key); } while (keyIndexes.Count > 0) { var keyIndex = keyIndexes[keyIndexes.Count - 1]; keyIndexes.RemoveAt(keyIndexes.Count - 1); _fileCollection.MakeIdxUnknown(keyIndex.Key); } LoadTransactionLogs(firstTrLogId, firstTrLogOffset); if (lastestTrLogFileId != firstTrLogId && firstTrLogId != 0 || !hasKeyIndex && _fileCollection.FileInfos.Any(p => p.Value.SubDBId == 0)) { CreateIndexFile(CancellationToken.None); } new Compactor(this, CancellationToken.None).FastStartCleanUp(); _fileCollection.DeleteAllUnknownFiles(); }
// Return true if it is suitable for continuing writing new transactions bool LoadTransactionLog(uint fileId, uint logOffset) { var inlineValueBuf = new byte[MaxValueSizeInlineInMemory]; var stack = new List <NodeIdxPair>(); var collectionFile = FileCollection.GetFile(fileId); var reader = collectionFile.GetExclusiveReader(); try { if (logOffset == 0) { FileTransactionLog.SkipHeader(reader); } else { reader.SkipBlock(logOffset); } if (reader.Eof) { return(true); } var afterTemporaryEnd = false; while (!reader.Eof) { var command = (KVCommandType)reader.ReadUInt8(); if (command == 0 && afterTemporaryEnd) { collectionFile.SetSize(reader.GetCurrentPosition() - 1); return(true); } afterTemporaryEnd = false; switch (command & KVCommandType.CommandMask) { case KVCommandType.CreateOrUpdateDeprecated: case KVCommandType.CreateOrUpdate: { if (_nextRoot == null) { return(false); } var keyLen = reader.ReadVInt32(); var valueLen = reader.ReadVInt32(); var key = new byte[keyLen]; reader.ReadBlock(key); var keyBuf = ByteBuffer.NewAsync(key); if ((command & KVCommandType.FirstParamCompressed) != 0) { _compression.DecompressKey(ref keyBuf); } var ctx = new CreateOrUpdateCtx { KeyPrefix = BitArrayManipulation.EmptyByteArray, Key = keyBuf, ValueFileId = fileId, ValueOfs = (uint)reader.GetCurrentPosition(), ValueSize = (command & KVCommandType.SecondParamCompressed) != 0 ? -valueLen : valueLen }; if (valueLen <= MaxValueSizeInlineInMemory && (command & KVCommandType.SecondParamCompressed) == 0) { reader.ReadBlock(inlineValueBuf, 0, valueLen); StoreValueInlineInMemory(ByteBuffer.NewSync(inlineValueBuf, 0, valueLen), out ctx.ValueOfs, out ctx.ValueSize); ctx.ValueFileId = 0; } else { reader.SkipBlock(valueLen); } _nextRoot.CreateOrUpdate(ctx); } break; case KVCommandType.EraseOne: { if (_nextRoot == null) { return(false); } var keyLen = reader.ReadVInt32(); var key = new byte[keyLen]; reader.ReadBlock(key); var keyBuf = ByteBuffer.NewAsync(key); if ((command & KVCommandType.FirstParamCompressed) != 0) { _compression.DecompressKey(ref keyBuf); } long keyIndex; var findResult = _nextRoot.FindKey(stack, out keyIndex, BitArrayManipulation.EmptyByteArray, keyBuf); if (findResult == FindResult.Exact) { _nextRoot.EraseRange(keyIndex, keyIndex); } } break; case KVCommandType.EraseRange: { if (_nextRoot == null) { return(false); } var keyLen1 = reader.ReadVInt32(); var keyLen2 = reader.ReadVInt32(); var key = new byte[keyLen1]; reader.ReadBlock(key); var keyBuf = ByteBuffer.NewAsync(key); if ((command & KVCommandType.FirstParamCompressed) != 0) { _compression.DecompressKey(ref keyBuf); } long keyIndex1; var findResult = _nextRoot.FindKey(stack, out keyIndex1, BitArrayManipulation.EmptyByteArray, keyBuf); if (findResult == FindResult.Previous) { keyIndex1++; } key = new byte[keyLen2]; reader.ReadBlock(key); keyBuf = ByteBuffer.NewAsync(key); if ((command & KVCommandType.SecondParamCompressed) != 0) { _compression.DecompressKey(ref keyBuf); } long keyIndex2; findResult = _nextRoot.FindKey(stack, out keyIndex2, BitArrayManipulation.EmptyByteArray, keyBuf); if (findResult == FindResult.Next) { keyIndex2--; } _nextRoot.EraseRange(keyIndex1, keyIndex2); } break; case KVCommandType.TransactionStart: if (!reader.CheckMagic(MagicStartOfTransaction)) { return(false); } _nextRoot = LastCommited.NewTransactionRoot(); break; case KVCommandType.CommitWithDeltaUlong: unchecked // overflow is expected in case commitUlong is decreasing but that should be rare { _nextRoot.CommitUlong += reader.ReadVUInt64(); } goto case KVCommandType.Commit; case KVCommandType.Commit: _nextRoot.TrLogFileId = fileId; _nextRoot.TrLogOffset = (uint)reader.GetCurrentPosition(); _lastCommited = _nextRoot; _nextRoot = null; break; case KVCommandType.Rollback: _nextRoot = null; break; case KVCommandType.EndOfFile: return(false); case KVCommandType.TemporaryEndOfFile: _lastCommited.TrLogFileId = fileId; _lastCommited.TrLogOffset = (uint)reader.GetCurrentPosition(); afterTemporaryEnd = true; break; default: _nextRoot = null; return(false); } } return(afterTemporaryEnd); } catch (EndOfStreamException) { _nextRoot = null; return(false); } }