ntt = userHandle.getTransaction();
long lastPage; // last allocated page
long lastPreallocPage; // last pre-allcated page
long pageNumber; // the page number of the new page
PageKey pkey; // the identity of the new page
boolean reuse; // if true, we are trying to reuse a page
/* in case the page recommeded by allocPage is not committed yet, may
/* need to retry a couple of times */
boolean retry;
int numtries = 0;
long startSearch = lastAllocatedPage;
AllocPage allocPage = null; // the alloc page
BasePage page = null; // the new page
try
{
do
{
retry = false; // we don't expect we need to retry
synchronized(allocCache)
{
if (SanityManager.DEBUG)
{
SanityManager.ASSERT(
ntt.getId().equals(
allocHandle.getTransaction().getId()));
if (useNTT)
SanityManager.ASSERT(
!ntt.getId().equals(
userHandle.getTransaction().getId()));
}
/* find an allocation page that can handle adding a new
* page.
*
* allocPage is unlatched when the ntt commits. The new
* page is initialized by the ntt but the latch is
* transfered to the user transaction before the allocPage
* is unlatched. The allocPage latch prevents almost any
* other reader or writer from finding the new page until
* the ntt is committed and the new page is latched by the
* user transaction.
*
* (If the page is being reused, it is possible for another
* xact which kept a handle on the reused page to find the
* page during the transfer UT -> NTT. If this unlikely
* even occurs and the transfer fails [see code relating
* to transfer below], we retry from the beginning.)
*
* After the NTT commits a reader (getNextPageNumber) may
* get the page number of the newly allocated page and it
* will wait for the new page and latch it when the user
* transaction commits, aborts or unlatches the new page.
* Whether the user transaction commits or aborts, the new
* page stay allocated.
*
* RESOLVE: before NTT rolls back (or commits) the latch is
* released. To repopulate the allocation cache, need to
* get either the container lock on add page, or get a per
* allocation page lock.
*
* This blocks all page read (getPage) from accessing this
* alloc page in this container until the alloc page is
* unlatched. Those who already have a page handle into
* this container are unaffected.
*
* In other words, allocation blocks out reader (of any
* page that is managed by this alloc page) by the latch
* on the allocation page.
*
* Note that write page can proceed as usual.
*/
allocPage =
findAllocPageForAdd(allocHandle, ntt, startSearch);
allocCache.invalidate(allocPage, allocPage.getPageNumber());
}
if (SanityManager.DEBUG)
{
if (allocPage == null)
allocCache.dumpAllocationCache();
SanityManager.ASSERT(allocPage != null,
"findAllocPageForAdd returned a null alloc page");
}
//
// get the next free page's number.
// for case 1, page number > lastPreallocPage
// for case 2, page number <= lastPage
// for case 3, lastPage < page number <= lastPreallocPage
//
pageNumber = allocPage.nextFreePageNumber(startSearch);
// need to distinguish between the following 3 cases:
// 1) the page has not been allocate or initalized.
// Create it in the page cache and sync it to disk.
// 2) the page is being re-allocated.
// We need to read it in to re-initialize it
// 3) the page has been preallocated.
// Create it in the page cache and don't sync it to disk
//
// first find out the current last initialized page and
// preallocated page before the new page is added
lastPage = allocPage.getLastPagenum();
lastPreallocPage = allocPage.getLastPreallocPagenum();
reuse = pageNumber <= lastPage;
// no address translation necessary
pkey = new PageKey(identity, pageNumber);
if (reuse)
{
// if re-useing a page, make sure the deallocLock on the new