summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAli Akhtarzada <ali.akhtarzada@nokia.com>2012-05-15 17:30:40 +0200
committerQt by Nokia <qt-info@nokia.com>2012-05-16 16:45:33 +0200
commit37693037e7ec7783fd6cd23e085546bad84e2d7c (patch)
treefba5c3f86ebe56ddbaa2ac56eaad24d24f6c8265
parentddf6ac47ec6e1ab54b66f18c18cd6933d292c004 (diff)
Persist collectible page list after closing hbtree
Collectible pages were being lost. Also added more to the markerOnReopen test with explanations on what's going on. Change-Id: I9f3b82c9aac428fb509fccc310c8bbba39975e01 Reviewed-by: Jamey Hicks <jamey.hicks@nokia.com> Reviewed-by: Denis Dzyubenko <denis.dzyubenko@nokia.com>
-rw-r--r--src/hbtree/hbtree.cpp213
-rw-r--r--src/hbtree/hbtree_p.h8
-rw-r--r--tests/auto/hbtree/main.cpp93
3 files changed, 190 insertions, 124 deletions
diff --git a/src/hbtree/hbtree.cpp b/src/hbtree/hbtree.cpp
index 0fc0510..45e8959 100644
--- a/src/hbtree/hbtree.cpp
+++ b/src/hbtree/hbtree.cpp
@@ -139,16 +139,20 @@ bool HBtreePrivate::open(int fd)
// Write sync markers
MarkerPage synced0(1);
- MarkerPage synced1(2);
- synced0.meta.size = synced1.meta.size = initSize;
+ synced0.meta.size = initSize;
- if (!writeMarker(&synced0)) {
- HBTREE_ERROR("failed to write sync0");
+ QByteArray buffer(spec_.pageSize, (char)0);
+ memcpy(buffer.data(), &synced0.info, sizeof(PageInfo));
+ memcpy(buffer.data() + sizeof(PageInfo), &synced0.meta, sizeof(MarkerPage::Meta));
+
+ if (!writePage(&buffer)) {
+ HBTREE_ERROR("failed to write sync marker 0");
return false;
}
- if (!writeMarker(&synced1)) {
- HBTREE_ERROR("failed to write sync1");
+ serializePageNumber(2, &buffer);
+ if (!writePage(&buffer)) {
+ HBTREE_ERROR("failed to write sync marker 1");
return false;
}
@@ -169,7 +173,8 @@ bool HBtreePrivate::open(int fd)
}
// Get synced marker
- if (!readSyncedMarker(&marker_)) {
+ QList<quint32> overflowPages;
+ if (!readSyncedMarker(&marker_, &overflowPages)) {
HBTREE_ERROR("sync markers invalid.");
return false;
}
@@ -191,6 +196,10 @@ bool HBtreePrivate::open(int fd)
marker_.residueHistory.clear();
marker_.info.upperOffset = 0;
+ // This has to be done after syncing as well
+ foreach (quint32 pgno, overflowPages)
+ collectiblePages_.remove(pgno);
+
} else {
size_ = marker_.meta.size;
}
@@ -432,6 +441,14 @@ void HBtreePrivate::serializeChecksum(quint32 checksum, QByteArray *buffer) cons
memcpy(buffer->data() + PageInfo::OFFSETOF_CHECKSUM, &checksum, sizeof(quint32));
}
+void HBtreePrivate::serializePageNumber(quint32 pgno, QByteArray *buffer) const
+{
+ HBTREE_ASSERT(spec_.pageSize >= HBTREE_DEFAULT_PAGE_SIZE)(spec_)(HBTREE_DEFAULT_PAGE_SIZE);
+ HBTREE_ASSERT(buffer->size() == (int)spec_.pageSize)(buffer->size())(spec_);
+ HBTREE_ASSERT(buffer->isDetached());
+ memcpy(buffer->data() + PageInfo::OFFSETOF_NUMBER, &pgno, sizeof(quint32));
+}
+
quint32 HBtreePrivate::deserializePageNumber(const QByteArray &buffer) const
{
HBTREE_ASSERT(spec_.pageSize >= HBTREE_DEFAULT_PAGE_SIZE)(spec_)(HBTREE_DEFAULT_PAGE_SIZE);
@@ -450,82 +467,10 @@ quint32 HBtreePrivate::deserializePageType(const QByteArray &buffer) const
return pageType;
}
-bool HBtreePrivate::writeMarker(HBtreePrivate::MarkerPage *page)
-{
- HBTREE_ASSERT(page);
- HBTREE_ASSERT(spec_.pageSize >= HBTREE_DEFAULT_PAGE_SIZE)(spec_)(HBTREE_DEFAULT_PAGE_SIZE);
-
- MarkerPage &mp = *page;
-
- mp.info.lowerOffset = 0;
- mp.info.upperOffset = mp.residueHistory.size() * sizeof(quint32);
-
- if (mp.info.number != 1)
- mp.residueHistory.clear();
-
- bool useOverflow = mp.info.upperOffset > capacity(&mp);
- if (useOverflow)
- mp.meta.flags |= MarkerPage::DataOnOverflow;
-
- QByteArray buffer(spec_.pageSize, (char)0);
-
- if (mp.info.hasPayload()) {
- QByteArray extra;
- char *ptr = buffer.data() + sizeof(PageInfo) + sizeof(MarkerPage::Meta);
-
- if (useOverflow && mp.info.number == 1) {
- extra.fill((char)0, mp.info.upperOffset);
- ptr = extra.data();
- }
-
- foreach (quint32 pgno, mp.residueHistory) {
- memcpy(ptr, &pgno, sizeof(quint32));
- ptr += sizeof(quint32);
- }
-
- if (useOverflow) {
- HBTREE_ASSERT(dirtyPages_.isEmpty())(dirtyPages_)(mp);
- NodeHeader node;
- // Sync marker 2 does not need to rewrite overflow pages if sync 1 did it.
- node.context.overflowPage = mp.info.number == 1 ? putDataOnOverflow(extra) : mp.overflowPage;
- memcpy(buffer.data() + sizeof(PageInfo) + sizeof(MarkerPage::Meta), &node, sizeof(NodeHeader));
- PageMap::const_iterator it = dirtyPages_.constBegin();
- while (it != dirtyPages_.constEnd()) {
- HBTREE_ASSERT(it.value()->info.type == PageInfo::Overflow)(*it.value())(mp);
- pageBuffer_ = serializePage(*it.value());
- if (pageBuffer_.isEmpty()) {
- HBTREE_DEBUG("failed to serialize" << mp.info);
- return false;
- }
- if (!writePage(&pageBuffer_)) {
- HBTREE_DEBUG("failed to write" << mp.info);
- return false;
- }
- ++it;
- }
- dirtyPages_.clear();
- mp.overflowPage = node.context.overflowPage;
- }
- }
-
- // If we set the size manually, trust it.
- if (!mp.meta.size)
- size_ = mp.meta.size = lseek(fd_, 0, SEEK_END);
-
- memcpy(buffer.data(), &mp.info, sizeof(PageInfo));
- memcpy(buffer.data() + sizeof(PageInfo), &mp.meta, sizeof(MarkerPage::Meta));
-
- HBTREE_DEBUG("writing" << mp);
-
- if (!writePage(&buffer))
- return false;
-
- return true;
-}
-
-bool HBtreePrivate::readMarker(quint32 pgno, HBtreePrivate::MarkerPage *markerOut)
+bool HBtreePrivate::readMarker(quint32 pgno, HBtreePrivate::MarkerPage *markerOut, QList<quint32> *overflowPages)
{
HBTREE_ASSERT(markerOut)(pgno);
+ HBTREE_ASSERT(overflowPages)(pgno);
HBTREE_ASSERT(spec_.pageSize >= HBTREE_DEFAULT_PAGE_SIZE)(spec_)(HBTREE_DEFAULT_PAGE_SIZE)(pgno);
HBTREE_ASSERT(pgno == 1 || pgno == 2)(pgno);
@@ -547,7 +492,7 @@ bool HBtreePrivate::readMarker(quint32 pgno, HBtreePrivate::MarkerPage *markerOu
NodeHeader node;
memcpy(&node, pageBuffer_.constData() + sizeof(PageInfo) + sizeof(MarkerPage::Meta), sizeof(NodeHeader));
mp.overflowPage = node.context.overflowPage;
- getOverflowData(node.context.overflowPage, &overflowData);
+ walkOverflowPages(node.context.overflowPage, &overflowData, overflowPages);
ptr = overflowData.constData();
}
@@ -805,6 +750,7 @@ bool HBtreePrivate::writePage(QByteArray *buffer) const
bool HBtreePrivate::sync()
{
+ HBTREE_ASSERT(spec_.pageSize >= HBTREE_DEFAULT_PAGE_SIZE)(spec_)(HBTREE_DEFAULT_PAGE_SIZE);
HBTREE_ASSERT(verifyIntegrity(&marker_))(marker_);
HBTREE_DEBUG("syncing" << marker_);
@@ -817,16 +763,69 @@ bool HBtreePrivate::sync()
}
MarkerPage synced0(1);
- MarkerPage synced1(2);
-
- copy(marker_, &synced0);
if (fsync(fd_) != 0) {
HBTREE_ERROR("failed to sync data");
return false;
}
- if (!writeMarker(&synced0)) {
+ // Write marker 1
+ copy(marker_, &synced0);
+
+ synced0.residueHistory.unite(collectiblePages_);
+ synced0.info.lowerOffset = 0;
+ synced0.info.upperOffset = synced0.residueHistory.size() * sizeof(quint32);
+
+ QByteArray buffer(spec_.pageSize, (char)0);
+ QList<quint32> overflowPages;
+ bool useOverflow = synced0.info.upperOffset > capacity(&synced0);
+
+ if (useOverflow)
+ synced0.meta.flags |= MarkerPage::DataOnOverflow;
+
+ if (synced0.info.hasPayload()) {
+ QByteArray extra;
+ char *ptr = buffer.data() + sizeof(PageInfo) + sizeof(MarkerPage::Meta);
+ if (useOverflow) {
+ extra.fill((char)0, synced0.info.upperOffset);
+ ptr = extra.data();
+ }
+ foreach (quint32 pgno, synced0.residueHistory) {
+ memcpy(ptr, &pgno, sizeof(quint32));
+ ptr += sizeof(quint32);
+ }
+ if (useOverflow) {
+ HBTREE_ASSERT(dirtyPages_.isEmpty())(dirtyPages_)(synced0);
+ NodeHeader node;
+ node.context.overflowPage = putDataOnOverflow(extra, &overflowPages);
+ memcpy(buffer.data() + sizeof(PageInfo) + sizeof(MarkerPage::Meta), &node, sizeof(NodeHeader));
+ PageMap::const_iterator it = dirtyPages_.constBegin();
+ while (it != dirtyPages_.constEnd()) {
+ HBTREE_ASSERT(it.value()->info.type == PageInfo::Overflow)(*it.value())(synced0);
+ pageBuffer_ = serializePage(*it.value());
+ if (pageBuffer_.isEmpty()) {
+ HBTREE_DEBUG("failed to serialize" << synced0.info);
+ return false;
+ }
+ if (!writePage(&pageBuffer_)) {
+ HBTREE_DEBUG("failed to write" << synced0.info);
+ return false;
+ }
+ it.value()->dirty = false;
+ cacheDelete(it.value()->info.number);
+ ++it;
+ }
+ dirtyPages_.clear();
+ synced0.overflowPage = node.context.overflowPage;
+ }
+ }
+
+ synced0.meta.size = lseek(fd_, 0, SEEK_END);
+
+ memcpy(buffer.data(), &synced0.info, sizeof(PageInfo));
+ memcpy(buffer.data() + sizeof(PageInfo), &synced0.meta, sizeof(MarkerPage::Meta));
+
+ if (!writePage(&buffer)) {
HBTREE_ERROR("failed to write sync marker 0");
return false;
}
@@ -842,42 +841,48 @@ bool HBtreePrivate::sync()
collectiblePages_.insert(pgno);
}
- lastSyncedId_++;
-
copy(synced0, &synced_);
- // Collect residue pages
+ lastSyncedId_++;
collectiblePages_.unite(marker_.residueHistory);
marker_.residueHistory.clear();
marker_.info.upperOffset = 0;
residueHistory_.clear();
+ size_ = synced0.meta.size;
+ // Remove the overflow pages from the collectible list. They may have been used
+ // if we had to put the residue pages on overflow pages.
+ // This has to be done on open as well.
+ foreach (quint32 pgno, overflowPages)
+ collectiblePages_.remove(pgno);
- HBTREE_DEBUG("synced marker and upped sync id to" << lastSyncedId_);
-
- if (fsync(fd_) != 0)
+ if (fsync(fd_) != 0) {
+ HBTREE_DEBUG("wrote but failed to sync marker 0");
return false;
+ }
+
+ HBTREE_DEBUG("synced marker 0 and upped sync id to" << lastSyncedId_);
Q_Q(HBtree);
q->stats_.numSyncs++;
- copy(synced0, &synced1);
-
- if (!writeMarker(&synced1)) {
- HBTREE_ERROR("failed to write sync marker 0");
+ // Just change page number and write second marker
+ serializePageNumber(2, &buffer);
+ if (!writePage(&buffer)) {
+ HBTREE_ERROR("failed to write sync marker 1");
return false;
}
- HBTREE_VERBOSE("synced marker 2");
+ HBTREE_VERBOSE("synced marker 1");
return true;
}
-bool HBtreePrivate::readSyncedMarker(HBtreePrivate::MarkerPage *markerOut)
+bool HBtreePrivate::readSyncedMarker(HBtreePrivate::MarkerPage *markerOut, QList<quint32> *overflowPages)
{
HBTREE_ASSERT(markerOut);
- if (!readMarker(1, markerOut)) {
+ if (!readMarker(1, markerOut, overflowPages)) {
HBTREE_DEBUG("synced marker 1 invalid. Checking synced marker 2.");
- if (!readMarker(2, markerOut)) {
+ if (!readMarker(2, markerOut, overflowPages)) {
HBTREE_DEBUG("sync markers both invalid.");
return false;
}
@@ -1358,12 +1363,14 @@ HBtreePrivate::NodePage *HBtreePrivate::touchNodePage(HBtreePrivate::NodePage *p
return touched;
}
-quint32 HBtreePrivate::putDataOnOverflow(const QByteArray &value)
+quint32 HBtreePrivate::putDataOnOverflow(const QByteArray &value, QList<quint32> *pagesUsed)
{
HBTREE_DEBUG("putting data on overflow page");
int sizePut = 0;
quint32 overflowPageNumber = PageInfo::INVALID_PAGE;
OverflowPage *prevPage = 0;
+ if (pagesUsed)
+ pagesUsed->clear();
while (sizePut < value.size()) {
OverflowPage *overflowPage = static_cast<OverflowPage *>(newPage(PageInfo::Overflow));
if (overflowPageNumber == PageInfo::INVALID_PAGE)
@@ -1372,6 +1379,8 @@ quint32 HBtreePrivate::putDataOnOverflow(const QByteArray &value)
HBTREE_DEBUG("putting" << sizeToPut << "bytes @ offset" << sizePut);
overflowPage->data.resize(sizeToPut);
memcpy(overflowPage->data.data(), value.constData() + sizePut, sizeToPut);
+ if (pagesUsed)
+ pagesUsed->append(overflowPage->info.number);
if (prevPage)
prevPage->nextPage = overflowPage->info.number;
overflowPage->info.lowerOffset = (quint16)sizeToPut; // put it here too for quicker checksum checking
@@ -2732,7 +2741,7 @@ bool HBtreePrivate::verifyIntegrity(const HBtreePrivate::Page *pPage) const
if (page.info.type == PageInfo::Marker) {
const MarkerPage &mp = static_cast<const MarkerPage &>(page);
CHECK_TRUE_X(mp.info.number == marker_.info.number, (marker_.info.number)(mp.info.number));
- CHECK_TRUE_X(mp.info.upperOffset == mp.residueHistory.size() * sizeof(quint32), (mp.residueHistory.size()));
+ CHECK_TRUE_X(mp.info.upperOffset == mp.residueHistory.size() * sizeof(quint32), (mp.residueHistory.size())(mp.info.upperOffset / sizeof(quint32)));
CHECK_TRUE_X(mp.meta.size <= size_, (size_));
CHECK_TRUE_X(mp.meta.syncId == lastSyncedId_ || mp.meta.syncId == (lastSyncedId_ + 1), (lastSyncedId_));
//if (mp->meta.syncedRevision == lastSyncedRevision_) // we just synced
diff --git a/src/hbtree/hbtree_p.h b/src/hbtree/hbtree_p.h
index 32516ff..98707dc 100644
--- a/src/hbtree/hbtree_p.h
+++ b/src/hbtree/hbtree_p.h
@@ -289,11 +289,11 @@ public:
bool serializeAndWrite(const Page &page) const;
void serializeChecksum(quint32 checksum, QByteArray *buffer) const;
+ void serializePageNumber(quint32 pgno, QByteArray *buffer) const;
quint32 deserializePageNumber(const QByteArray &buffer) const;
quint32 deserializePageType(const QByteArray &buffer) const;
- bool writeMarker(MarkerPage *page);
- bool readMarker(quint32 pgno, MarkerPage *markerOut);
+ bool readMarker(quint32 pgno, MarkerPage *markerOut, QList<quint32> *overflowPages);
NodePage deserializeNodePage(const QByteArray &buffer) const;
QByteArray serializeNodePage(const NodePage &page) const;
@@ -312,7 +312,7 @@ public:
bool commit(HBtreeTransaction *transaction, quint64 tag);
void abort(HBtreeTransaction *transaction);
bool sync();
- bool readSyncedMarker(MarkerPage *markerOut);
+ bool readSyncedMarker(MarkerPage *markerOut, QList<quint32> *overflowPages);
bool rollback();
Page *newPage(PageInfo::Type type);
@@ -320,7 +320,7 @@ public:
void deletePage(Page *page) const;
void destructPage(Page *page) const;
NodePage *touchNodePage(NodePage *page);
- quint32 putDataOnOverflow(const QByteArray &value);
+ quint32 putDataOnOverflow(const QByteArray &value, QList<quint32> *pagesUsed = NULL);
QByteArray getDataFromNode(const NodeValue &nval);
bool walkOverflowPages(quint32 startPage, QByteArray *data, QList<quint32> *pages);
bool getOverflowData(quint32 startPage, QByteArray *data);
diff --git a/tests/auto/hbtree/main.cpp b/tests/auto/hbtree/main.cpp
index 94acb4a..912aa3f 100644
--- a/tests/auto/hbtree/main.cpp
+++ b/tests/auto/hbtree/main.cpp
@@ -1155,7 +1155,7 @@ void TestHBtree::addDeleteNodes()
QCOMPARE(numItems - i - 1, db->stats().numEntries);
}
- for (int i = 0; i < numItems; ++i) {
+ for (int i = 0; i < 1; ++i) {
HBtreeTransaction *transaction = db->beginTransaction(HBtreeTransaction::ReadOnly);
QVERIFY(transaction);
QCOMPARE(transaction->get(QByteArray::number(randomize ? numTable[i] : i)), QByteArray());
@@ -2353,8 +2353,10 @@ void TestHBtree::cursors()
void TestHBtree::markerOnReopen_data()
{
QTest::addColumn<quint32>("numCommits");
- QTest::newRow("Even commits") << 4u;
- QTest::newRow("Odd Commits") << 5u;
+ // The test below is made for 4 and 5 commits respectively. Changing the number of commits requires
+ // changing all the verifications in the test.
+ QTest::newRow("Even test") << 4u;
+ QTest::newRow("Odd test") << 5u;
}
void TestHBtree::markerOnReopen()
@@ -2370,53 +2372,108 @@ void TestHBtree::markerOnReopen()
QVERIFY(txn->commit(i));
}
+ /* What happens to the pages on the commit rounds:
+ * commit 1: Collectible(empty). Root invalid -> create Page 3. Put on page 3. History(empty). Root = 3.
+ * commit 2: Collectible(empty). Root 3 -> touch to Page 4. Put on Page 4. History(3). Commit chain is 1 so does not put 3 in collectible. Root = 4.
+ * commit 3: Collectible(empty). Root 4 -> touch to Page 5. Put on Page 5. History(4, 3). Commit chain is 1 -> leave Page 4, put 3 in collectible. Root = 5.
+ * commit 4: Collectible(3). Root 5 -> touch to Page 3. Put on Page 3. History(5, 4). Commit chain is 1 -> leave page 5, put 4 in collectible. Root = 3.
+ * commit 5: Collectible(4). Root 3 -> touch to Page 4. Put on page 4. History(3, 5). Commit chain is 1 -> leave Page 3, put 5 in collectible. Root = 4.
+ */
QCOMPARE(d->marker_.info.number, 1u);
QCOMPARE(d->collectiblePages_.size(), 1);
- QCOMPARE(d->size_, quint32(pageSize * 6)); // Header page + 2 markers + current page + num of commit chain (which is 1) + synced page
+ QCOMPARE(*d->collectiblePages_.constBegin(), even ? 4u : 5u);
+ QCOMPARE(d->size_, quint32(pageSize * 6)); // Header page + 2 markers + current page + num of commit chain (which is 1) + the reusable page
QCOMPARE(d->marker_.meta.revision, numCommits);
QCOMPARE(d->marker_.meta.syncId, 1u);
QCOMPARE(d->marker_.meta.root, even ? 3u : 4u);
QCOMPARE(d->marker_.meta.tag, (quint64)numCommits - 1);
- db->close();
+ db->close(); // syncs root 3 is even, 4 if odd.
QVERIFY(db->open());
+ /* On open after 4 commits:
+ * |Header|Marker1|Marker2|Page 3 is root|Page 4 is reusable|Page 5 is copy of Page 3|
+ *
+ * On open after 5 commits:
+ * |Header|Marker1|Marker2|Page 3 is copy of Page 4|Page 4 is root|Page 5 is reusable|
+ */
QCOMPARE(d->marker_.info.number, 1u);
- QCOMPARE(d->collectiblePages_.size(), 0);
+ QCOMPARE(d->collectiblePages_.size(), 1);
+ QCOMPARE(*d->collectiblePages_.constBegin(), even ? 4u : 5u);
QCOMPARE(d->size_, quint32(pageSize * 6));
QCOMPARE(d->marker_.meta.revision, numCommits);
QCOMPARE(d->marker_.meta.syncId, 1u);
QCOMPARE(d->marker_.meta.root, even ? 3u : 4u);
QCOMPARE(d->marker_.meta.tag, (quint64)numCommits - 1);
-
+ QCOMPARE(d->lastSyncedId_, 1u);
+
+ /* Test (even) commits:
+ * commit 5: Collectible(4). Root 3 -> touch to Page 4. Put on page 4. History(3, 5). Commit chain is 1 -> leave Page 3, put 5 in collectible. Root = 4.
+ * note: Page 3 is synced.
+ *
+ * Test (odd) commits:
+ * commit 6: Collectible(5). Root 4 -> touch to Page 5. Put on page 5. History(4, 3). Commit chain is 1 -> leave Page 4, put 3 in collectible. Root = 5.
+ * note: Page 4 is synced.
+ */
HBtreeTransaction *txn = db->beginTransaction(HBtreeTransaction::ReadWrite);
QVERIFY(txn);
QVERIFY(txn->put(QByteArray::number(1000), QByteArray("1000")));
QVERIFY(txn->commit(1000));
- // Synced page should not be used
QCOMPARE(d->marker_.info.number, 1u);
QCOMPARE(d->collectiblePages_.size(), 1);
- QCOMPARE(d->size_, quint32(pageSize * 7));
+ QCOMPARE(*d->collectiblePages_.constBegin(), even ? 5u : 3u);
+ QCOMPARE(d->size_, quint32(pageSize * 6));
QCOMPARE(d->marker_.meta.revision, numCommits + 1);
QCOMPARE(d->marker_.meta.syncId, 2u);
- QCOMPARE(d->marker_.meta.root, 6u); // root 3 was synced so should not be reused
+ QCOMPARE(d->marker_.meta.root, even ? 4u : 5u);
QCOMPARE(d->marker_.meta.tag, (quint64)1000);
-
- QVERIFY(db->sync());
-
+ QCOMPARE(d->lastSyncedId_, 1u);
+
+ /* Test (even) commits:
+ * commit 6: Collectible(5). Root 4 -> touch to Page 5. Put on page 5. History(4, 3). Commit chain is 1 -> leave Page 4, leave Page 3 because it's synced. Root = 5.
+ *
+ * Test (odd) commits:
+ * commit 7: Collectible(3). Root 5 -> touch to Page 3. Put on page 3. History(5, 4). Commit chain is 1 -> leave Page 5, leave Page 4 because it's synced. Root = 3.
+ */
txn = db->beginTransaction(HBtreeTransaction::ReadWrite);
QVERIFY(txn);
QVERIFY(txn->put(QByteArray::number(2000), QByteArray("2000")));
QVERIFY(txn->commit(2000));
QCOMPARE(d->marker_.info.number, 1u);
- QCOMPARE(d->collectiblePages_.size(), 1);
- QCOMPARE(d->size_, quint32(pageSize * 7));
+ QCOMPARE(d->collectiblePages_.size(), 0);
+ QCOMPARE(d->size_, quint32(pageSize * 6));
QCOMPARE(d->marker_.meta.revision, numCommits + 2);
- QCOMPARE(d->marker_.meta.syncId, 3u);
- QCOMPARE(d->marker_.meta.root, even ? 5u : 3u); // root 4 was synced so should not be reused
+ QCOMPARE(d->marker_.meta.syncId, 2u);
+ QCOMPARE(d->marker_.meta.root, even ? 5u : 3u);
QCOMPARE(d->marker_.meta.tag, (quint64)2000);
+ QCOMPARE(d->lastSyncedId_, 1u);
+
+ QVERIFY(db->sync()); // syncs root 5 if even, 3 if odd.
+
+ QCOMPARE(d->lastSyncedId_, 2u);
+
+ /* Test (even) commits:
+ * commit 7: Collectible(empty). Root 5 -> touch to Page 6. Put on page 6. History(5, 4, 3). Leave Page 5 because it's synced, collect 4, 3. Root = 6.
+ *
+ * Test (odd) commits:
+ * commit 8: Collectible(empty). Root 3 -> touch to Page 6. Put on page 6. History(3, 5, 4). Leave Page 3 because it's synced, collect 5, 4. Root = 6.
+ */
+ txn = db->beginTransaction(HBtreeTransaction::ReadWrite);
+ QVERIFY(txn);
+ QVERIFY(txn->put(QByteArray::number(3000), QByteArray("3000")));
+ QVERIFY(txn->commit(3000));
+
+ QCOMPARE(d->marker_.info.number, 1u);
+ QCOMPARE(d->collectiblePages_.size(), 2);
+ QCOMPARE(d->collectiblePages_, even ? (QSet<quint32>() << 4 << 3) : (QSet<quint32>() << 5 << 4));
+ QCOMPARE(d->size_, quint32(pageSize * 7));
+ QCOMPARE(d->marker_.meta.revision, numCommits + 3);
+ QCOMPARE(d->marker_.meta.syncId, 3u);
+ QCOMPARE(d->marker_.meta.root, 6u);
+ QCOMPARE(d->marker_.meta.tag, (quint64)3000);
+ QCOMPARE(d->lastSyncedId_, 2u);
}
void TestHBtree::corruptSyncMarker1_data()
@@ -2447,7 +2504,7 @@ void TestHBtree::corruptSyncMarker1()
QVERIFY(db->open());
- QCOMPARE(d->collectiblePages_.size(), 0);
+ QCOMPARE(d->collectiblePages_.size(), 1);
for (quint32 i = 0; i < numCommits; ++i) {
HBtreeTransaction *txn = db->beginTransaction(HBtreeTransaction::ReadOnly);