#At file:///G:/bzr/mysql-6.0-falcon-team/ based on revid:vvaintroub@stripped
2981 Vladislav Vaintroub 2009-01-28
Bug #40946: assertion in PageInventoryPage::allocPage in recovery.
Reason :
Creation of section pages was not always logged. Hence, not all section pages were redone by recovery. During recovery a section root was missing and Section::getSectionPage was trying to allocate a missing root. This caused the assertion in bug.
Solution : always log section pages and rebuild them on recovery.
- This patch also simplified the redo logic for section pages - no more guessing and trying to save information in it. The page should be clean after creation.
- This patch also removed another "allocate on demand" code in getSectionRoot() - it should not be necessary since the page is either already in the tablespace (written by last checkpoint), or exists as in log record and will be created in recovery prior to first use.
modified:
storage/falcon/Section.cpp
=== modified file 'storage/falcon/Section.cpp'
--- a/storage/falcon/Section.cpp 2008-06-17 17:41:54 +0000
+++ b/storage/falcon/Section.cpp 2009-01-28 11:01:08 +0000
@@ -164,6 +164,10 @@ void Section::createSection(Dbb *dbb, in
if (sections->pages [slot] == 0)
{
+ // If we're in recovery and slot is empty, something went wrong , page must have
+ // been logged and rebuilt already (every allocation is redone)
+ ASSERT (!(dbb->serialLog && dbb->serialLog->recovering));
+
sectionsBdb->mark(transId);
Bdb *sectionBdb = dbb->allocPage(PAGE_sections, transId);
BDB_HISTORY(sectionBdb);
@@ -172,6 +176,11 @@ void Section::createSection(Dbb *dbb, in
sections->pages [slot] = sectionBdb->pageNumber;
SectionPage *page = (SectionPage*) sectionBdb->buffer;
page->section = sectionId;
+
+ // Log allocated page
+ dbb->serialLog->logControl->sectionPage.append(dbb, transId, SECTION_ROOT,
+ sectionBdb->pageNumber, slot, sectionId, 0, 0);
+
sectionBdb->release(REL_HISTORY);
}
@@ -1196,38 +1205,25 @@ bool Section::isCleanupRequired()
void Section::redoSectionPage(Dbb *dbb, int32 parentPage, int32 pageNumber, int slot, int sectionId, int sequence, int level)
{
- Bdb *bdb = dbb->fetchPage (parentPage, PAGE_any, Exclusive);
+ Bdb *bdb = dbb->fetchPage (parentPage, PAGE_sections, Exclusive);
BDB_HISTORY(bdb);
SectionPage *page = (SectionPage*) bdb->buffer;
- // Unless parent page is already leaf, probe and if necessary rebuild section page
- //if (pageNumber && (page->level > 0 || parentPage == SECTION_ROOT))
- if (pageNumber && (page->level > 0 || page->section == -1))
- {
- Bdb *sectionBdb = dbb->fakePage(pageNumber, PAGE_any, 0);
- BDB_HISTORY(bdb);
- SectionPage *sectionPage = (SectionPage*) sectionBdb->buffer;
-
- if (!dbb->trialRead(sectionBdb) ||
- sectionPage->pageType != PAGE_sections ||
- sectionPage->section != sectionId ||
- sectionPage->sequence != sequence ||
- sectionPage->level != level)
- {
- memset(sectionPage, 0, dbb->pageSize);
- //sectionPage->pageType = PAGE_sections;
- sectionBdb->setPageHeader(PAGE_sections);
- sectionPage->section = sectionId;
- sectionPage->sequence = sequence;
- sectionPage->level = level;
- }
+ Bdb *sectionBdb = dbb->fakePage(pageNumber, PAGE_any, 0);
+ BDB_HISTORY(bdb);
+ SectionPage *sectionPage = (SectionPage*) sectionBdb->buffer;
+ memset(sectionPage, 0, dbb->pageSize);
+ sectionBdb->setPageHeader(PAGE_sections);
+ sectionPage->section = sectionId;
+ sectionPage->sequence = sequence;
+ sectionPage->level = level;
- PageInventoryPage::markPageInUse(dbb, pageNumber, NO_TRANSACTION);
- sectionBdb->release(REL_HISTORY);
- }
+ PageInventoryPage::markPageInUse(dbb, pageNumber, NO_TRANSACTION);
+ sectionBdb->release(REL_HISTORY);
- // Now try to store it in the right place
+
+ // Now store it in the right place
if (page->pages[slot] != pageNumber)
{
@@ -1243,33 +1239,9 @@ int32 Section::getSectionRoot()
Bdb *bdb = getSectionPage(dbb, SECTION_ROOT, sectionId / dbb->pagesPerSection, Shared, NO_TRANSACTION);
BDB_HISTORY(bdb);
SectionPage *sectionPage = (SectionPage*) bdb->buffer;
- root = sectionPage->pages[sectionId % dbb->pagesPerSection];
+ int slot = sectionId % dbb->pagesPerSection;
+ root = sectionPage->pages[slot];
bdb->release(REL_HISTORY);
-
- if (root == 0)
- {
- if (!dbb->serialLog->recovering)
- throw SQLError(DATABASE_DAMAGED, "Missing section root for section %d/%d\n", sectionId, dbb->tableSpaceId);
-
- // Missing root page -- make a new one
-
- Bdb *sectionBdb = dbb->allocPage(PAGE_sections, NO_TRANSACTION);
- BDB_HISTORY(sectionBdb);
- root = sectionBdb->pageNumber;
- SectionPage *page = (SectionPage*) sectionBdb->buffer;
- page->section = sectionId;
- sectionBdb->release(REL_HISTORY);
-
- // Register new root page
-
- bdb = getSectionPage(dbb, SECTION_ROOT, sectionId / dbb->pagesPerSection, Exclusive, NO_TRANSACTION);
- BDB_HISTORY(bdb);
- sectionPage = (SectionPage*) bdb->buffer;
- sectionPage->pages[sectionId % dbb->pagesPerSection] = root;
- bdb->release(REL_HISTORY);
- }
-
-
return root;
}