ppPage = pTrunk;
pTrunk = null;
TRACE("ALLOCATE: %d trunk - %d free pages left\n", pPgno[0], n - 1);
} else if (k > usableSize / 4 - 2) {
/* Value of k is out of range. Database corruption */
throw new SqlJetException(SqlJetErrorCode.CORRUPT);
} else if (searchList && nearby == iTrunk) {
/*
* The list is being searched and this trunk page is the
* page to allocate, regardless of whether it has
* leaves.
*/
assert (pPgno[0] == iTrunk);
ppPage = pTrunk;
searchList = false;
pTrunk.pDbPage.write();
if (k == 0) {
if (pPrevTrunk == null) {
SqlJetUtility.memcpy(pPage1.aData, 32, pTrunk.aData, 0, 4);
} else {
SqlJetUtility.memcpy(pPrevTrunk.aData, 0, pTrunk.aData, 0, 4);
}
} else {
/*
* The trunk page is required by the caller but it
* contains pointers to free-list leaves. The first
* leaf becomes a trunk page in this case.
*/
SqlJetMemPage pNewTrunk;
int iNewTrunk = SqlJetUtility.get4byte(pTrunk.aData, 8);
pNewTrunk = getPage(iNewTrunk, false);
try {
pNewTrunk.pDbPage.write();
} catch (SqlJetException e) {
SqlJetMemPage.releasePage(pNewTrunk);
throw e;
}
SqlJetUtility.memcpy(pNewTrunk.aData, 0, pTrunk.aData, 0, 4);
SqlJetUtility.put4byte(pNewTrunk.aData, 4, k - 1);
SqlJetUtility.memcpy(pNewTrunk.aData, 8, pTrunk.aData, 12, (k - 1) * 4);
SqlJetMemPage.releasePage(pNewTrunk);
if (pPrevTrunk == null) {
SqlJetUtility.put4byte(pPage1.aData, 32, iNewTrunk);
} else {
pPrevTrunk.pDbPage.write();
SqlJetUtility.put4byte(pPrevTrunk.aData, 0, iNewTrunk);
}
}
pTrunk = null;
TRACE("ALLOCATE: %d trunk - %d free pages left\n", pPgno[0], n - 1);
} else {
/* Extract a leaf from the trunk */
int closest;
int iPage;
ISqlJetMemoryPointer aData = pTrunk.aData;
pTrunk.pDbPage.write();
if (nearby > 0) {
int i, dist;
closest = 0;
dist = SqlJetUtility.get4byte(aData, 8) - nearby;
if (dist < 0)
dist = -dist;
for (i = 1; i < k; i++) {
int d2 = SqlJetUtility.get4byte(aData, 8 + i * 4) - nearby;
if (d2 < 0)
d2 = -d2;
if (d2 < dist) {
closest = i;
dist = d2;
}
}
} else {
closest = 0;
}
iPage = SqlJetUtility.get4byte(aData, 8 + closest * 4);
if (!searchList || iPage == nearby) {
int nPage;
pPgno[0] = iPage;
nPage = getPageCount();
if (pPgno[0] > nPage) {
/* Free page off the end of the file */
throw new SqlJetException(SqlJetErrorCode.CORRUPT);
}
TRACE("ALLOCATE: %d was leaf %d of %d on trunk %d" + ": %d more free pages\n", pPgno[0],
closest + 1, k, pTrunk.pgno, n - 1);
if (closest < k - 1) {
SqlJetUtility.memcpy(aData, 8 + closest * 4, aData, 4 + k * 4, 4);
}
SqlJetUtility.put4byte(aData, 4, k - 1);
ppPage = getPage(pPgno[0], true);
ppPage.pDbPage.dontRollback();
try {
ppPage.pDbPage.write();
} catch (SqlJetException e) {
SqlJetMemPage.releasePage(ppPage);
}
searchList = false;
}
}
SqlJetMemPage.releasePage(pPrevTrunk);
pPrevTrunk = null;
} while (searchList);
} else {
/*
* There are no pages on the freelist, so create a new page at
* the end of the file
*/
int nPage = getPageCount();
pPgno[0] = nPage + 1;
if (autoVacuum && PTRMAP_ISPAGE(pPgno[0])) {
/*
* IfpPgno refers to a pointer-map page, allocate two new
* pages at the end of the file instead of one. The first
* allocated page becomes a new pointer-map page, the second
* is used by the caller.
*/
TRACE("ALLOCATE: %d from end of file (pointer-map page)\n", pPgno[0]);
assert (pPgno[0] != PENDING_BYTE_PAGE());
pPgno[0]++;
if (pPgno[0] == PENDING_BYTE_PAGE()) {
pPgno[0]++;
}
}
assert (pPgno[0] != PENDING_BYTE_PAGE());
ppPage = getPage(pPgno[0], false);
try {
ppPage.pDbPage.write();
} catch (SqlJetException e) {
SqlJetMemPage.releasePage(ppPage);
}
TRACE("ALLOCATE: %d from end of file\n", pPgno[0]);
}
assert (pPgno[0] != PENDING_BYTE_PAGE());
} finally {
// end_allocate_page:
SqlJetMemPage.releasePage(pTrunk);
SqlJetMemPage.releasePage(pPrevTrunk);
}
if (ppPage.pDbPage.getRefCount() > 1) {
SqlJetMemPage.releasePage(ppPage);
throw new SqlJetException(SqlJetErrorCode.CORRUPT);
}
ppPage.isInit = false;
return ppPage;
}