Пример #1
0
 public PageSplitter(Transaction tx,
     Tree tree,
     SliceComparer cmp,
     Slice newKey,
     int len,
     long pageNumber,
     NodeFlags nodeType,
     ushort nodeVersion,
     Cursor cursor,
     TreeMutableState treeState)
 {
     _tx = tx;
     _tree = tree;
     _cmp = cmp;
     _newKey = newKey;
     _len = len;
     _pageNumber = pageNumber;
     _nodeType = nodeType;
     _nodeVersion = nodeVersion;
     _cursor = cursor;
     _treeState = treeState;
     Page page = _cursor.Pages.First.Value;
     _page = tx.ModifyPage(page.PageNumber, page);
     _cursor.Pop();
 }
Пример #2
0
 public ParentPageAction(Page parentPage, Page currentPage, Tree tree, Cursor cursor, Transaction tx)
 {
     _parentPage = parentPage;
     _currentPage = currentPage;
     _tree = tree;
     _cursor = cursor;
     _tx = tx;
 }
Пример #3
0
		public bool Seek(Slice key)
		{
			Lazy<Cursor> lazy;
			_currentPage = _tree.FindPageFor(_tx, key, out lazy);
			_cursor = lazy.Value;
			_cursor.Pop();
			var node = _currentPage.Search(key, _cmp);
			if (node == null)
			{
				return false;
			}
			_currentKey.Set(node);
			return this.ValidateCurrentKey(Current, _cmp);
		}
Пример #4
0
		public bool Seek(Slice key)
		{
			Lazy<Cursor> lazy;
			_currentPage = _tree.FindPageFor(key, out lazy);
			_cursor = lazy.Value;
			_cursor.Pop();
			var node = _currentPage.Search(key);
		    if (node != null)
		    {
                _currentKey.Set(node);
                return this.ValidateCurrentKey(Current);
		    }
		    
            // The key is not found in the db, but we are Seek()ing for equals or starts with.
		    // We know that the exact value isn't there, but it is possible that the next page has values 
		    // that is actually greater than the key, so we need to check it as well.

		    _currentPage.LastSearchPosition = _currentPage.NumberOfEntries; // force next MoveNext to move to the next _page_.
		    return MoveNext();
		}
Пример #5
0
        public TreeRebalancer(Transaction tx, Tree tree, Cursor cursor)
        {
            _tx = tx;
			_tree = tree;
	        _cursor = cursor;
        }
Пример #6
0
	    private bool TryUseRecentTransactionPage(Transaction tx, Slice key, out Lazy<Cursor> cursor, out Page page)
		{
			page = null;
			cursor = null;

			var recentPages = tx.GetRecentlyFoundPages(this);

			if (recentPages == null)
				return false;

			var foundPage = recentPages.Find(key);

			if (foundPage == null)
				return false;

			var lastFoundPageNumber = foundPage.Number;
			page = tx.GetReadOnlyPage(lastFoundPageNumber);

			if (page.IsLeaf == false)
				throw new DataException("Index points to a non leaf page");

			page.NodePositionFor(key, _cmp); // will set the LastSearchPosition

			var cursorPath = foundPage.CursorPath;
			var pageCopy = page;
			cursor = new Lazy<Cursor>(() =>
			{
				var c = new Cursor();
				foreach (var p in cursorPath)
				{
					if (p == lastFoundPageNumber)
						c.Push(pageCopy);
					else
					{
						var cursorPage = tx.GetReadOnlyPage(p);
						if (key.Options == SliceOptions.BeforeAllKeys)
						{
							cursorPage.LastSearchPosition = 0;
						}
						else if (key.Options == SliceOptions.AfterAllKeys)
						{
							cursorPage.LastSearchPosition = (ushort)(cursorPage.NumberOfEntries - 1);
						}
						else if (cursorPage.Search(key, _cmp) != null)
						{
							if (cursorPage.LastMatch != 0)
							{
								cursorPage.LastSearchPosition--;
							}
						}

						c.Push(cursorPage);
					}
				}

				return c;
			});

			return true;
		}
