internal void WriteStartTransaction() { if (_fileIdWithTransactionLog == 0) { WriteStartOfNewTransactionLogFile(); } else { if (_writerWithTransactionLog == null) { _fileWithTransactionLog = FileCollection.GetFile(_fileIdWithTransactionLog); _writerWithTransactionLog = _fileWithTransactionLog.GetAppenderWriter(); } if (_writerWithTransactionLog.GetCurrentPosition() > MaxTrLogFileSize) { WriteStartOfNewTransactionLogFile(); } } _writerWithTransactionLog.WriteUInt8((byte)KVCommandType.TransactionStart); _writerWithTransactionLog.WriteByteArrayRaw(MagicStartOfTransaction); }
public ByteBuffer ReadValue(uint valueFileId, uint valueOfs, int valueSize) { if (valueSize == 0) { return(ByteBuffer.NewEmpty()); } if (valueFileId == 0) { var len = valueSize >> 24; var buf = new byte[len]; switch (len) { case 7: buf[6] = (byte)(valueOfs >> 24); goto case 6; case 6: buf[5] = (byte)(valueOfs >> 16); goto case 5; case 5: buf[4] = (byte)(valueOfs >> 8); goto case 4; case 4: buf[3] = (byte)valueOfs; goto case 3; case 3: buf[2] = (byte)valueSize; goto case 2; case 2: buf[1] = (byte)(valueSize >> 8); goto case 1; case 1: buf[0] = (byte)(valueSize >> 16); break; default: throw new BTDBException("Corrupted DB"); } return(ByteBuffer.NewAsync(buf)); } var compressed = false; if (valueSize < 0) { compressed = true; valueSize = -valueSize; } var result = ByteBuffer.NewAsync(new byte[valueSize]); var file = FileCollection.GetFile(valueFileId); file.RandomRead(result.Buffer, 0, valueSize, valueOfs, false); if (compressed) { _compression.DecompressValue(ref result); } return(result); }
// 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); } }
bool LoadKeyIndex(uint fileId, IKeyIndex info) { try { var reader = FileCollection.GetFile(fileId).GetExclusiveReader(); FileKeyIndex.SkipHeader(reader); var keyCount = info.KeyValueCount; _nextRoot.TrLogFileId = info.TrLogFileId; _nextRoot.TrLogOffset = info.TrLogOffset; _nextRoot.CommitUlong = info.CommitUlong; if (info.Compression == KeyIndexCompression.Old) { _nextRoot.BuildTree(keyCount, () => { var keyLength = reader.ReadVInt32(); var key = ByteBuffer.NewAsync(new byte[Math.Abs(keyLength)]); reader.ReadBlock(key); if (keyLength < 0) { _compression.DecompressKey(ref key); } return(new BTreeLeafMember { Key = key.ToByteArray(), ValueFileId = reader.ReadVUInt32(), ValueOfs = reader.ReadVUInt32(), ValueSize = reader.ReadVInt32() }); }); } else { if (info.Compression != KeyIndexCompression.None) { return(false); } var prevKey = ByteBuffer.NewEmpty(); _nextRoot.BuildTree(keyCount, () => { var prefixLen = (int)reader.ReadVUInt32(); var keyLengthWithoutPrefix = (int)reader.ReadVUInt32(); var key = ByteBuffer.NewAsync(new byte[prefixLen + keyLengthWithoutPrefix]); Array.Copy(prevKey.Buffer, prevKey.Offset, key.Buffer, key.Offset, prefixLen); reader.ReadBlock(key.SubBuffer(prefixLen)); prevKey = key; return(new BTreeLeafMember { Key = key.ToByteArray(), ValueFileId = reader.ReadVUInt32(), ValueOfs = reader.ReadVUInt32(), ValueSize = reader.ReadVInt32() }); }); } if (reader.Eof) { return(true); } if (reader.ReadInt32() == EndOfIndexFileMarker) { return(true); } return(false); } catch (Exception) { return(false); } }