Skip to content

Commit 82a9f02

Browse files
JaySon-Huangzanmato1984
authored andcommitted
[FLASH-546] Fix exception after reload PageStorage from disk (pingcap#274)
* Idempotent del for PageStorage * Fix the won't decrease of Normal Page in PageStorage * Add more test case for checking the ref-count of NormalPage * add metrics: PSMVCCNumSnapshots
1 parent c60e020 commit 82a9f02

10 files changed

+369
-29
lines changed

dbms/src/Common/CurrentMetrics.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
M(StorageBufferBytes) \
3838
M(DictCacheRequests) \
3939
M(Revision) \
40+
M(PSMVCCNumSnapshots) \
4041
M(RWLockWaitingReaders) \
4142
M(RWLockWaitingWriters) \
4243
M(RWLockActiveReaders) \

dbms/src/Common/CurrentMetrics.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace CurrentMetrics
5050
add(metric, -value);
5151
}
5252

53-
/// For lifetime of object, add amout for specified metric. Then subtract.
53+
/// For lifetime of object, add amount for specified metric. Then subtract.
5454
class Increment
5555
{
5656
private:

dbms/src/Storages/Page/PageEntries.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class PageEntriesMixin
107107
{
108108
return {false, 0UL};
109109
}
110-
return {ref_pair->second != page_id, ref_pair->second};
110+
return {true, ref_pair->second};
111111
}
112112

113113
inline void clear()
@@ -237,10 +237,13 @@ void PageEntriesMixin<T>::del(PageId page_id)
237237
assert(is_base); // can only call by base
238238
// Note: must resolve ref-id before erasing entry in `page_ref`
239239
const PageId normal_page_id = resolveRefId(page_id);
240-
page_ref.erase(page_id);
241240

242-
// decrease origin page's ref counting
243-
decreasePageRef<must_exist>(normal_page_id);
241+
const size_t num_erase = page_ref.erase(page_id);
242+
if (num_erase > 0)
243+
{
244+
// decrease origin page's ref counting
245+
decreasePageRef<must_exist>(normal_page_id);
246+
}
244247
}
245248

246249
template <typename T>

dbms/src/Storages/Page/VersionSet/PageEntriesVersionSetWithDelta.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,15 @@ void DeltaVersionEditAcceptor::applyPut(PageEntriesEdit::EditRecord & rec)
208208
void DeltaVersionEditAcceptor::applyDel(PageEntriesEdit::EditRecord & rec)
209209
{
210210
assert(rec.type == WriteBatch::WriteType::DEL);
211-
const PageId normal_page_id = view->resolveRefId(rec.page_id);
211+
auto [is_ref, normal_page_id] = view->isRefId(rec.page_id);
212+
view->resolveRefId(rec.page_id);
212213
current_version->ref_deletions.insert(rec.page_id);
213214
current_version->page_ref.erase(rec.page_id);
214-
this->decreasePageRef(normal_page_id);
215+
if (is_ref)
216+
{
217+
// If ref exists, we need to decrease entry ref-count
218+
this->decreasePageRef(normal_page_id);
219+
}
215220
}
216221