Пример #7
0
	    private void AddToRecentlyFoundPages(Transaction tx, Cursor c, Page p, bool? leftmostPage, bool? rightmostPage)
	    {
	        var foundPage = new RecentlyFoundPages.FoundPage(c.Pages.Count)
	        {
	            Number = p.PageNumber,
	            FirstKey = leftmostPage == true ? Slice.BeforeAllKeys : p.GetNodeKey(0),
	            LastKey = rightmostPage == true ? Slice.AfterAllKeys : p.GetNodeKey(p.NumberOfEntries - 1),
	        };
	        var cur = c.Pages.First;
	        int pos = foundPage.CursorPath.Length - 1;
	        while (cur != null)
	        {
	            foundPage.CursorPath[pos--] = cur.Value.PageNumber;
	            cur = cur.Next;
	        }

	        tx.AddRecentlyFoundPage(this, foundPage);
	    }
Пример #8
0
	    private Page SearchForPage(Transaction tx, Slice key, ref Lazy<Cursor> cursor)
	    {
	        var p = tx.GetReadOnlyPage(State.RootPageNumber);
	        var c = new Cursor();
	        c.Push(p);

	        bool rightmostPage = true;
	        bool leftmostPage = true;

	        while (p.Flags == (PageFlags.Branch))
	        {
	            int nodePos;
	            if (key.Options == SliceOptions.BeforeAllKeys)
	            {
	                p.LastSearchPosition = nodePos = 0;
	                rightmostPage = false;
	            }
	            else if (key.Options == SliceOptions.AfterAllKeys)
	            {
	                p.LastSearchPosition = nodePos = (ushort) (p.NumberOfEntries - 1);
	                leftmostPage = false;
	            }
	            else
	            {
	                if (p.Search(key, _cmp) != null)
	                {
	                    nodePos = p.LastSearchPosition;
	                    if (p.LastMatch != 0)
	                    {
	                        nodePos--;
	                        p.LastSearchPosition--;
	                    }

	                    if (nodePos != 0)
	                        leftmostPage = false;

	                    rightmostPage = false;
	                }
	                else
	                {
	                    nodePos = (ushort) (p.LastSearchPosition - 1);

	                    leftmostPage = false;
	                }
	            }

	            var node = p.GetNode(nodePos);
	            p = tx.GetReadOnlyPage(node->PageNumber);
	            Debug.Assert(node->PageNumber == p.PageNumber,
	                string.Format("Requested Page: #{0}. Got Page: #{1}", node->PageNumber, p.PageNumber));

	            c.Push(p);
	        }

	        if (p.IsLeaf == false)
	            throw new DataException("Index points to a non leaf page");

	        p.Search(key, _cmp); // will set the LastSearchPosition

	        AddToRecentlyFoundPages(tx, c, p, leftmostPage, rightmostPage);

	        cursor = new Lazy<Cursor>(() => c);
	        return p;
	    }
Пример #9
0
        private void AddToRecentlyFoundPages(Cursor c, Page p, bool? leftmostPage, bool? rightmostPage)
        {
            var foundPage = new RecentlyFoundPages.FoundPage(c.Pages.Count)
            {
                Number = p.PageNumber
            };

            if (leftmostPage == true)
            {
                if(p.KeysPrefixed)
                    foundPage.FirstKey = PrefixedSlice.BeforeAllKeys;
                else
                    foundPage.FirstKey = Slice.BeforeAllKeys;
            }
            else
            {
                foundPage.FirstKey = p.GetNodeKey(0);
            }

            if (rightmostPage == true)
            {
                if (p.KeysPrefixed)
                    foundPage.LastKey = PrefixedSlice.AfterAllKeys;
                else
                    foundPage.LastKey = Slice.AfterAllKeys;
            }
            else
            {
                foundPage.LastKey = p.GetNodeKey(p.NumberOfEntries - 1);
            }

            var cur = c.Pages.First;
            int pos = foundPage.CursorPath.Length - 1;
            while (cur != null)
            {
                foundPage.CursorPath[pos--] = cur.Value.PageNumber;
                cur = cur.Next;
            }

            _tx.AddRecentlyFoundPage(this, foundPage);
        }
Пример #10
0
        private void RebalanceRoot(Cursor cursor, Page page)
        {
            if (page.NumberOfEntries == 0)
                return; // nothing to do 
            if (!page.IsBranch || page.NumberOfEntries > 1)
            {
                return; // cannot do anything here
            }
            // in this case, we have a root pointer with just one pointer, we can just swap it out

            var node = page.GetNode(0);
            Debug.Assert(node->Flags == (NodeFlags.PageRef));

            _tree.State.LeafPages = 1;
			_tree.State.BranchPages = 0;
			_tree.State.Depth = 1;
			_tree.State.PageCount = 1;

			var rootPage = _tx.ModifyPage(node->PageNumber, null);
			_tree.State.RootPageNumber = rootPage.PageNumber;

            Debug.Assert(rootPage.Dirty);

            cursor.Pop();
            cursor.Push(rootPage);

            _tx.FreePage(page.PageNumber);
        }
