Skip to content

Commit 64e96a6

Browse files
committed
[bugfix] Drop the free page list on recovery, as the free page list does not seem to be crash-recovery safe
1 parent db67b28 commit 64e96a6

File tree

3 files changed

+51
-16
lines changed

3 files changed

+51
-16
lines changed

src/org/exist/storage/btree/Paged.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,17 +453,47 @@ protected final void unlinkPages(final long pageNum) throws IOException {
453453
unlinkPages(getPage(pageNum));
454454
}
455455

456+
/**
457+
* Clears the {@link FileHeader#firstFreePage} and
458+
* {@link FileHeader#lastFreePage}.
459+
*
460+
* This is needed in recovery, as the free page list
461+
* may have become corrupted.
462+
*
463+
* Unfortunately this means we loose some space
464+
* that we will never recover, but it does mean
465+
* we are more likely to correctly recover.
466+
*/
467+
protected void dropFreePageList() throws IOException {
468+
boolean updated = false;
469+
if (fileHeader.getFirstFreePage() != Page.NO_PAGE) {
470+
fileHeader.setFirstFreePage(Page.NO_PAGE);
471+
updated = true;
472+
}
473+
if (fileHeader.getLastFreePage() != Page.NO_PAGE) {
474+
fileHeader.setLastFreePage(Page.NO_PAGE);
475+
updated = true;
476+
}
477+
478+
if (updated) {
479+
fileHeader.write();
480+
}
481+
}
482+
456483
protected void reuseDeleted(final Page page) throws IOException {
457484
if (page != null && fileHeader.getFirstFreePage() != Page.NO_PAGE) {
485+
458486
long firstFreePageNum = fileHeader.getFirstFreePage();
459487
if (firstFreePageNum == page.pageNum) {
460488
fileHeader.setFirstFreePage(page.header.getNextPage());
461489
fileHeader.write();
462490
return;
463491
}
492+
464493
Page firstFreePage = getPage(firstFreePageNum);
465494
firstFreePage.read();
466495
firstFreePageNum = firstFreePage.header.getNextPage();
496+
467497
while (firstFreePageNum != Page.NO_PAGE) {
468498
if (firstFreePageNum == page.pageNum) {
469499
firstFreePage.header.setNextPage(page.header.getNextPage());

src/org/exist/storage/dom/DOMFile.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,7 +2188,7 @@ protected void redoCreatePage(final CreatePageLoggable loggable) {
21882188
final DOMFilePageHeader newPageHeader = newPage.getPageHeader();
21892189
if (newPageHeader.getLsn() == Lsn.LSN_INVALID || requiresRedo(loggable, newPage)) {
21902190
try {
2191-
reuseDeleted(newPage.page);
2191+
dropFreePageList();
21922192
newPageHeader.setStatus(RECORD);
21932193
newPageHeader.setDataLength(0);
21942194
newPageHeader.setNextTupleID(ItemId.UNKNOWN_ID);
@@ -2458,7 +2458,7 @@ protected void undoRemoveEmptyPage(final RemoveEmptyPageLoggable loggable) {
24582458
try {
24592459
final DOMPage newPage = getDOMPage(loggable.pageNum);
24602460
final DOMFilePageHeader newPageHeader = newPage.getPageHeader();
2461-
reuseDeleted(newPage.page);
2461+
dropFreePageList();
24622462
if (loggable.prevPage == Page.NO_PAGE) {
24632463
newPageHeader.setPrevDataPage(Page.NO_PAGE);
24642464
} else {
@@ -2514,7 +2514,7 @@ protected void undoRemovePage(final RemovePageLoggable loggable) {
25142514
try {
25152515
final DOMPage page = getDOMPage(loggable.pageNum);
25162516
final DOMFilePageHeader pageHeader = page.getPageHeader();
2517-
reuseDeleted(page.page);
2517+
dropFreePageList();
25182518
pageHeader.setStatus(RECORD);
25192519
pageHeader.setNextDataPage(loggable.nextPage);
25202520
pageHeader.setPrevDataPage(loggable.prevPage);
@@ -2533,12 +2533,12 @@ protected void undoRemovePage(final RemovePageLoggable loggable) {
25332533

25342534
protected void redoWriteOverflow(final WriteOverflowPageLoggable loggable) {
25352535
try {
2536-
final Page page = getPage(loggable.pageNum);
2537-
page.read();
2536+
final Page page = getPage(loggable.pageNum);
25382537
final PageHeader pageHeader = page.getPageHeader();
2539-
reuseDeleted(page);
2540-
pageHeader.setStatus(RECORD);
25412538
if (pageHeader.getLsn() != Lsn.LSN_INVALID && requiresRedo(loggable, page)) {
2539+
2540+
dropFreePageList();
2541+
pageHeader.setStatus(RECORD);
25422542
if (loggable.nextPage == Page.NO_PAGE) {
25432543
pageHeader.setNextPage(Page.NO_PAGE);
25442544
} else {
@@ -2547,9 +2547,10 @@ protected void redoWriteOverflow(final WriteOverflowPageLoggable loggable) {
25472547
pageHeader.setLsn(loggable.getLsn());
25482548
writeValue(page, loggable.value);
25492549
}
2550+
25502551
} catch (final IOException e) {
25512552
LOG.warn("Failed to redo " + loggable.dump() + ": " + e.getMessage(), e);
2552-
//TODO : throw exception ? -pb
2553+
//TODO : throw exception ? -pb
25532554
}
25542555
}
25552556

@@ -2583,7 +2584,7 @@ protected void undoRemoveOverflow(final RemoveOverflowLoggable loggable) {
25832584
final Page page = getPage(loggable.pageNum);
25842585
page.read();
25852586
final PageHeader pageHeader = page.getPageHeader();
2586-
reuseDeleted(page);
2587+
dropFreePageList();
25872588
pageHeader.setStatus(RECORD);
25882589
if (loggable.nextPage == Page.NO_PAGE) {
25892590
pageHeader.setNextPage(Page.NO_PAGE);

src/org/exist/storage/index/BFile.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ protected void undoStoreValue(final StoreValueLoggable loggable) {
10311031
}
10321032

10331033
protected void redoCreatePage(final CreatePageLoggable loggable) {
1034-
createPageHelper(loggable, loggable.newPage);
1034+
createPageHelper(loggable, loggable.newPage, false);
10351035
}
10361036

10371037
protected void undoCreatePage(final CreatePageLoggable loggable) {
@@ -1105,7 +1105,7 @@ protected void redoRemovePage(final RemoveEmptyPageLoggable loggable) {
11051105
}
11061106

11071107
protected void undoRemovePage(final RemoveEmptyPageLoggable loggable) {
1108-
createPageHelper(loggable, loggable.page);
1108+
createPageHelper(loggable, loggable.page, false);
11091109
}
11101110

11111111
protected void redoCreateOverflow(final OverflowCreateLoggable loggable) {
@@ -1115,7 +1115,7 @@ protected void redoCreateOverflow(final OverflowCreateLoggable loggable) {
11151115
final Page page = getPage(loggable.pageNum);
11161116
byte[] data = page.read();
11171117
if (page.getPageHeader().getLsn() == Lsn.LSN_INVALID || requiresRedo(loggable, page)) {
1118-
reuseDeleted(page);
1118+
dropFreePageList();
11191119
final BFilePageHeader ph = (BFilePageHeader) page.getPageHeader();
11201120
ph.setStatus(MULTI_PAGE);
11211121
ph.setNextInChain(0L);
@@ -1150,7 +1150,7 @@ protected void undoCreateOverflow(final OverflowCreateLoggable loggable) {
11501150
}
11511151

11521152
protected void redoCreateOverflowPage(final OverflowCreatePageLoggable loggable) {
1153-
createPageHelper(loggable, loggable.newPage);
1153+
createPageHelper(loggable, loggable.newPage, false);
11541154
if (loggable.prevPage != Page.NO_PAGE) {
11551155
try {
11561156
final SinglePage page = getSinglePageForRedo(null, loggable.prevPage);
@@ -1297,7 +1297,7 @@ protected void redoRemoveOverflow(final OverflowRemoveLoggable loggable) {
12971297
}
12981298

12991299
protected void undoRemoveOverflow(final OverflowRemoveLoggable loggable) {
1300-
final DataPage page = createPageHelper(loggable, loggable.pageNum);
1300+
final DataPage page = createPageHelper(loggable, loggable.pageNum, false);
13011301
final BFilePageHeader ph = page.getPageHeader();
13021302
ph.setStatus(loggable.status);
13031303
ph.setDataLength(loggable.length);
@@ -1378,14 +1378,18 @@ private void removeValueHelper(final Loggable loggable, final short tid, final S
13781378
}
13791379
}
13801380

1381-
private DataPage createPageHelper(final Loggable loggable, final long newPage) {
1381+
private DataPage createPageHelper(final Loggable loggable, final long newPage, final boolean reuseDeleted) {
13821382
try {
13831383
DataPage dp = (DataPage) dataCache.get(newPage);
13841384
if (dp == null) {
13851385
final Page page = getPage(newPage);
13861386
byte[] data = page.read();
13871387
if (page.getPageHeader().getLsn() == Lsn.LSN_INVALID || (loggable != null && requiresRedo(loggable, page)) ) {
1388-
reuseDeleted(page);
1388+
if (reuseDeleted) {
1389+
reuseDeleted(page);
1390+
} else {
1391+
dropFreePageList();
1392+
}
13891393
final BFilePageHeader ph = (BFilePageHeader) page.getPageHeader();
13901394
ph.setStatus(RECORD);
13911395
ph.setDataLength(0);

0 commit comments

Comments
 (0)