internal KeyValueDBTransaction(KeyValueDB owner, KeyValueDB.ReadTrLink readLink) { _owner = owner; _readLink = readLink; _currentKeySector = null; _currentKeyIndexInLeaf = -1; _currentKeyIndex = -1; _prefix = EmptyByteArray; _prefixKeyStart = 0; _prefixKeyCount = (long)_readLink.KeyValuePairCount; }
Sector PopCurrentKeyParent() { var count = _currentKeySectorParents.Count; if (count == 0) return null; var parent = _currentKeySectorParents[count - 1]; _currentKeySectorParents.RemoveAt(count - 1); _currentKeySector = parent; return parent; }
void ErasePartially(ref Sector sector, long firstKeyIndex, long lastKeyIndex) { if (sector.Type == SectorType.BTreeParent) { ErasePartiallyParent(ref sector, firstKeyIndex, lastKeyIndex); } else { ErasePartiallyChild(ref sector, firstKeyIndex, lastKeyIndex); } }
void DeleteContentSector(SectorPtr sectorPtr, long len, Sector parent) { var sector = GetOrReadDataSector(sectorPtr, len, parent); if (sector.Type == SectorType.DataChild) { _owner.DeallocateSector(sector); return; } int downPtrCount; long bytesInDownLevel = KeyValueDB.GetBytesInDownLevel(len, out downPtrCount); for (int i = 0; i < downPtrCount; i++) { var downSectorPtr = SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize); DeleteContentSector(downSectorPtr, Math.Min(len, bytesInDownLevel), sector); len -= bytesInDownLevel; } _owner.DeallocateSector(sector); }
void CreateContentSector(byte[] buf, int ofs, int len, byte[] buf2, int ofs2, int len2, Sector parent, int ofsInParent) { if (len + len2 <= KeyValueDB.MaxLeafDataSectorSize) { var newLeafSector = _owner.NewSector(); newLeafSector.Type = SectorType.DataChild; newLeafSector.SetLengthWithRound(len + len2); newLeafSector.Parent = parent; if (len > 0) Array.Copy(buf, ofs, newLeafSector.Data, 0, len); if (len2 > 0) Array.Copy(buf2, ofs2, newLeafSector.Data, len, len2); _owner.PublishSector(newLeafSector, false); Debug.Assert(parent.Dirty); SectorPtr.Pack(parent.Data, ofsInParent, newLeafSector.ToSectorPtr()); return; } int downPtrCount; var bytesInDownLevel = (int)KeyValueDB.GetBytesInDownLevel(len + len2, out downPtrCount); var newSector = _owner.NewSector(); newSector.Type = SectorType.DataParent; newSector.SetLengthWithRound(downPtrCount * KeyValueDB.PtrDownSize); newSector.Parent = parent; _owner.PublishSector(newSector, false); Debug.Assert(parent.Dirty); SectorPtr.Pack(parent.Data, ofsInParent, newSector.ToSectorPtr()); for (int i = 0; i < downPtrCount; i++) { var usedLen = Math.Min(len, bytesInDownLevel); var usedLen2 = Math.Min(len2, bytesInDownLevel - usedLen); CreateContentSector(buf, ofs, usedLen, buf2, ofs2, usedLen2, newSector, i * KeyValueDB.PtrDownSize); _owner.TruncateSectorCache(true, newSector.Position); ofs += usedLen; ofs2 += usedLen2; len -= usedLen; len2 -= usedLen2; } }
void CreateBTreeParentFromTwoLeafs(Sector leftSector, Sector rightSector) { var iter = new BTreeChildIterator(rightSector.Data); iter.MoveFirst(); int keyLenInSector = iter.KeyLenInline + (iter.HasKeySectorPtr ? KeyValueDB.PtrDownSize : 0); if (iter.HasKeySectorPtr) { ForceKeyFlush(iter.KeySectorPtr, iter.KeyLen - iter.KeyLenInline, rightSector); } CreateBTreeParentFromTwoChildren(leftSector, rightSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); }
void AddToBTreeParent(Sector leftSector, Sector rightSector, byte[] middleKeyData, int middleKeyLen, int middleKeyOfs, int middleKeyLenInSector) { var parentSector = leftSector.Parent; var iter = new BTreeParentIterator(parentSector.Data); int additionalLengthNeeded = BTreeParentIterator.HeaderForEntry + BTreeParentIterator.CalcEntrySize(middleKeyLen); int leftIndexInParent = iter.FindChildByPos(leftSector.Position); bool splitting = true; if (!KeyValueDB.ShouldSplitBTreeParent(iter.TotalLength, additionalLengthNeeded, iter.Count + 1)) { parentSector = _owner.ResizeSectorWithUpdatePositionNoWriteTruncate( parentSector, iter.TotalLength + additionalLengthNeeded, parentSector.Parent, _currentKeySectorParents); splitting = false; } var mergedData = new byte[iter.TotalLength + additionalLengthNeeded]; BTreeParentIterator.SetCountToSectorData(mergedData, iter.Count + 1); int ofs; int splitOfs = iter.OffsetOfIndex(leftIndexInParent); if (leftIndexInParent == 0) { SectorPtr.Pack(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, leftSector.ToSectorPtr()); PackUnpack.PackUInt64LE(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset + KeyValueDB.PtrDownSize, CalcKeysInSector(leftSector)); ofs = BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry * (iter.Count + 1); } else { Array.Copy(iter.Data, BTreeParentIterator.FirstChildSectorPtrOffset, mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8); ofs = BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry * (iter.Count + 1); int splitOfsPrev = iter.OffsetOfIndex(leftIndexInParent - 1); Array.Copy(iter.Data, iter.FirstOffset, mergedData, ofs, splitOfsPrev - iter.FirstOffset); ofs += splitOfsPrev - iter.FirstOffset; Array.Copy(iter.Data, splitOfsPrev, mergedData, ofs, 4 + KeyValueDB.PtrDownSize); ofs += 4 + KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(mergedData, ofs, CalcKeysInSector(leftSector)); ofs += 8; splitOfsPrev += 4 + KeyValueDB.PtrDownSize + 8; Array.Copy(iter.Data, splitOfsPrev, mergedData, ofs, splitOfs - splitOfsPrev); ofs += splitOfs - splitOfsPrev; } PackUnpack.PackInt32LE(mergedData, ofs, middleKeyLen); ofs += 4; SectorPtr.Pack(mergedData, ofs, rightSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(mergedData, ofs, CalcKeysInSector(rightSector)); ofs += 8; Array.Copy(middleKeyData, middleKeyOfs, mergedData, ofs, middleKeyLenInSector); ofs += middleKeyLenInSector; Array.Copy(iter.Data, splitOfs, mergedData, ofs, iter.TotalLength - splitOfs); BTreeParentIterator.RecalculateHeader(mergedData, iter.Count + 1); if (!splitting) { Array.Copy(mergedData, parentSector.Data, mergedData.Length); leftSector.Parent = parentSector; rightSector.Parent = parentSector; IncrementChildCountInBTreeParents(parentSector); _owner.FixChildrenParentPointers(parentSector); } else { iter = new BTreeParentIterator(mergedData); int middleoffset = mergedData.Length / 2; iter.MoveFirst(); int splitIndex = 0; int currentPos = iter.FirstOffset; while (currentPos < middleoffset) { currentPos += iter.CurrentEntrySize; splitIndex++; iter.MoveNext(); } Sector leftParentSector = null; Sector rightParentSector = null; try { rightParentSector = _owner.NewSector(); rightParentSector.Type = SectorType.BTreeParent; var rightCount = iter.Count - splitIndex - 1; var rightFirstOffset = BTreeParentIterator.HeaderSize + rightCount * BTreeParentIterator.HeaderForEntry; rightParentSector.SetLengthWithRound(rightFirstOffset + mergedData.Length - iter.NextEntryOffset); BTreeParentIterator.SetCountToSectorData(rightParentSector.Data, rightCount); rightParentSector.Parent = parentSector.Parent; var leftFirstOffset = BTreeParentIterator.HeaderSize + splitIndex * BTreeParentIterator.HeaderForEntry; leftParentSector = _owner.ResizeSectorWithUpdatePosition(parentSector, leftFirstOffset + currentPos - iter.FirstOffset, parentSector.Parent, _currentKeySectorParents); BTreeParentIterator.SetCountToSectorData(leftParentSector.Data, splitIndex); leftSector.Parent = leftParentSector; rightSector.Parent = leftParentSector; Array.Copy(mergedData, BTreeParentIterator.FirstChildSectorPtrOffset, leftParentSector.Data, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8 + BTreeParentIterator.HeaderForEntry * splitIndex); Array.Copy(mergedData, iter.FirstOffset, leftParentSector.Data, leftFirstOffset, currentPos - iter.FirstOffset); Array.Copy(mergedData, iter.ChildSectorPtrOffset, rightParentSector.Data, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8); Array.Copy(mergedData, iter.NextEntryOffset, rightParentSector.Data, rightFirstOffset, iter.TotalLength - iter.NextEntryOffset); BTreeParentIterator.RecalculateHeader(rightParentSector.Data, rightCount); _owner.FixChildrenParentPointers(leftParentSector); _owner.PublishSector(rightParentSector, true); Interlocked.Increment(ref leftParentSector.ChildrenInCache); Interlocked.Increment(ref rightParentSector.ChildrenInCache); try { _owner.TruncateSectorCache(true, 0); int keyLenInSector = iter.KeyLenInline + (iter.HasKeySectorPtr ? KeyValueDB.PtrDownSize : 0); if (leftParentSector.Parent == null) { CreateBTreeParentFromTwoChildren(leftParentSector, rightParentSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); } else { AddToBTreeParent(leftParentSector, rightParentSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); } } finally { Interlocked.Decrement(ref leftParentSector.ChildrenInCache); Interlocked.Decrement(ref rightParentSector.ChildrenInCache); } } finally { if (leftSector.Parent == rightParentSector) { for (int i = 0; i < _currentKeySectorParents.Count; i++) { if (_currentKeySectorParents[i] == leftParentSector) { _currentKeySectorParents[i] = rightParentSector; break; } } } } } }
static ulong CalcKeysInSector(Sector sector) { if (sector.Type == SectorType.BTreeChild) { return BTreeChildIterator.CountFromSectorData(sector.Data); } Debug.Assert(sector.Type == SectorType.BTreeParent); var iter = new BTreeParentIterator(sector.Data); var res = (ulong)iter.FirstChildKeyCount; if (iter.Count != 0) { iter.MoveFirst(); do { res += (ulong)iter.ChildKeyCount; } while (iter.MoveNext()); } return res; }
void SetBTreeChildKeyDataJustLengths(Sector inSector, int keyLen, int valueLen, int sectorDataOfs) { byte[] sectorData = inSector.Data; int realKeyLen = _prefix.Length + keyLen; int realValueLen = valueLen < 0 ? 0 : valueLen; PackUnpack.PackVUInt(sectorData, ref sectorDataOfs, (uint)realKeyLen); PackUnpack.PackVUInt(sectorData, ref sectorDataOfs, (uint)realValueLen); }
void SetBTreeChildKeyData(Sector inSector, byte[] keyBuf, int keyOfs, int keyLen, byte[] valueBuf, int valueOfs, int valueLen, int sectorDataOfs) { byte[] sectorData = inSector.Data; int realKeyLen = _prefix.Length + keyLen; int realValueLen = valueLen < 0 ? 0 : valueLen; int keyLenInline = BTreeChildIterator.CalcKeyLenInline(realKeyLen); int valueLenInline = BTreeChildIterator.CalcValueLenInline(realValueLen); PackUnpack.PackVUInt(sectorData, ref sectorDataOfs, (uint)realKeyLen); PackUnpack.PackVUInt(sectorData, ref sectorDataOfs, (uint)realValueLen); var usedPrefixLen = Math.Min(_prefix.Length, keyLenInline); Array.Copy(_prefix, 0, sectorData, sectorDataOfs, usedPrefixLen); Array.Copy(keyBuf, keyOfs, sectorData, sectorDataOfs + _prefix.Length, keyLenInline - usedPrefixLen); sectorDataOfs += keyLenInline; if (realKeyLen > BTreeChildIterator.MaxKeyLenInline) { CreateContentSector(_prefix, keyLenInline, _prefix.Length - usedPrefixLen, keyBuf, keyOfs + keyLenInline - usedPrefixLen, keyLen - keyLenInline + usedPrefixLen, inSector, sectorDataOfs); sectorDataOfs += KeyValueDB.PtrDownSize; } if (valueLen <= 0) return; Array.Copy(valueBuf, valueOfs + realValueLen - valueLenInline, sectorData, sectorDataOfs, valueLenInline); sectorDataOfs += valueLenInline; if (realValueLen > BTreeChildIterator.MaxValueLenInline) { CreateContentSector(valueBuf, valueOfs, realValueLen - valueLenInline, inSector, sectorDataOfs); } }
int SectorDataCompare(int startOfs, byte[] buf, int ofs, int len, SectorPtr sectorPtr, int dataLen, Sector parent) { var sector = GetOrReadDataSector(sectorPtr, dataLen, parent); if (sector.Type == SectorType.DataChild) { int dataOfs = 0; if (startOfs < _prefix.Length) { int compareLen = Math.Min(_prefix.Length - startOfs, sector.Length); int res = BitArrayManipulation.CompareByteArray(_prefix, startOfs, compareLen, sector.Data, dataOfs, compareLen); if (res != 0) return res; startOfs += compareLen; if (startOfs < _prefix.Length) return 0; dataOfs += compareLen; } if (ofs == -1) return 1; startOfs -= _prefix.Length; return BitArrayManipulation.CompareByteArray(buf, ofs + startOfs, Math.Min(len - startOfs, sector.Length - dataOfs), sector.Data, dataOfs, sector.Length - dataOfs); } int downPtrCount; var bytesInDownLevel = (int)KeyValueDB.GetBytesInDownLevel(dataLen, out downPtrCount); int i; SectorPtr downSectorPtr; for (i = 0; i < downPtrCount - 1; i++) { downSectorPtr = SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize); int res = SectorDataCompare(startOfs, buf, ofs, len, downSectorPtr, Math.Min(dataLen, bytesInDownLevel), sector); if (res != 0) return res; startOfs += bytesInDownLevel; dataLen -= bytesInDownLevel; } downSectorPtr = SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize); return SectorDataCompare(startOfs, buf, ofs, len, downSectorPtr, dataLen, sector); }
void ResizeContentSectorChild(SectorPtr oldSectorPtr, int oldLength, int newLength, Sector parentSector, int ofsInParent, byte[] buf, int bufOfs) { var sector = _owner.GetOrReadSector(oldSectorPtr, true, SectorTypeInit.DataChild, parentSector); byte[] oldData = sector.Data; sector = _owner.ResizeSectorNoUpdatePosition(sector, newLength, parentSector, null); if (buf == null) { Array.Copy(oldData, 0, sector.Data, 0, Math.Min(oldLength, newLength)); } else { Array.Copy(buf, bufOfs, sector.Data, 0, newLength); } SectorPtr.Pack(parentSector.Data, ofsInParent, sector.ToSectorPtr()); }
void ResizeContentSector(SectorPtr oldSectorPtr, long oldSize, Sector parentSector, int ofsInParent, long newSize, byte[] buf, int bufOfs) { Debug.Assert(oldSize != 0 && newSize != 0); if (oldSize == newSize) { if (buf != null) { RecursiveWriteValue(oldSectorPtr, newSize, 0, (int)newSize, buf, bufOfs, parentSector, ofsInParent); return; } SectorPtr.Pack(parentSector.Data, ofsInParent, oldSectorPtr); return; } int oldDownPtrCount; var oldBytesInDownLevel = KeyValueDB.GetBytesInDownLevel(oldSize, out oldDownPtrCount); int newDownPtrCount; var newBytesInDownLevel = KeyValueDB.GetBytesInDownLevel(newSize, out newDownPtrCount); Sector sector; if (oldBytesInDownLevel < newBytesInDownLevel) { sector = _owner.NewSector(); sector.SetLengthWithRound(newDownPtrCount * KeyValueDB.PtrDownSize); sector.Parent = parentSector; sector.Type = SectorType.DataParent; SectorPtr.Pack(sector.Data, 0, oldSectorPtr); _owner.PublishSector(sector, true); SectorPtr.Pack(parentSector.Data, ofsInParent, sector.ToSectorPtr()); Interlocked.Increment(ref sector.ChildrenInCache); try { _owner.TruncateSectorCache(true, oldSectorPtr.Ptr); } finally { Interlocked.Decrement(ref sector.ChildrenInCache); } ResizeContentSector(oldSectorPtr, oldSize, sector, 0, newBytesInDownLevel, buf, bufOfs); for (int i = 1; i < newDownPtrCount; i++) { long downLevelSize = Math.Min(newSize - i * newBytesInDownLevel, newBytesInDownLevel); if (buf != null) CreateContentSector(buf, (int)(bufOfs + i * newBytesInDownLevel), (int)downLevelSize, sector, i * KeyValueDB.PtrDownSize); else CreateContentSector(downLevelSize, sector, i * KeyValueDB.PtrDownSize); } return; } if (oldBytesInDownLevel > newBytesInDownLevel) { sector = _owner.GetOrReadSector(oldSectorPtr, true, SectorTypeInit.DataParent, parentSector); for (int i = 1; i < oldDownPtrCount; i++) { long downLevelSize = Math.Min(oldSize - i * oldBytesInDownLevel, oldBytesInDownLevel); DeleteContentSector(SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize), downLevelSize, sector); } _owner.DeallocateSector(sector); ResizeContentSector(SectorPtr.Unpack(sector.Data, 0), oldBytesInDownLevel, parentSector, ofsInParent, newSize, buf, bufOfs); return; } if (oldBytesInDownLevel == 1) { ResizeContentSectorChild(oldSectorPtr, oldDownPtrCount, newDownPtrCount, parentSector, ofsInParent, buf, bufOfs); return; } sector = _owner.GetOrReadSector(oldSectorPtr, true, SectorTypeInit.DataParent, parentSector); SectorPtr lastSectorPtr; long lastOffset; for (int i = newDownPtrCount; i < oldDownPtrCount; i++) { lastOffset = i * oldBytesInDownLevel; lastSectorPtr = SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize); DeleteContentSector(lastSectorPtr, Math.Min(oldSize - lastOffset, oldBytesInDownLevel), sector); } var lastCommonPtrCount = Math.Min(oldDownPtrCount, newDownPtrCount) - 1; byte[] oldData = sector.Data; sector = _owner.ResizeSectorNoUpdatePosition(sector, newDownPtrCount * KeyValueDB.PtrDownSize, parentSector, null); var commonLength = (lastCommonPtrCount + 1) * KeyValueDB.PtrDownSize; Array.Copy(oldData, 0, sector.Data, 0, commonLength); Array.Clear(sector.Data, commonLength, sector.Data.Length - commonLength); SectorPtr.Pack(parentSector.Data, ofsInParent, sector.ToSectorPtr()); _owner.FixChildrenParentPointers(sector); if (buf != null) { for (int i = 0; i < lastCommonPtrCount; i++) { lastSectorPtr = SectorPtr.Unpack(sector.Data, i * KeyValueDB.PtrDownSize); lastOffset = i * newBytesInDownLevel; RecursiveWriteValue(lastSectorPtr, newBytesInDownLevel, 0, (int)newBytesInDownLevel, buf, (int)(bufOfs + lastOffset), sector, i * KeyValueDB.PtrDownSize); } } lastSectorPtr = SectorPtr.Unpack(sector.Data, lastCommonPtrCount * KeyValueDB.PtrDownSize); lastOffset = lastCommonPtrCount * newBytesInDownLevel; ResizeContentSector(lastSectorPtr, Math.Min(oldSize - lastOffset, oldBytesInDownLevel), sector, lastCommonPtrCount * KeyValueDB.PtrDownSize, Math.Min(newSize - lastOffset, newBytesInDownLevel), buf, (int)(bufOfs + lastOffset)); for (int i = oldDownPtrCount; i < newDownPtrCount; i++) { lastOffset = i * newBytesInDownLevel; if (buf != null) CreateContentSector(buf, (int)(bufOfs + lastOffset), (int)Math.Min(newSize - lastOffset, newBytesInDownLevel), sector, i * KeyValueDB.PtrDownSize); else CreateContentSector(Math.Min(newSize - lastOffset, newBytesInDownLevel), sector, i * KeyValueDB.PtrDownSize); } }
void RecursiveWriteValue(SectorPtr sectorPtr, long valueLen, long ofs, int len, byte[] buf, int bufOfs, Sector newParent, int ofsInParent) { if (ofs < 0) throw new ArgumentOutOfRangeException("ofs"); if (ofs + len > valueLen) throw new ArgumentOutOfRangeException("ofs"); var dataSector = GetOrReadDataSector(sectorPtr, valueLen, newParent); if (dataSector.Type == SectorType.DataChild) { Debug.Assert(valueLen <= dataSector.Length); dataSector = _owner.ResizeSectorNoUpdatePosition(dataSector, dataSector.Length, newParent, null); // DirtizeSector but without update position if (buf != null) { Array.Copy(buf, bufOfs, dataSector.Data, (int)ofs, len); } else { Array.Clear(dataSector.Data, (int)ofs, len); } SectorPtr.Pack(newParent.Data, ofsInParent, dataSector.ToSectorPtr()); return; } dataSector = _owner.DirtizeSector(dataSector, newParent, null); SectorPtr.Pack(newParent.Data, ofsInParent, dataSector.ToSectorPtr()); int downPtrCount; long bytesInDownLevel = KeyValueDB.GetBytesInDownLevel(valueLen, out downPtrCount); var i = (int)(ofs / bytesInDownLevel); while (i < downPtrCount) { long newofs = ofs - i * bytesInDownLevel; if (newofs + len <= 0) break; long downValueLen; if (i < downPtrCount - 1) { downValueLen = bytesInDownLevel; } else { downValueLen = valueLen % bytesInDownLevel; if (downValueLen == 0) downValueLen = bytesInDownLevel; } SectorPtr downSectorPtr = SectorPtr.Unpack(dataSector.Data, i * KeyValueDB.PtrDownSize); int newBufOfs = bufOfs; int newlen = len; if (newofs < 0) { newlen += (int)newofs; newBufOfs -= (int)newofs; newofs = 0; } if (downValueLen - newofs < newlen) { newlen = (int)(downValueLen - newofs); } RecursiveWriteValue(downSectorPtr, downValueLen, newofs, newlen, buf, newBufOfs, dataSector, i * KeyValueDB.PtrDownSize); i++; } }
void RecursiveReadOverflown(long ofs, SectorPtr dataSectorPtr, Sector parentOfSector, long dataLen, byte[] buf, ref int bufOfs, ref int len) { Sector dataSector = GetOrReadDataSector(dataSectorPtr, dataLen, parentOfSector); if (dataSector.Type == SectorType.DataChild) { var copyLen = Math.Min(len, (int)(dataSector.Length - ofs)); Array.Copy(dataSector.Data, (int)ofs, buf, bufOfs, copyLen); len -= copyLen; bufOfs += copyLen; return; } int downPtrCount; long bytesInDownLevel = KeyValueDB.GetBytesInDownLevel(dataLen, out downPtrCount); var childIndex = (int)(ofs / bytesInDownLevel); ofs = ofs % bytesInDownLevel; while (childIndex < downPtrCount && len > 0) { long childDataLen; if (childIndex < downPtrCount - 1) { childDataLen = bytesInDownLevel; } else { childDataLen = dataLen % bytesInDownLevel; if (childDataLen == 0) childDataLen = bytesInDownLevel; } dataSectorPtr = SectorPtr.Unpack(dataSector.Data, childIndex * KeyValueDB.PtrDownSize); RecursiveReadOverflown(ofs, dataSectorPtr, dataSector, childDataLen, buf, ref bufOfs, ref len); ofs = 0; childIndex++; } }
public void SetValue(byte[] buf, int bufOfs, int len) { if (len < 0) throw new ArgumentOutOfRangeException("len"); if (_currentKeyIndexInLeaf < 0) throw new BTDBException("Current Key is invalid"); var iter = new BTreeChildIterator(_currentKeySector.Data); iter.MoveTo(_currentKeyIndexInLeaf); long oldSize = iter.ValueLen; if (oldSize == len) { WriteValue(0, len, buf, bufOfs); return; } UpgradeToWriteTransaction(); int oldInlineSize = BTreeChildIterator.CalcValueLenInline(oldSize); int newInlineSize = BTreeChildIterator.CalcValueLenInline(len); long oldDeepSize = oldSize - oldInlineSize; int newDeepSize = len - newInlineSize; if (oldDeepSize > 0 && newDeepSize == 0) DeleteContentSector(iter.ValueSectorPtr, oldDeepSize, _currentKeySector); _currentKeySector = _owner.ResizeSectorWithUpdatePosition(_currentKeySector, iter.TotalLength - iter.CurrentEntrySize + BTreeChildIterator.CalcEntrySize(iter.KeyLen, len), _currentKeySector.Parent, _currentKeySectorParents); iter.ResizeValue(_currentKeySector.Data, len); _owner.FixChildrenParentPointers(_currentKeySector); Array.Copy(buf, bufOfs + len - newInlineSize, _currentKeySector.Data, iter.ValueOffset, newInlineSize); if (oldDeepSize == 0) { if (newDeepSize != 0) { CreateContentSector(buf, bufOfs, newDeepSize, _currentKeySector, iter.ValueSectorPtrOffset); } } else if (newDeepSize != 0) { ResizeContentSector(iter.ValueSectorPtr, oldDeepSize, _currentKeySector, iter.ValueSectorPtrOffset, newDeepSize, buf, bufOfs); } }
public void SetValueSize(long newSize) { if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); if (_currentKeyIndexInLeaf < 0) throw new BTDBException("Current Key is invalid"); var iter = new BTreeChildIterator(_currentKeySector.Data); iter.MoveTo(_currentKeyIndexInLeaf); long oldSize = iter.ValueLen; if (oldSize == newSize) return; UpgradeToWriteTransaction(); int oldInlineSize = BTreeChildIterator.CalcValueLenInline(oldSize); int newInlineSize = BTreeChildIterator.CalcValueLenInline(newSize); var newEndContent = new byte[newInlineSize]; byte[] oldEndContent = null; long newEndContentOfs = newSize - newEndContent.Length; if (oldSize < newSize) { oldEndContent = new byte[oldInlineSize]; ReadValue(oldSize - oldInlineSize, oldInlineSize, oldEndContent, 0); } else { ReadValue(newEndContentOfs, (int)Math.Min(newEndContent.Length, oldSize - newEndContentOfs), newEndContent, 0); } long oldDeepSize = oldSize - oldInlineSize; long newDeepSize = newSize - newInlineSize; if (oldDeepSize > 0 && newDeepSize == 0) DeleteContentSector(iter.ValueSectorPtr, oldDeepSize, _currentKeySector); _currentKeySector = _owner.ResizeSectorWithUpdatePosition(_currentKeySector, iter.TotalLength - iter.CurrentEntrySize + BTreeChildIterator.CalcEntrySize(iter.KeyLen, newSize), _currentKeySector.Parent, _currentKeySectorParents); iter.ResizeValue(_currentKeySector.Data, newSize); _owner.FixChildrenParentPointers(_currentKeySector); if (oldDeepSize != newDeepSize) { if (oldDeepSize == 0) { CreateContentSector(newDeepSize, _currentKeySector, iter.ValueSectorPtrOffset); } else if (newDeepSize != 0) { ResizeContentSector(iter.ValueSectorPtr, oldDeepSize, _currentKeySector, iter.ValueSectorPtrOffset, newDeepSize, null, 0); } } if (newEndContent.Length > 0) InternalWriteValue(newEndContentOfs, newEndContent.Length, newEndContent, 0); if (oldEndContent != null && oldEndContent.Length > 0) InternalWriteValue(oldSize - oldInlineSize, oldInlineSize, oldEndContent, 0); }
void SimplifyBTree(ref Sector sector, int mergeAroundIndex) { var iter = new BTreeParentIterator(sector.Data); if (iter.Count == 0 || mergeAroundIndex > iter.Count) return; var lenCurrent = ApproximateLengthOfBTreeChild(iter.GetChildSectorPtr(mergeAroundIndex)); var lenPrevious = -1; if (mergeAroundIndex > 0) lenPrevious = ApproximateLengthOfBTreeChild(iter.GetChildSectorPtr(mergeAroundIndex - 1)); var lenNext = -1; if (mergeAroundIndex < iter.Count) lenNext = ApproximateLengthOfBTreeChild(iter.GetChildSectorPtr(mergeAroundIndex + 1)); ShouldMergeResult result = KeyValueDB.ShouldMergeBTreeParent(lenPrevious, lenCurrent, lenNext); if (result == ShouldMergeResult.NoMerge) return; if (result == ShouldMergeResult.MergeWithPrevious) mergeAroundIndex--; long mergedPairs; var leftSectorPtr = iter.GetChildSectorPtrWithKeyCount(mergeAroundIndex, out mergedPairs); Sector mergedSector; var leftSector = GetBTreeSector(leftSectorPtr, sector); long tempPairs; var rightSectorPtr = iter.GetChildSectorPtrWithKeyCount(mergeAroundIndex + 1, out tempPairs); mergedPairs += tempPairs; var rightSector = GetBTreeSector(rightSectorPtr, sector); Debug.Assert(leftSector.Type == rightSector.Type); iter.MoveTo(mergeAroundIndex); if (leftSector.Type == SectorType.BTreeChild) { var leftIter = new BTreeChildIterator(leftSector.Data); var rightIter = new BTreeChildIterator(rightSector.Data); if (!KeyValueDB.ShouldMerge2BTreeChild(leftIter.Count, leftIter.TotalLength, rightIter.Count, rightIter.TotalLength)) return; mergedSector = _owner.NewSector(); mergedSector.Type = SectorType.BTreeChild; mergedSector.Parent = sector; mergedSector.SetLengthWithRound(leftIter.TotalLength + rightIter.TotalLength - BTreeChildIterator.HeaderSize); var mergedCount = leftIter.Count + rightIter.Count; BTreeChildIterator.SetCountToSectorData(mergedSector.Data, mergedCount); var ofs = BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * mergedCount; Array.Copy(leftIter.Data, leftIter.FirstOffset, mergedSector.Data, ofs, leftIter.TotalLength - leftIter.FirstOffset); ofs += leftIter.TotalLength - leftIter.FirstOffset; Array.Copy(rightIter.Data, rightIter.FirstOffset, mergedSector.Data, ofs, rightIter.TotalLength - rightIter.FirstOffset); BTreeChildIterator.RecalculateHeader(mergedSector.Data, mergedCount); } else { var keyStorageLen = 4 + iter.KeyLenInline + (iter.HasKeySectorPtr ? KeyValueDB.PtrDownSize : 0); var leftIter = new BTreeParentIterator(leftSector.Data); var rightIter = new BTreeParentIterator(rightSector.Data); if (!KeyValueDB.ShouldMerge2BTreeParent(leftIter.Count, leftIter.TotalLength, rightIter.Count, rightIter.TotalLength, keyStorageLen)) return; mergedSector = _owner.NewSector(); mergedSector.Type = SectorType.BTreeParent; mergedSector.Parent = sector; mergedSector.SetLengthWithRound(leftIter.TotalLength + rightIter.TotalLength + keyStorageLen); var mergedCount = leftIter.Count + rightIter.Count + 1; BTreeParentIterator.SetCountToSectorData(mergedSector.Data, mergedCount); Array.Copy(leftIter.Data, BTreeParentIterator.FirstChildSectorPtrOffset, mergedSector.Data, BTreeParentIterator.FirstChildSectorPtrOffset, KeyValueDB.PtrDownSize + 8); var ofs = BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry * mergedCount; Array.Copy(leftIter.Data, leftIter.FirstOffset, mergedSector.Data, ofs, leftIter.TotalLength - leftIter.FirstOffset); ofs += leftIter.TotalLength - leftIter.FirstOffset; PackUnpack.PackInt32LE(mergedSector.Data, ofs, iter.KeyLen); ofs += 4; Array.Copy(rightIter.Data, BTreeParentIterator.FirstChildSectorPtrOffset, mergedSector.Data, ofs, KeyValueDB.PtrDownSize + 8); ofs += KeyValueDB.PtrDownSize + 8; Array.Copy(iter.Data, iter.KeyOffset, mergedSector.Data, ofs, keyStorageLen - 4); ofs += keyStorageLen - 4; Array.Copy(rightIter.Data, rightIter.FirstOffset, mergedSector.Data, ofs, rightIter.TotalLength - rightIter.FirstOffset); BTreeParentIterator.RecalculateHeader(mergedSector.Data, mergedCount); } _owner.PublishSector(mergedSector, true); _owner.DeallocateSector(leftSector); _owner.DeallocateSector(rightSector); InternalBTreeParentEraseRange(ref sector, ref iter, mergeAroundIndex, mergeAroundIndex + 1); new BTreeParentIterator(sector.Data).SetChildSectorPtrWithKeyCount(mergeAroundIndex, mergedSector.ToSectorPtr(), mergedPairs); _owner.TruncateSectorCache(true, 0); }
static void IncrementChildCountInBTreeParents(Sector sector) { while (sector.Parent != null) { Sector parentSector = sector.Parent; Debug.Assert(parentSector.Dirty); BTreeParentIterator.IncrementChildCount(parentSector.Data, sector.Position); sector = parentSector; } }
void SimplifySingleSubChild(ref Sector sector) { while (sector.Type == SectorType.BTreeParent) { var iter = new BTreeParentIterator(sector.Data); if (iter.Count > 0) break; var sectorPtr = iter.FirstChildSectorPtr; _owner.DeallocateSector(sector); sector = GetBTreeSector(sectorPtr, null); _owner.NewState.RootBTreeLevels--; } }
void CreateBTreeParentFromTwoChildren(Sector leftSector, Sector rightSector, byte[] middleKeyData, int middleKeyLen, int middleKeyOfs, int middleKeyLenInSector) { Sector parentSector = _owner.NewSector(); parentSector.Type = SectorType.BTreeParent; var entrySize = BTreeParentIterator.CalcEntrySize(middleKeyLen); parentSector.SetLengthWithRound(BTreeParentIterator.HeaderSize + BTreeParentIterator.HeaderForEntry + entrySize); BTreeParentIterator.SetCountToSectorData(parentSector.Data, 1); int ofs = 2; SectorPtr.Pack(parentSector.Data, ofs, leftSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(parentSector.Data, ofs, CalcKeysInSector(leftSector)); ofs += 8; PackUnpack.PackUInt16LE(parentSector.Data, ofs, (ushort)entrySize); ofs += 2; PackUnpack.PackUInt32LE(parentSector.Data, ofs, (uint)middleKeyLen); ofs += 4; SectorPtr.Pack(parentSector.Data, ofs, rightSector.ToSectorPtr()); ofs += KeyValueDB.PtrDownSize; PackUnpack.PackUInt64LE(parentSector.Data, ofs, CalcKeysInSector(rightSector)); ofs += 8; Array.Copy(middleKeyData, middleKeyOfs, parentSector.Data, ofs, middleKeyLenInSector); _owner.NewState.RootBTree.Ptr = parentSector.Position; _owner.NewState.RootBTreeLevels++; leftSector.Parent = parentSector; rightSector.Parent = parentSector; _currentKeySectorParents.Insert(0, parentSector); _owner.PublishSector(parentSector, false); _owner.TruncateSectorCache(true, 0); }
void SplitBTreeChild(byte[] keyBuf, int keyOfs, int keyLen, byte[] valueBuf, int valueOfs, int valueLen, Sector sector, BTreeChildIterator iter, int additionalLengthNeeded) { int middleoffset = (iter.TotalLength + iter.FirstOffset + additionalLengthNeeded) / 2; iter.MoveFirst(); bool beforeNew = true; int splitIndex = 0; int currentPos = iter.FirstOffset; while (currentPos < middleoffset) { if (beforeNew && splitIndex == _currentKeyIndexInLeaf) { beforeNew = false; currentPos += additionalLengthNeeded - BTreeChildIterator.HeaderForEntry; } else { currentPos += iter.CurrentEntrySize; splitIndex++; iter.MoveNext(); } } var rightSector = _owner.NewSector(); rightSector.Type = SectorType.BTreeChild; int rightCount = iter.Count - splitIndex + (beforeNew ? 1 : 0); rightSector.SetLengthWithRound(BTreeChildIterator.HeaderSize + rightCount * BTreeChildIterator.HeaderForEntry + iter.TotalLength + additionalLengthNeeded - BTreeChildIterator.HeaderForEntry - currentPos); BTreeChildIterator.SetCountToSectorData(rightSector.Data, rightCount); rightSector.Parent = sector.Parent; int leftCount = splitIndex + (beforeNew ? 0 : 1); var leftSector = _owner.ResizeSectorWithUpdatePosition(sector, BTreeChildIterator.HeaderSize + leftCount * BTreeChildIterator.HeaderForEntry + currentPos - iter.FirstOffset, sector.Parent, _currentKeySectorParents); _currentKeySector = leftSector; Sector newKeySector; BTreeChildIterator.SetCountToSectorData(leftSector.Data, leftCount); int newItemPos = iter.OffsetOfIndex(_currentKeyIndexInLeaf); int setActualDataPos; if (beforeNew) { Array.Copy(iter.Data, iter.FirstOffset, leftSector.Data, BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * leftCount, currentPos - iter.FirstOffset); Array.Copy(iter.Data, currentPos, rightSector.Data, BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * rightCount, newItemPos - currentPos); int rightPos = BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * rightCount + newItemPos - currentPos; setActualDataPos = rightPos; SetBTreeChildKeyDataJustLengths(rightSector, keyLen, valueLen, rightPos); rightPos += additionalLengthNeeded - BTreeChildIterator.HeaderForEntry; Array.Copy(iter.Data, newItemPos, rightSector.Data, rightPos, iter.TotalLength - newItemPos); newKeySector = rightSector; _currentKeyIndexInLeaf -= splitIndex; } else { Array.Copy(iter.Data, iter.FirstOffset, leftSector.Data, BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * leftCount, newItemPos - iter.FirstOffset); int leftPosInsert = BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * leftCount + newItemPos - iter.FirstOffset; int leftPos = leftPosInsert; leftPos += additionalLengthNeeded - BTreeChildIterator.HeaderForEntry; Array.Copy(iter.Data, currentPos - additionalLengthNeeded + BTreeChildIterator.HeaderForEntry, rightSector.Data, BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * rightCount, iter.TotalLength + additionalLengthNeeded - BTreeChildIterator.HeaderForEntry - currentPos); Array.Copy(iter.Data, newItemPos, leftSector.Data, leftPos, currentPos - newItemPos - additionalLengthNeeded + BTreeChildIterator.HeaderForEntry); setActualDataPos = leftPosInsert; SetBTreeChildKeyDataJustLengths(leftSector, keyLen, valueLen, leftPosInsert); newKeySector = leftSector; } BTreeChildIterator.RecalculateHeader(leftSector.Data, leftCount); BTreeChildIterator.RecalculateHeader(rightSector.Data, rightCount); _owner.FixChildrenParentPointers(leftSector); _owner.PublishSector(rightSector, true); Interlocked.Increment(ref leftSector.ChildrenInCache); Interlocked.Increment(ref rightSector.ChildrenInCache); try { _owner.TruncateSectorCache(true, 0); SetBTreeChildKeyData(newKeySector, keyBuf, keyOfs, keyLen, valueBuf, valueOfs, valueLen, setActualDataPos); if (leftSector.Parent == null) { CreateBTreeParentFromTwoLeafs(leftSector, rightSector); } else { iter = new BTreeChildIterator(rightSector.Data); iter.MoveFirst(); if (iter.HasKeySectorPtr) ForceKeyFlush(iter.KeySectorPtr, iter.KeyLen - iter.KeyLenInline, rightSector); int keyLenInSector = iter.KeyLenInline + (iter.HasKeySectorPtr ? KeyValueDB.PtrDownSize : 0); AddToBTreeParent(leftSector, rightSector, iter.Data, iter.KeyLen, iter.KeyOffset, keyLenInSector); } } finally { Interlocked.Decrement(ref leftSector.ChildrenInCache); Interlocked.Decrement(ref rightSector.ChildrenInCache); } UnlockUselessAndFixKeySectorParents(newKeySector, leftSector, rightSector); _currentKeySector = newKeySector; }
void CreateContentSector(byte[] buf, int ofs, int len, Sector parent, int ofsInParent) { CreateContentSector(buf, ofs, len, null, 0, 0, parent, ofsInParent); }
void UnlockCurrentKeySector() { _currentKeySector = null; _currentKeySectorParents.Clear(); }
void CreateContentSector(long len, Sector parent, int ofsInParent) { if (len <= KeyValueDB.MaxLeafDataSectorSize) { var newLeafSector = _owner.NewSector(); newLeafSector.Type = SectorType.DataChild; newLeafSector.SetLengthWithRound((int)len); newLeafSector.Parent = parent; _owner.PublishSector(newLeafSector, false); Debug.Assert(parent.Dirty); SectorPtr.Pack(parent.Data, ofsInParent, newLeafSector.ToSectorPtr()); return; } int downPtrCount; long bytesInDownLevel = KeyValueDB.GetBytesInDownLevel(len, out downPtrCount); var newSector = _owner.NewSector(); newSector.Type = SectorType.DataParent; newSector.SetLengthWithRound(downPtrCount * KeyValueDB.PtrDownSize); newSector.Parent = parent; _owner.PublishSector(newSector, false); Debug.Assert(parent.Dirty); SectorPtr.Pack(parent.Data, ofsInParent, newSector.ToSectorPtr()); for (int i = 0; i < downPtrCount; i++) { CreateContentSector(Math.Min(len, bytesInDownLevel), newSector, i * KeyValueDB.PtrDownSize); _owner.TruncateSectorCache(true, newSector.Position); len -= bytesInDownLevel; } }
void UnlockUselessAndFixKeySectorParents(Sector newKeySector, Sector leftSector, Sector rightSector) { if (newKeySector != leftSector) { var pi = _currentKeySectorParents.Count; do { if (pi < _currentKeySectorParents.Count) { Debug.Assert(_currentKeySectorParents[pi] == leftSector); _currentKeySectorParents[pi] = rightSector; } leftSector = leftSector.Parent; rightSector = rightSector.Parent; pi--; } while (leftSector != rightSector); } }
void EraseCompletely(ref Sector sector) { if (sector.Type == SectorType.BTreeChild) { var iter = new BTreeChildIterator(sector.Data); iter.MoveFirst(); do { if (iter.HasKeySectorPtr) DeleteContentSector(iter.KeySectorPtr, iter.KeyLen - iter.KeyLenInline, sector); if (iter.HasValueSectorPtr) DeleteContentSector(iter.ValueSectorPtr, iter.ValueLen - iter.ValueLenInline, sector); } while (iter.MoveNext()); } else { var iter = new BTreeParentIterator(sector.Data); for (int i = 0; i <= iter.Count; i++) { var childSectorPtr = iter.GetChildSectorPtr(i); var childSector = GetBTreeSector(childSectorPtr, sector); EraseCompletely(ref childSector); } } _owner.DeallocateSector(sector); sector = null; }
void UpdateKeyAfterRemoval(ref Sector sector, ref BTreeParentIterator iter, Sector childSector) { var entryOffset = iter.EntryOffset; var nextEntryOffset = iter.NextEntryOffset; var originalEntryLength = nextEntryOffset - entryOffset; byte[] data; int ofs; int len; int keyLen; ExtractFirstKey(childSector, out data, out ofs, out len, out keyLen); var newEntryLength = BTreeParentIterator.CalcEntrySize(keyLen); // structure of data is inlinekey/var, [downptr/12] int originalLength = iter.TotalLength; sector = _owner.ResizeSectorNoUpdatePosition(sector, originalLength - originalEntryLength + newEntryLength, sector.Parent, null); Array.Copy(iter.Data, 0, sector.Data, 0, iter.KeyOffset); Array.Copy(iter.Data, nextEntryOffset, sector.Data, entryOffset + newEntryLength, originalLength - nextEntryOffset); PackUnpack.PackInt32LE(sector.Data, entryOffset, keyLen); Array.Copy(data, ofs, sector.Data, iter.KeyOffset, len); BTreeParentIterator.RecalculateHeader(sector.Data, iter.Count); iter = new BTreeParentIterator(sector.Data); }
void ErasePartiallyChild(ref Sector sector, long firstKeyIndex, long lastKeyIndex) { var iter = new BTreeChildIterator(sector.Data); iter.MoveTo((int)firstKeyIndex); var eraseFromOfs = iter.EntryOffset; while (true) { if (iter.HasKeySectorPtr) DeleteContentSector(iter.KeySectorPtr, iter.KeyLen - iter.KeyLenInline, sector); if (iter.HasValueSectorPtr) DeleteContentSector(iter.ValueSectorPtr, iter.ValueLen - iter.ValueLenInline, sector); if (iter.Index == (int)lastKeyIndex) break; iter.MoveNext(); } var eraseToOfs = iter.EntryOffset + iter.CurrentEntrySize; var originalLength = iter.TotalLength; var newCount = iter.Count - 1 - (int)(lastKeyIndex - firstKeyIndex); sector = _owner.ResizeSectorNoUpdatePosition(sector, originalLength - eraseToOfs + eraseFromOfs - BTreeChildIterator.HeaderForEntry * (iter.Count - newCount), sector.Parent, null); BTreeChildIterator.SetCountToSectorData(sector.Data, newCount); var ofs = BTreeChildIterator.HeaderSize + BTreeChildIterator.HeaderForEntry * newCount; Array.Copy(iter.Data, iter.FirstOffset, sector.Data, ofs, eraseFromOfs - iter.FirstOffset); ofs += eraseFromOfs - iter.FirstOffset; Array.Copy(iter.Data, eraseToOfs, sector.Data, ofs, originalLength - eraseToOfs); BTreeChildIterator.RecalculateHeader(sector.Data, newCount); }
Sector LoadBTreeSector(SectorPtr sectorPtr) { Sector sector = _owner.GetOrReadSector(sectorPtr, IsWritting(), SectorTypeInit.BTreeChildOrParent, _currentKeySector); if (_currentKeySector != null) _currentKeySectorParents.Add(_currentKeySector); _currentKeySector = sector; return sector; }