Пример #11
0
        public Page Execute(Cursor cursor, Page page)
        {
            _tx.ClearRecentFoundPages(_tree);
            if (cursor.PageCount <= 1) // the root page
            {
                RebalanceRoot(cursor, page);
                return null;
            }

			var parentPage = _tx.ModifyPage(cursor.ParentPage.PageNumber, cursor.ParentPage);
			cursor.Update(cursor.Pages.First.Next, parentPage);

            if (page.NumberOfEntries == 0) // empty page, just delete it and fixup parent
            {
				// need to delete the implicit left page, shift right 
                if (parentPage.LastSearchPosition == 0 && parentPage.NumberOfEntries > 2)
                {
					var newImplicit = parentPage.GetNode(1)->PageNumber;
                    parentPage.RemoveNode(0);
                    parentPage.RemoveNode(0);
                    parentPage.AddPageRefNode(0, Slice.Empty, newImplicit);
                }
                else // will be set to rights by the next rebalance call
                {
                    parentPage.RemoveNode(parentPage.LastSearchPositionOrLastEntry);
                }
				
				_tx.FreePage(page.PageNumber);
                cursor.Pop();

                return parentPage;
            }

            var minKeys = page.IsBranch ? 2 : 1;
            if ((page.UseMoreSizeThan(_tx.DataPager.PageMinSpace)) &&
                page.NumberOfEntries >= minKeys)
                return null; // above space/keys thresholds

            Debug.Assert(parentPage.NumberOfEntries >= 2); // if we have less than 2 entries in the parent, the tree is invalid

            var sibling = SetupMoveOrMerge(cursor, page, parentPage);
            Debug.Assert(sibling.PageNumber != page.PageNumber);

            minKeys = sibling.IsBranch ? 2 : 1; // branch must have at least 2 keys
            if (sibling.UseMoreSizeThan(_tx.DataPager.PageMinSpace) &&
                sibling.NumberOfEntries > minKeys)
            {	         
                // neighbor is over the min size and has enough key, can move just one key to  the current page
	            if (page.IsBranch)
	            {
		            MoveBranchNode(parentPage, sibling, page);
	            }
	            else
		            MoveLeafNode(parentPage, sibling, page);
	            cursor.Pop();

                return parentPage;
            }

			if (page.LastSearchPosition == 0) // this is the right page, merge left
            {
				if (!HasEnoughSpaceToCopyNodes(sibling, page))
					return null;
				MergePages(parentPage, sibling, page);
            }
            else // this is the left page, merge right
            {
				if (!HasEnoughSpaceToCopyNodes(page, sibling))
					return null;
				MergePages(parentPage, page, sibling);
            }
            cursor.Pop();			

            return parentPage;
        }
Пример #12
0
 private Page SetupMoveOrMerge(Cursor c, Page page, Page parentPage)
 {
     Page sibling;
     if (parentPage.LastSearchPosition == 0) // we are the left most item
     {
         parentPage.LastSearchPosition = 1;
         sibling = _tx.ModifyPage(parentPage.GetNode(1)->PageNumber, null);
         parentPage.LastSearchPosition = 0;
         sibling.LastSearchPosition = 0;
         page.LastSearchPosition = page.NumberOfEntries;
         parentPage.LastSearchPosition = 1;
     }
     else // there is at least 1 page to our left
     {
         var beyondLast = parentPage.LastSearchPosition == parentPage.NumberOfEntries;
         if (beyondLast)
             parentPage.LastSearchPosition--;
         parentPage.LastSearchPosition--;
         sibling = _tx.ModifyPage(parentPage.GetNode(parentPage.LastSearchPosition)->PageNumber, null);
         parentPage.LastSearchPosition++;
         if (beyondLast)
             parentPage.LastSearchPosition++;
         sibling.LastSearchPosition = sibling.NumberOfEntries - 1;
         page.LastSearchPosition = 0;
     }
     return sibling;
 }