Exemple #1
0
        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;
Exemple #2
0
        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));
        }
Exemple #3
0
        public void EnsureMapped(LowLevelTransaction tx, int scratchNumber, long positionInScratchBuffer, int numberOfPages)
        {
            var item = GetScratchBufferFile(scratchNumber);

            ScratchBufferFile bufferFile = item.File;

            bufferFile.EnsureMapped(tx, positionInScratchBuffer, numberOfPages);
        }
Exemple #4
0
        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));
        }
Exemple #6
0
        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));
        }
Exemple #9
0
        /// <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);
        }
Exemple #11
0
        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;
            }
        }
Exemple #12
0
 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);
 }
Exemple #16
0
 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);
        }
Exemple #20
0
 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
                });
            }
        }
Exemple #23
0
        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();
            });
        }
Exemple #24
0
        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());
        }
Exemple #25
0
 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;
 }
Exemple #26
0
 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
     };
 }
Exemple #27
0
        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;
        }
Exemple #28
0
        public TreeCursorConstructor(TreeCursor cursor)
        {
            this._current = cursor;

            this._llt                 = null;
            this._tree                = null;
            this._pageCopy            = null;
            this._cursorPath          = null;
            this._lastFoundPageNumber = 0;
        }
Exemple #29
0
        public void UpdateCurrentTransaction(Transaction tx)
        {
            if (tx != null)
            {
                _llt      = tx.LowLevelTransaction;
                _lastPage = default(Page);
                return;
            }

            ThrowTransactionIsNull();
        }
Exemple #30
0
        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));
        }