diff -r 000000000000 -r 08ec8eefde2f persistentstorage/store/UBTREE/UB_INL.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/store/UBTREE/UB_INL.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,408 @@ +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Inline entry node organisations +// +// + +#include "UB_STD.H" + +EXPORT_C TBtreeInlineLeafOrg::TBtreeInlineLeafOrg() + {} + +EXPORT_C void TBtreeInlineLeafOrg::SetEntrySize(TInt aSize) + { + __ASSERT_DEBUG(aSize<=KMaxBtreeKeyLength,Panic(EBadEntrySize)); + iEntrySize=Align4(aSize); + iMaxEntries=(KPoolPageSize-sizeof(SHeader))/iEntrySize; + } + +EXPORT_C TBool TBtreeInlineLeafOrg::Insert(TAny *aNode,TInt aPos,const TDesC8& anEntry) const + { + SNode* const pn=Node(aNode); + __ASSERT_DEBUG(aPos<=pn->iHead.iCount,Panic(EBadEntryPos)); + if (pn->iHead.iCount==iMaxEntries) + return EFalse; + TUint8* pe=Entry(pn,aPos); + Mem::Copy(pe+iEntrySize,pe,iEntrySize*(pn->iHead.iCount-aPos)); + TInt size=anEntry.Size(); + __ASSERT_ALWAYS(size<=iEntrySize,Panic(EBadEntrySize)); + Mem::Copy(pe,anEntry.Ptr(),size); + ++pn->iHead.iCount; + return ETrue; + } + +TAny *TBtreeInlineLeafOrg::DoRedistribute(TAny *aLeftNode,TAny *aRightNode,TInt aInsertPos) const +// +// Even out the distibution of entries in LeftNode and RightNode +// if aInsertPos>=0 we want to insert at this cumulative position so take into account for redistribution +// If total entries <=iMaxEntries or >iMaxEntries*2 then return 0 +// Otherwise return the node into which insertion should take place +// + { + SNode* const pl=Node(aLeftNode); + SNode* const pr=Node(aRightNode); + TAny *insertNode=aRightNode; + TInt lCount=pl->iHead.iCount; + TInt rCount=pr->iHead.iCount; + TInt total=lCount+rCount; + TInt left=(total+1)>>1; + if (aInsertPos>=0) + { // call from Insertoverflow + __ASSERT_DEBUG(aInsertPos<=total,Panic(EBadEntryPos)); + if (aInsertPos=iMaxEntries<<1) + return 0; // no space + } + else + { // from Redistribute + if (total<=iMaxEntries) + return 0; // underflow state + } + pl->iHead.iCount=left; + pr->iHead.iCount=total-left; + if (lCount>left) + { // move right + TInt move=lCount-left; + Mem::Copy(Entry(pr,move),pr->iEntries,rCount*iEntrySize); + Mem::Copy(pr->iEntries,Entry(pl,left),move*iEntrySize); + } + else if (lCountiEntries,move*iEntrySize); + Mem::Copy(pr->iEntries,Entry(pr,move),(rCount-move)*iEntrySize); + } + return insertNode; + } + +EXPORT_C TBool TBtreeInlineLeafOrg::InsertOverflow(TAny *aLeftNode,TAny *aRightNode,TInt aPos,TBool aInsertOnLeft,const TDesC8& anEntry) const +// +// Redistribute keys in aLeftNode and aRightNode to insert a new entry, return success or failure +// We know that the insertion node is full (see code for CBplusTree::InsertAtCurrentL) +// promotion done by manager +// + { + __ASSERT_DEBUG(Node(aInsertOnLeft?aLeftNode:aRightNode)->iHead.iCount==iMaxEntries,Panic(EIllegalOverflow)); + if (!aInsertOnLeft) + aPos+=Node(aLeftNode)->iHead.iCount; + TAny* iNode=DoRedistribute(aLeftNode,aRightNode,aPos); + if (!iNode) + return EFalse; + if (iNode==aRightNode) + aPos-=Node(aLeftNode)->iHead.iCount; + return Insert(iNode,aPos,anEntry); + } + +EXPORT_C void TBtreeInlineLeafOrg::InsertSplit(TAny *aLeftNode,TAny *aRightNode,TInt aPos,const TDesC8& anEntry) const +// +// Split contents of left node into left and right and insert entry +// copy link node from left to right +// + { + __ASSERT_DEBUG(Node(aLeftNode)->iHead.iCount==iMaxEntries,Panic(EIllegalSplit)); + __ASSERT_DEBUG(Node(aRightNode)->iHead.iCount==0,Panic(EIllegalSplit)); + TAny* iNode=DoRedistribute(aLeftNode,aRightNode,aPos); + if (iNode==aRightNode) + aPos-=Node(aLeftNode)->iHead.iCount; + Insert(iNode,aPos,anEntry); + Node(aRightNode)->iHead.iLink=Node(aLeftNode)->iHead.iLink; + } + +EXPORT_C TBool TBtreeInlineLeafOrg::Delete(TAny *aNode,TInt aPos) const +// +// Delete the specified entry from the node +// Part of the contract is to garauntee that the entry is deleted, even if undeflowed +// + { + SNode* const pn=Node(aNode); + __ASSERT_DEBUG(aPosiHead.iCount,Panic(EBadEntryPos)); + + --pn->iHead.iCount; + TUint8* pe=Entry(pn,aPos); + Mem::Copy(pe,pe+iEntrySize,(pn->iHead.iCount-aPos)*iEntrySize); + return pn->iHead.iCount>=iMaxEntries>>1; // underflow criterion + } + +EXPORT_C TBool TBtreeInlineLeafOrg::Redistribute(TAny *aLeftNode,TAny *aRightNode) const +// +// Even out the distibution of entries in LeftNode and RightNode if enough keys +// leaf nodes do not set the pivot, done by manager +// + { + return DoRedistribute(aLeftNode,aRightNode)!=0; + } + +EXPORT_C void TBtreeInlineLeafOrg::Concatenate(TAny *aLeftNode,const TAny *aRightNode) const +// +// Join LeftNode and RightNode together in LeftNode, set link +// contract says that it will fit +// + { + SNode* const pl=Node(aLeftNode); + const SNode* const pr=Node(aRightNode); + TInt rCount=pr->iHead.iCount; + __ASSERT_DEBUG(pl->iHead.iCount+rCount<=iMaxEntries,Panic(ECannotConcatenate)); + Mem::Copy(Entry(pl,pl->iHead.iCount),pr->iEntries,rCount*iEntrySize); + pl->iHead.iCount+=rCount; + pl->iHead.iLink=pr->iHead.iLink; + } + +EXPORT_C TInt TBtreeInlineLeafOrg::LastEntry(const TAny* aNode) const + { + return Node(aNode)->iHead.iCount; + } + +EXPORT_C const TAny *TBtreeInlineLeafOrg::EntryPtr(const TAny* aNode,TInt aPos) const + { + __ASSERT_DEBUG(aPosiHead.iCount,Panic(EBadEntryPos)); + return Entry(Node(aNode),aPos); + } + +EXPORT_C TPtrC8 TBtreeInlineLeafOrg::Entry(const TAny* aNode,TInt aPos) const + { + return TPtrC8((const TUint8*)EntryPtr(aNode,aPos),iEntrySize); + } + +EXPORT_C TPageRef TBtreeInlineLeafOrg::LinkNode(const TAny* aNode) const + { + return Node(aNode)->iHead.iLink; + } + +EXPORT_C void TBtreeInlineLeafOrg::SetLinkNode(TAny* aNode,TPageRef aNextNode) const + { + Node(aNode)->iHead.iLink=aNextNode; + } + + +// class TBtreeInlineIndexOrg + +EXPORT_C TBtreeInlineIndexOrg::TBtreeInlineIndexOrg() + {} + +EXPORT_C void TBtreeInlineIndexOrg::SetEntrySize(TInt aSize) + { + __ASSERT_DEBUG(aSize<=KMaxBtreeKeyLength,Panic(EBadEntrySize)); + iEntrySize=_FOFF(SEntry,iKey[Align4(aSize)]); + iMaxEntries=(KPoolPageSize-sizeof(SHeader)-sizeof(TPageRef))/iEntrySize; + } + +EXPORT_C TBool TBtreeInlineIndexOrg::Insert(TAny *aNode,TInt aPos,const TDesC8& anEntry,TPageRef aChild) const + { + SNode* const pn=Node(aNode); + __ASSERT_DEBUG(aPos<=pn->iHead.iCount,Panic(EBadEntryPos)); + if (pn->iHead.iCount==iMaxEntries) + return EFalse; + TUint8* pe=Entry(pn,aPos)->iKey; + Mem::Copy(pe+iEntrySize,pe,iEntrySize*(pn->iHead.iCount-aPos)); + TInt size=anEntry.Size(); + __ASSERT_ALWAYS(size<=KeySize(),Panic(EBadEntrySize)); + *(TPageRef*)Mem::Copy(pe,anEntry.Ptr(),size)=aChild; + ++pn->iHead.iCount; + return ETrue; + } + +TBtreeInlineIndexOrg::SNode* TBtreeInlineIndexOrg::DoRedistribute(TAny *aLeftNode,TAny *aRightNode,const TDesC8& aPivot,TBtreePivot& aNewPivot,TInt aInsertPos) const +// +// Even out the distibution of entries in LeftNode and RightNode +// if aInsertPos>=0 we want to insert at this cumulative position so take into account for redistribution +// If total entries <=iMaxEntries or >iMaxEntries*2 then return 0 +// Otherwise return the node into which insertion should take place +// If insertion should be promoted insert position is beyond end of left node, otherwise +// the new pivot is copied to aNewPivot +// + { + SNode* const pl=Node(aLeftNode); + SNode* const pr=Node(aRightNode); + SNode *insertNode=pr; + TInt lCount=pl->iHead.iCount; + TInt rCount=pr->iHead.iCount; + TInt total=lCount+rCount+1; // including pivot entry + TInt left=total>>1; + if (aInsertPos>=0) + { // call from InsertOverflow + __ASSERT_DEBUG(aInsertPos<=total,Panic(EBadEntryPos)); + if (total>iMaxEntries<<1) + return NULL; // no space to insert + if (aInsertPos<=left) + { + if (aInsertPosiHead.iCount=left; + pr->iHead.iCount=total-left-1; // pivot not included + TInt pSize=aPivot.Size(); + __ASSERT_DEBUG(pSize<=KeySize(),Panic(EBadEntrySize)); + if (lCount>left) + { // move right + TInt move=lCount-left; + Mem::Copy(Entry(pr,move),pr->iEntries,rCount*iEntrySize+sizeof(TPageRef)); + TUint8 *pp=Mem::Copy(pr->iEntries,Entry(pl,left+1),(move-1)*iEntrySize+sizeof(TPageRef)); + Mem::Copy(pp,aPivot.Ptr(),pSize); + aNewPivot.Copy(Entry(pl,left)->iKey,KeySize()); // new pivot + } + else if (lCountiKey,aPivot.Ptr(),pSize); + Mem::Copy(pp,pr->iEntries,move*iEntrySize+sizeof(TPageRef)); + aNewPivot.Copy(Entry(pr,move)->iKey,KeySize()); + Mem::Copy(pr->iEntries,Entry(pr,move+1),(rCount-move-1)*iEntrySize+sizeof(TPageRef)); + } + else + { // should we ever get here? (lCount==left) + aNewPivot=aPivot; + } + return insertNode; + } + +EXPORT_C TBool TBtreeInlineIndexOrg::InsertOverflow(TAny *aLeftNode,TAny *aRightNode,TInt aPos,TBool aInsertOnLeft,const TDesC8& anEntry, + TPageRef aChild,const TDesC8& aPivot,TBtreePivot& aNewPivot) const +// +// Redistribute keys in aNodePtr and aRight to insert a new entry, return success or failure +// We know that aNodePtr is full (see code for Insert) +// + { + SNode* const pl=Node(aLeftNode); + if (!aInsertOnLeft) + aPos+=pl->iHead.iCount+1; // cumulative insertion point + SNode* insert=DoRedistribute(aLeftNode,aRightNode,aPivot,aNewPivot,aPos); + if (insert==NULL) // no space + return EFalse; + TInt lCount=pl->iHead.iCount; + if (insert==aRightNode) + aPos-=lCount+1; // insert position in right node + else + { + // check for the special situation [aPos]:[aPos-1] + // in which case re-arrange to promote the new entry + SNode* pr=Node(aRightNode); + if (aPos==lCount && pr->iHead.iCountiChild); + Entry(pr,0)->iChild=aChild; + aNewPivot=anEntry; + return ETrue; + } + } + __ASSERT_DEBUG(insert->iHead.iCountiHead.iCount==iMaxEntries,Panic(EIllegalSplit)); + __ASSERT_DEBUG(Node(aRightNode)->iHead.iCount==0,Panic(EIllegalSplit)); + SNode* const pl=Node(aLeftNode); + SNode* const pr=Node(aRightNode); + SEntry *pe=Entry(pl,pl->iHead.iCount); + --pl->iHead.iCount; + Entry(pr,0)->iChild=pe->iChild; + TPtrC8 pivot((TUint8*)pe-KeySize(),KeySize()); + InsertOverflow(aLeftNode,aRightNode,aPos,ETrue,anEntry,aChild,pivot,aPromote); + } + +EXPORT_C TBool TBtreeInlineIndexOrg::Update(TAny *aNode,TInt aPos,const TDesC8& anEntry) const + { + __ASSERT_DEBUG(anEntry.Size()<=KeySize(),Panic(EBadEntrySize)); + __ASSERT_DEBUG(aPosiHead.iCount,Panic(EBadEntryPos)); + Mem::Copy(Entry(Node(aNode),aPos)->iKey,anEntry.Ptr(),KeySize()); + return ETrue; + } + +EXPORT_C TBool TBtreeInlineIndexOrg::Delete(TAny *aNode,TInt aPos) const +// +// Delete the specified key and following child reference from the node +// Part of the contract is to garauntee that the entry is deleted, even if undeflowed +// + { + SNode* const pn=Node(aNode); + __ASSERT_DEBUG(aPosiHead.iCount,Panic(EBadEntryPos)); + + --pn->iHead.iCount; + TUint8* pe=Entry(pn,aPos)->iKey; + Mem::Copy(pe,pe+iEntrySize,(pn->iHead.iCount-aPos)*iEntrySize); + return pn->iHead.iCount>=iMaxEntries>>1; // underflow criterion + } + +EXPORT_C TBool TBtreeInlineIndexOrg::Redistribute(TAny *aLeftNode,TAny *aRightNode,const TDesC8& aPivot,TBtreePivot& aNewPivot) const + { + return DoRedistribute(aLeftNode,aRightNode,aPivot,aNewPivot)!=NULL; + } + +EXPORT_C void TBtreeInlineIndexOrg::Concatenate(TAny *aLeftNode,const TAny *aRightNode,const TDesC8& aPivot) const +// +// Join LeftNode and RightNode together in LeftNode +// contract says that it will fit +// + { + SNode* const pl=Node(aLeftNode); + const SNode* const pr=Node(aRightNode); + TInt rCount=pr->iHead.iCount; + TInt lCount=pl->iHead.iCount; + __ASSERT_DEBUG(lCount+rCount+1<=iMaxEntries,Panic(ECannotConcatenate)); + TInt pSize=aPivot.Size(); + __ASSERT_DEBUG(pSize<=KeySize(),Panic(EBadEntrySize)); + TUint8* pp=Mem::Copy(Entry(pl,lCount)->iKey,aPivot.Ptr(),pSize); + Mem::Copy(pp,pr->iEntries,rCount*iEntrySize+sizeof(TPageRef)); + pl->iHead.iCount+=rCount+1; + } + +EXPORT_C void TBtreeInlineIndexOrg::MakeRoot(TAny* aNode,TPageRef aChild) const + { + __ASSERT_DEBUG(Node(aNode)->iHead.iCount==0,Panic(ECannotMakeRoot)); + Entry(Node(aNode),0)->iChild=aChild; + } + +EXPORT_C TInt TBtreeInlineIndexOrg::LastEntry(const TAny* aNode) const + { + return Node(aNode)->iHead.iCount; + } + +EXPORT_C const TAny *TBtreeInlineIndexOrg::EntryPtr(const TAny* aNode,TInt aPos) const + { + __ASSERT_DEBUG(aPosiHead.iCount,Panic(EBadEntryPos)); + return Entry(Node(aNode),aPos)->iKey; + } + +EXPORT_C TPtrC8 TBtreeInlineIndexOrg::Entry(const TAny* aNode,TInt aPos) const + { + return TPtrC8((const TUint8*)EntryPtr(aNode,aPos),KeySize()); + } + +EXPORT_C TPageRef TBtreeInlineIndexOrg::ChildNode(const TAny* aNode,TInt aPos) const +// +// Entries are always aligned +// + { + __ASSERT_DEBUG(aPos<=Node(aNode)->iHead.iCount,Panic(EBadEntryPos)); + return Entry(Node(aNode),aPos)->iChild; + } +