protected SplitContext SplitLeaf(LowLevelTransaction lltx, TreePage current, Stack <TreePage> path, Span <byte> key, int index) { if (!current.IsLeaf) { throw new InvalidOperationException($"page:{current.Position} is not a leaf page"); } ref var currentHeader = ref current.TreeHeader;
public byte *AcquirePagePointerForNewPage(LowLevelTransaction tx, int scratchNumber, long p, int numberOfPages) { var item = GetScratchBufferFile(scratchNumber); ScratchBufferFile bufferFile = item.File; return(bufferFile.AcquirePagePointerForNewPage(tx, p, numberOfPages)); }
public void EnsureMapped(LowLevelTransaction tx, int scratchNumber, long positionInScratchBuffer, int numberOfPages) { var item = GetScratchBufferFile(scratchNumber); ScratchBufferFile bufferFile = item.File; bufferFile.EnsureMapped(tx, positionInScratchBuffer, numberOfPages); }
public byte *AcquirePagePointerWithOverflowHandling(LowLevelTransaction tx, int scratchNumber, long p) { var item = GetScratchBufferFile(scratchNumber); ScratchBufferFile bufferFile = item.File; return(bufferFile.AcquirePagePointerWithOverflowHandling(tx, p)); }
public DecompressedLeafPage GetPage(LowLevelTransaction tx, int pageSize, DecompressionUsage usage, TreePage original) { GetTemporaryPage(tx, pageSize, out var tempPage); var treePage = tempPage.GetTempPage(); return(new DecompressedLeafPage(treePage.Base, treePage.PageSize, usage, original, tempPage)); }
public RawDataSection(LowLevelTransaction tx, long pageNumber) { PageNumber = pageNumber; _tx = tx; _sectionHeader = (RawDataSmallSectionPageHeader *)_tx.GetPage(pageNumber).Pointer; }
public byte *AcquirePagePointer(LowLevelTransaction tx, int scratchNumber, long p) { var item = _scratchBuffers[scratchNumber]; ScratchBufferFile bufferFile = item.File; return(bufferFile.AcquirePagePointer(tx, p)); }
public Page ReadPage(LowLevelTransaction tx, int scratchNumber, long p, PagerState pagerState = null) { var item = _scratchBuffers[scratchNumber]; ScratchBufferFile bufferFile = item.File; return(bufferFile.ReadPage(tx, p, pagerState)); }
/// <summary> /// write transaction's raw page data into journal /// </summary> public UpdatePageTranslationTableAndUnusedPagesAction Write(LowLevelTransaction tx, CompressedPagesResult pages, LazyTransactionBuffer lazyTransactionScratch) { var ptt = new Dictionary <long, PagePosition>(NumericEqualityComparer.BoxedInstanceInt64); var cur4KbPos = _writePosIn4Kb; Debug.Assert(pages.NumberOf4Kbs > 0); UpdatePageTranslationTable(tx, _unusedPagesHashSetPool, ptt); if (tx.IsLazyTransaction == false && (lazyTransactionScratch == null || lazyTransactionScratch.HasDataInBuffer() == false)) { try { Write(cur4KbPos, pages.Base, pages.NumberOf4Kbs); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { if (lazyTransactionScratch == null) { throw new InvalidOperationException("lazyTransactionScratch cannot be null if the transaction is lazy (or a previous one was)"); } var sizeInBytes = _journalWriter.NumberOfAllocated4Kb * 4 * Constants.Size.Kilobyte; int sizeInPages = checked (sizeInBytes / Constants.Storage.PageSize + sizeInBytes % Constants.Storage.PageSize == 0 ? 0 : 1); lazyTransactionScratch.EnsureSize(sizeInPages); lazyTransactionScratch.AddToBuffer(cur4KbPos, pages); // non lazy tx will add itself to the buffer and then flush scratch to journal if (tx.IsLazyTransaction == false || lazyTransactionScratch.NumberOfPages > tx.Environment.ScratchBufferPool.GetAvailablePagesCount() / 2) { try { lazyTransactionScratch.WriteBufferToFile(this, tx); } catch (Exception e) { _env.Options.SetCatastrophicFailure(ExceptionDispatchInfo.Capture(e)); throw; } } else { lazyTransactionScratch.EnsureHasExistingReadTransaction(tx); } } return(new UpdatePageTranslationTableAndUnusedPagesAction(this, tx, ptt, pages.NumberOf4Kbs)); }
public void Free(LowLevelTransaction tx, int scratchNumber, long page, long?txId) { var scratch = _scratchBuffers[scratchNumber]; scratch.File.Free(page, txId); if (scratch.File.AllocatedPagesCount != 0) { return; } while (_recycleArea.First != null) { var recycledScratch = _recycleArea.First.Value; if (IsLowMemory() == false && DateTime.UtcNow - recycledScratch.RecycledAt <= TimeSpan.FromMinutes(1)) { break; } _recycleArea.RemoveFirst(); if (recycledScratch.File.HasActivelyUsedBytes(_env.PossibleOldestReadTransaction(tx))) { // even though this was in the recycle area, there might still be some transactions looking at it // so we cannot dispose it right now, the disposal will happen in RemoveInactiveScratches // when we are sure it's really no longer in use continue; } _scratchBuffers.TryRemove(recycledScratch.Number, out var _); recycledScratch.File.Dispose(); _scratchSpaceMonitor.Decrease(recycledScratch.File.NumberOfAllocatedPages * Constants.Storage.PageSize); } if (scratch == _current) { if (scratch.File.Size <= _options.MaxScratchBufferSize) { // we'll take the chance that no one is using us to reset the memory allocations // and avoid fragmentation, we can only do that if no transaction is looking at us if (scratch.File.HasActivelyUsedBytes(_env.PossibleOldestReadTransaction(tx)) == false) { scratch.File.Reset(); } return; } // this is the current one, but the size is too big, let us trim it var newCurrent = NextFile(_options.InitialLogFileSize, _options.MaxScratchBufferSize); newCurrent.File.PagerState.AddRef(); _current = newCurrent; } TryRecycleScratchFile(scratch); }
public PageFromScratchBuffer Allocate(LowLevelTransaction tx, int numberOfPages) { if (tx == null) { throw new ArgumentNullException(nameof(tx)); } var size = Bits.PowerOf2(numberOfPages); var current = _current; PageFromScratchBuffer result; if (current.File.TryGettingFromAllocatedBuffer(tx, numberOfPages, size, out result)) { return(result); } // we can allocate from the end of the file directly if (current.File.LastUsedPage + size <= current.File.NumberOfAllocatedPages) { return(current.File.Allocate(tx, numberOfPages, size)); } if (current.File.Size < _options.MaxScratchBufferSize) { var numberOfPagesBeforeAllocate = current.File.NumberOfAllocatedPages; var page = current.File.Allocate(tx, numberOfPages, size); if (current.File.NumberOfAllocatedPages > numberOfPagesBeforeAllocate) { _scratchSpaceMonitor.Increase((current.File.NumberOfAllocatedPages - numberOfPagesBeforeAllocate) * Constants.Storage.PageSize); } return(page); } var minSize = numberOfPages * Constants.Storage.PageSize; var requestedSize = Math.Max(minSize, Math.Min(_current.File.Size * 2, _options.MaxScratchBufferSize)); // We need to ensure that _current stays constant through the codepath until return. current = NextFile(minSize, requestedSize); try { var scratchPagerState = current.File.PagerState; tx.EnsurePagerStateReference(ref scratchPagerState); return(current.File.Allocate(tx, numberOfPages, size)); } finally { // That's why we update only after exiting. _current = current; } }
public FixedSizeTreeCursor GetCursor(LowLevelTransaction lltx) { return(new FixedSizeTreeCursor() { Tree = this, Index = 0, Current = GetPageForQuery(lltx, long.MinValue, Constants.BTreeLeafPageDepth) }); }
public static int GetDataSize(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); return(overFlowPage.OverflowSize); } return(node->DataSize); }
public static void CopyTo(LowLevelTransaction tx, TreeNodeHeader *node, byte *dest) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetPage(node->PageNumber); Memory.Copy(dest, overFlowPage.Pointer + Constants.TreePageHeaderSize, overFlowPage.OverflowSize); } Memory.Copy(dest, (byte *)node + node->KeySize + Constants.NodeHeaderSize, node->DataSize); }
public static byte *DirectAccess(LowLevelTransaction tx, TreeNodeHeader *node) { if (node->Flags == (TreeNodeFlags.PageRef)) { var overFlowPage = tx.GetReadOnlyTreePage(node->PageNumber); return(overFlowPage.Base + Constants.TreePageHeaderSize); } return((byte *)node + node->KeySize + Constants.NodeHeaderSize); }
public Tree(LowLevelTransaction llt, Transaction tx, Slice name, TreeMutableState state) { _llt = llt; _tx = tx; Name = name; _recentlyFoundPages = new RecentlyFoundTreePages(llt.Flags == TransactionFlags.Read ? 8 : 2); _state = new TreeMutableState(llt); _state = state; }
public bool TryGettingFromAllocatedBuffer(LowLevelTransaction tx, int numberOfPages, long size, out PageFromScratchBuffer result) { result = null; LinkedList <long> listOfAvailableImmediately; if (_freePagesBySizeAvailableImmediately.TryGetValue(size, out listOfAvailableImmediately) && listOfAvailableImmediately.Count > 0) { var freeAndAvailablePageNumber = listOfAvailableImmediately.Last.Value; listOfAvailableImmediately.RemoveLast(); #if VALIDATE byte *freeAndAvailablePagePointer = _scratchPager.AcquirePagePointer(tx, freeAndAvailablePageNumber, PagerState); ulong freeAndAvailablePageSize = (ulong)size * Constants.Storage.PageSize; // This has to be forced, as the list of available pages should be protected by default, but this // is a policy we implement inside the ScratchBufferFile only. _scratchPager.UnprotectPageRange(freeAndAvailablePagePointer, freeAndAvailablePageSize, true); #endif result = new PageFromScratchBuffer(_scratchNumber, freeAndAvailablePageNumber, size, numberOfPages); _allocatedPagesCount += numberOfPages; _allocatedPages.Add(freeAndAvailablePageNumber, result); return(true); } LinkedList <PendingPage> list; if (!_freePagesBySize.TryGetValue(size, out list) || list.Count <= 0) { return(false); } var val = list.Last.Value; if (val.ValidAfterTransactionId >= tx.Environment.PossibleOldestReadTransaction(tx)) { return(false); } list.RemoveLast(); #if VALIDATE byte *freePageBySizePointer = _scratchPager.AcquirePagePointer(tx, val.Page, PagerState); ulong freePageBySizeSize = (ulong)size * Constants.Storage.PageSize; // This has to be forced, as the list of available pages should be protected by default, but this // is a policy we implement inside the ScratchBufferFile only. _scratchPager.UnprotectPageRange(freePageBySizePointer, freePageBySizeSize, true); #endif result = new PageFromScratchBuffer(_scratchNumber, val.Page, size, numberOfPages); _allocatedPagesCount += numberOfPages; _allocatedPages.Add(val.Page, result); return(true); }
public IEnumerable <long> GetFreePagesOverheadPages(LowLevelTransaction tx) { var fst = GetFreeSpaceTree(tx); foreach (var page in fst.AllPages()) { yield return(page); } }
public void FlushLogToDataFile(LowLevelTransaction tx = null, bool allowToFlushOverwrittenPages = false) { if (_options.ManualFlushing == false) { throw new NotSupportedException("Manual flushes are not set in the storage options, cannot manually flush!"); } ForceLogFlushToDataFile(tx, allowToFlushOverwrittenPages); }
private void UpdateMaxSeenTxId(LowLevelTransaction tx) { if (_maxSeenTransaction > tx.Id) { throw new InvalidOperationException("Transaction ids has to always increment, but got " + tx.Id + " when already seen tx " + _maxSeenTransaction); } _maxSeenTransaction = tx.Id; }
public void FreeScratchPagesOlderThan(LowLevelTransaction tx, long lastSyncedTransactionId, bool forceToFreeAllPages = false) { if (tx == null) { throw new ArgumentNullException(nameof(tx)); } var unusedPages = new List <PagePosition>(); List <PagePosition> unusedAndFree; List <long> keysToRemove; lock (_locker) { unusedAndFree = _unusedPages.FindAll(position => position.TransactionId <= lastSyncedTransactionId); _unusedPages.RemoveAll(position => position.TransactionId <= lastSyncedTransactionId); if (forceToFreeAllPages) { keysToRemove = _pageTranslationTable.KeysWhereSomePagesOlderThan(lastSyncedTransactionId); } else { keysToRemove = _pageTranslationTable.KeysWhereAllPagesOlderThan(lastSyncedTransactionId); } _pageTranslationTable.Remove(keysToRemove, lastSyncedTransactionId, unusedPages); } foreach (var unusedScratchPage in unusedAndFree) { if (unusedScratchPage.IsFreedPageMarker) { continue; } tx.Environment.ScratchBufferPool.Free(unusedScratchPage.ScratchNumber, unusedScratchPage.ScratchPos, tx.Id); } foreach (var page in unusedPages) { if (page.IsFreedPageMarker) { continue; } if (page.UnusedInPTT) // to prevent freeing a page that was already freed as unusedAndFree { // the page could be either freed in the current run, then just skip it to avoid freeing an unallocated page, or // it could be released in an earlier run, but it still resided in PTT because a under a relevant page number of PTT // there were overwrites by newer transactions (> lastSyncedTransactionId) and we didn't remove it from there continue; } tx.Environment.ScratchBufferPool.Free(page.ScratchNumber, page.ScratchPos, tx.Id); } }
private void UpdatePageTranslationTable(LowLevelTransaction tx, HashSet <PagePosition> unused, Dictionary <long, PagePosition> ptt) { foreach (var freedPageNumber in tx.GetFreedPagesNumbers()) { // set freed page marker - note it can be overwritten below by later allocation ptt[freedPageNumber] = new PagePosition { ScratchPos = -1, ScratchNumber = -1, TransactionId = tx.Id, JournalNumber = Number, IsFreedPageMarker = true }; } var txPages = tx.GetTransactionPages(); foreach (var txPage in txPages) { var scratchPage = tx.Environment.ScratchBufferPool.ReadPage(tx, txPage.ScratchFileNumber, txPage.PositionInScratchBuffer); var pageNumber = scratchPage.PageNumber; PagePosition value; if (_pageTranslationTable.TryGetValue(tx, pageNumber, out value)) { value.UnusedInPTT = true; unused.Add(value); } PagePosition pagePosition; if (ptt.TryGetValue(pageNumber, out pagePosition) && pagePosition.IsFreedPageMarker == false) { unused.Add(pagePosition); } ptt[pageNumber] = new PagePosition { ScratchPos = txPage.PositionInScratchBuffer, ScratchNumber = txPage.ScratchFileNumber, TransactionId = tx.Id, JournalNumber = Number }; } foreach (var freedPage in tx.GetUnusedScratchPages()) { unused.Add(new PagePosition { ScratchPos = freedPage.PositionInScratchBuffer, ScratchNumber = freedPage.ScratchFileNumber, TransactionId = tx.Id, JournalNumber = Number }); } }
public static void RenderAndShow_FixedSizeTree(LowLevelTransaction tx, FixedSizeTree fst) { var name = fst.Name; var tree = fst.Parent; RenderHtmlTreeView(writer => { DumpFixedSizeTreeToStreamAsync(tx, fst, writer, name, tree).Wait(); }); }
public string Dump(LowLevelTransaction tx) { var sb = new StringBuilder(); for (var i = 0; i < NumberOfEntries; i++) { sb.Append(GetNodeKey(tx, i)).Append(", "); } return(sb.ToString()); }
public Tree(LowLevelTransaction llt, Transaction tx, TreeMutableState state) { _llt = llt; _tx = tx; _recentlyFoundPages = new RecentlyFoundTreePages(llt.Flags == TransactionFlags.Read ? 8 : 2); _isPageLocatorOwned = true; _pageLocator = llt.PersistentContext.AllocatePageLocator(llt); _state = new TreeMutableState(llt); _state = state; }
private Tree(LowLevelTransaction llt, Transaction tx, long root) { _llt = llt; _tx = tx; _recentlyFoundPages = new RecentlyFoundTreePages(llt.Flags == TransactionFlags.Read ? 8 : 2); _state = new TreeMutableState(llt) { RootPageNumber = root }; }
public TreeCursorConstructor(LowLevelTransaction llt, Tree tree, TreePage pageCopy, long[] cursorPath, long lastFoundPageNumber) { this._llt = llt; this._tree = tree; this._pageCopy = pageCopy; this._cursorPath = cursorPath; this._lastFoundPageNumber = lastFoundPageNumber; this._current = null; }
public TreeCursorConstructor(TreeCursor cursor) { this._current = cursor; this._llt = null; this._tree = null; this._pageCopy = null; this._cursorPath = null; this._lastFoundPageNumber = 0; }
public void UpdateCurrentTransaction(Transaction tx) { if (tx != null) { _llt = tx.LowLevelTransaction; _lastPage = default(Page); return; } ThrowTransactionIsNull(); }
public ByteStringContext.Scope GetNodeKey(LowLevelTransaction tx, int nodeNumber, ByteStringType type /* = ByteStringType.Mutable | ByteStringType.External*/, out Slice result) { var node = GetNode(nodeNumber); // This will ensure that we can create a copy or just use the pointer instead. if ((type & ByteStringType.External) == 0) { return(TreeNodeHeader.ToSlice(tx.Allocator, node, type, out result)); } return(TreeNodeHeader.ToSlicePtr(tx.Allocator, node, type, out result)); }