217222
void DeltaVersionEditAcceptor::applyRef(PageEntriesEdit::EditRecord & rec)
@@ -283,7 +288,7 @@ void DeltaVersionEditAcceptor::applyInplace(const PageEntriesVersionSetWithDelta
283288
void DeltaVersionEditAcceptor::decreasePageRef(const PageId page_id)
284289
{
285290
const auto old_entry = view->findNormalPageEntry(page_id);
286-
if (!old_entry)
291+
if (old_entry)
287292
{
288293
auto entry = *old_entry;
289294
entry.ref = old_entry->ref <= 1 ? 0 : old_entry->ref - 1;

dbms/src/Storages/Page/VersionSet/PageEntriesView.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ std::optional<PageEntry> PageEntriesView::findNormalPageEntry(PageId page_id) co
6767
std::pair<bool, PageId> PageEntriesView::isRefId(PageId page_id) const
6868
{
6969
auto node = tail;
70+
// For delta, we need to check if page_id is deleted, then try to find in page_ref
7071
for (; !node->isBase(); node = node->prev)
7172
{
7273
if (node->ref_deletions.count(page_id) > 0)
@@ -75,6 +76,7 @@ std::pair<bool, PageId> PageEntriesView::isRefId(PageId page_id) const
7576
if (iter != node->page_ref.end())
7677
return {true, iter->second};
7778
}
79+
// For base
7880
return node->isRefId(page_id);
7981
}
8082

dbms/src/Storages/Page/mvcc/VersionSetWithDelta.h

+19-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <stack>
99
#include <unordered_set>
1010

11+
#include <Common/CurrentMetrics.h>
1112
#include <Common/ProfileEvents.h>
1213
#include <IO/WriteHelpers.h>
1314
#include <Storages/Page/mvcc/VersionSet.h>
@@ -22,6 +23,11 @@ extern const Event PSMVCCApplyOnCurrentDelta;
2223
extern const Event PSMVCCApplyOnNewDelta;
2324
} // namespace ProfileEvents
2425

26+
namespace CurrentMetrics
27+
{
28+
extern const Metric PSMVCCNumSnapshots;
29+
} // namespace CurrentMetrics
30+
2531
namespace DB
2632
{
2733
namespace MVCC
@@ -61,13 +67,18 @@ class VersionSetWithDelta
6167
snapshots(std::move(std::make_shared<Snapshot>(this, nullptr))), //
6268
config(config_)
6369
{
70+
// The placeholder snapshot should not be counted.
71+
CurrentMetrics::sub(CurrentMetrics::PSMVCCNumSnapshots);
6472
}
6573

6674
virtual ~VersionSetWithDelta()
6775
{
6876
current.reset();
6977
// snapshot list is empty
7078
assert(snapshots->prev == snapshots.get());
79+
80+
// Ignore the destructor of placeholder snapshot
81+
CurrentMetrics::add(CurrentMetrics::PSMVCCNumSnapshots);
7182
}
7283

7384
void apply(TVersionEdit & edit)
@@ -114,7 +125,10 @@ class VersionSetWithDelta
114125
Snapshot * next;
115126

116127
public:
117-
Snapshot(VersionSetWithDelta * vset_, VersionPtr tail_) : vset(vset_), view(std::move(tail_)), prev(this), next(this) {}
128+
Snapshot(VersionSetWithDelta * vset_, VersionPtr tail_) : vset(vset_), view(std::move(tail_)), prev(this), next(this)
129+
{
130+
CurrentMetrics::add(CurrentMetrics::PSMVCCNumSnapshots);
131+
}
118132

119133
~Snapshot()
120134
{
@@ -123,6 +137,8 @@ class VersionSetWithDelta
123137
std::unique_lock lock = vset->acquireForLock();
124138
prev->next = next;
125139
next->prev = prev;
140+
141+
CurrentMetrics::sub(CurrentMetrics::PSMVCCNumSnapshots);
126142
}
127143

128144
const TVersionView * version() const { return &view; }
@@ -327,6 +343,8 @@ class VersionSetWithDelta
327343
VersionPtr current;
328344
SnapshotPtr snapshots;
329345
::DB::MVCC::VersionSetConfig config;
346+
347+
friend class VersionSetWithDeltaCompactTest;
330348
};
331349

332350
} // namespace MVCC

dbms/src/Storages/Page/tests/gtest_page_entry_map.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,55 @@ TEST_F(PageEntryMap_test, PutDel)
125125
ASSERT_EQ(map->find(2), std::nullopt);
126126
}
127127

128+
TEST_F(PageEntryMap_test, IdempotentDel)
129+
{
130+
PageEntry p0entry;
131+
p0entry.file_id = 1;
132+
p0entry.checksum = 0x123;
133+
map->put(0, p0entry);
134+
{
135+
ASSERT_NE(map->find(0), std::nullopt);
136+
const PageEntry & entry = map->at(0);
137+
EXPECT_EQ(entry.file_id, p0entry.file_id);
138+
EXPECT_EQ(entry.checksum, p0entry.checksum);
139+
}
140+
map->ref(2, 0);
141+
{
142+
ASSERT_NE(map->find(2), std::nullopt);
143+
const PageEntry & entry = map->at(2);
144+
EXPECT_EQ(entry.file_id, p0entry.file_id);
145+
EXPECT_EQ(entry.checksum, p0entry.checksum);
146+
}
147+
148+
map->del(0);
149+
{
150+
// Should not found Page0, but Page2 is still available
151+
ASSERT_EQ(map->find(0), std::nullopt);
152+
auto entry = map->find(2);
153+
ASSERT_TRUE(entry);
154+
EXPECT_EQ(entry->file_id, p0entry.file_id);
155+
EXPECT_EQ(entry->checksum, p0entry.checksum);
156+
entry = map->findNormalPageEntry(0);
157+
ASSERT_TRUE(entry);
158+
EXPECT_EQ(entry->file_id, p0entry.file_id);
159+
EXPECT_EQ(entry->checksum, p0entry.checksum);
160+
}
161+
162+
// Del should be idempotent
163+
map->del(0);
164+
{
165+
ASSERT_EQ(map->find(0), std::nullopt);
166+
auto entry = map->find(2);
167+
ASSERT_TRUE(entry);
168+
EXPECT_EQ(entry->file_id, p0entry.file_id);
169+
EXPECT_EQ(entry->checksum, p0entry.checksum);
170+
entry = map->findNormalPageEntry(0);
171+
ASSERT_TRUE(entry);
172+
EXPECT_EQ(entry->file_id, p0entry.file_id);
173+
EXPECT_EQ(entry->checksum, p0entry.checksum);
174+
}
175+
}
176+
128177
TEST_F(PageEntryMap_test, UpdateRefPageEntry)
129178
{
130179
const PageId page_id = 0;

0 commit comments

Comments
 (0)