Skip to content

Commit a6e543b

Browse files
authored
fix signed int and overflow bugs (apple#11273)
now timestamp has uint64 and page number starts at 1
1 parent e0c6b6a commit a6e543b

File tree

3 files changed

+25
-29
lines changed

3 files changed

+25
-29
lines changed

fdbrpc/AsyncFileWriteChecker.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class LRU2 {
8989

9090
uint32_t randomPage() {
9191
if (m.size() == 0) {
92-
return -1;
92+
return 0;
9393
}
9494
auto it = m.begin();
9595
std::advance(it, deterministicRandom()->randomInt(0, (int)m.size()));
@@ -133,7 +133,7 @@ class LRU2 {
133133

134134
uint32_t leastRecentlyUsedPage() {
135135
if (m.size() == 0) {
136-
return -1;
136+
return 0;
137137
}
138138
return end->prev->page;
139139
}
@@ -164,14 +164,14 @@ TEST_CASE("/fdbrpc/AsyncFileWriteChecker/LRU") {
164164
double r = deterministicRandom()->random01();
165165
if (lru2.size() == 0 || r > 0.5) {
166166
// to add/update
167-
uint32_t page = deterministicRandom()->randomInt(0, limit);
167+
uint32_t page = deterministicRandom()->randomInt(1, limit);
168168
if (lru2.exist(page)) {
169169
// the page already exist
170170
compareWriteInfo(lru.find(page), lru2.find(page));
171171
}
172172
// change the content each time
173173
AsyncFileWriteChecker::WriteInfo wi;
174-
wi.checksum = deterministicRandom()->randomInt(0, INT_MAX);
174+
wi.checksum = deterministicRandom()->randomInt(1, INT_MAX);
175175
wi.timestamp = AsyncFileWriteChecker::transformTime(now());
176176
lru.update(page, wi);
177177
lru2.update(page, wi);
@@ -181,7 +181,7 @@ TEST_CASE("/fdbrpc/AsyncFileWriteChecker/LRU") {
181181
// to remove
182182
uint32_t page = lru2.randomPage();
183183

184-
ASSERT(page != -1);
184+
ASSERT(page != 0);
185185
ASSERT(lru.exist(page));
186186
ASSERT(lru2.exist(page));
187187
compareWriteInfo(lru.find(page), lru2.find(page));
@@ -193,7 +193,7 @@ TEST_CASE("/fdbrpc/AsyncFileWriteChecker/LRU") {
193193
} else {
194194
// to truncate
195195
uint32_t page = lru2.randomPage();
196-
uint32_t page2 = lru2.randomPage(); // to ensure
196+
uint32_t page2 = lru2.randomPage();
197197
lru.truncate(page);
198198
lru2.truncate(page);
199199
if (page2 >= page) {

fdbrpc/include/fdbrpc/AsyncFileWriteChecker.actor.h

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,17 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
103103
struct WriteInfo {
104104
WriteInfo() : checksum(0), timestamp(0) {}
105105
uint32_t checksum;
106-
uint32_t timestamp; // keep a precision of ms
106+
uint64_t timestamp; // keep a precision of ms
107107
};
108108

109-
static uint32_t transformTime(double unixTime) { return (uint32_t)(unixTime * millisecondsPerSecond); }
109+
static uint64_t transformTime(double unixTime) { return (uint64_t)(unixTime * millisecondsPerSecond); }
110110

111111
class LRU {
112112
private:
113-
int64_t step;
113+
uint64_t step;
114114
std::string fileName;
115-
std::map<int, uint32_t> stepToKey;
116-
std::map<uint32_t, int> keyToStep; // std::map is to support ::truncate
115+
std::map<uint64_t, uint32_t> stepToKey;
116+
std::map<uint32_t, uint64_t> keyToStep; // std::map is to support ::truncate
117117
std::unordered_map<uint32_t, AsyncFileWriteChecker::WriteInfo> pageContents;
118118

119119
public:
@@ -137,7 +137,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
137137
auto it = keyToStep.lower_bound(page);
138138
// iterate through keyToStep, to find corresponding entries in stepToKey
139139
while (it != keyToStep.end()) {
140-
int step = it->second;
140+
uint64_t step = it->second;
141141
auto next = it;
142142
next++;
143143
keyToStep.erase(it);
@@ -148,7 +148,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
148148

149149
uint32_t randomPage() {
150150
if (keyToStep.size() == 0) {
151-
return -1;
151+
return 0;
152152
}
153153
auto it = keyToStep.begin();
154154
std::advance(it, deterministicRandom()->randomInt(0, (int)keyToStep.size()));
@@ -173,7 +173,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
173173

174174
uint32_t leastRecentlyUsedPage() {
175175
if (stepToKey.size() == 0) {
176-
return -1;
176+
return 0;
177177
}
178178
return stepToKey.begin()->second;
179179
}
@@ -207,14 +207,14 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
207207
}
208208

209209
private:
210-
// transform from unixTime(double) to uint32_t, to retain ms precision.
211210
Reference<IAsyncFile> m_f;
212211
Future<Void> checksumWorker;
213212
Future<Void> checksumLogger;
214213
LRU lru;
215214
void* pageBuffer;
216215
uint64_t totalCheckedFail, totalCheckedSucceed;
217-
uint32_t syncedTime;
216+
// transform from unixTime(double) to uint64_t, to retain ms precision.
217+
uint64_t syncedTime;
218218
// to avoid concurrent operation, so that the continuous reader will skip a page if it is being written
219219
std::unordered_set<uint32_t> writing;
220220
// This is the most page checksum history blocks we will use across all files.
@@ -226,7 +226,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
226226
// for each page, read and do checksum
227227
// scan from the least recently used, thus it is safe to quit if data has not been synced
228228
state uint32_t page = self->lru.leastRecentlyUsedPage();
229-
while (self->writing.find(page) != self->writing.end() || page == -1) {
229+
while (self->writing.find(page) != self->writing.end() || page == 0) {
230230
// avoid concurrent ops
231231
wait(delay(FLOW_KNOBS->ASYNC_FILE_WRITE_CHEKCER_CHECKING_DELAY));
232232
continue;
@@ -253,7 +253,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
253253

254254
// return true if there are still remaining valid synced pages to check, otherwise false
255255
// this method removes the page entry from checksum history upon a successful check
256-
bool verifyChecksum(int page, uint32_t checksum, uint8_t* start, bool sweep) {
256+
bool verifyChecksum(uint32_t page, uint32_t checksum, uint8_t* start) {
257257
if (!lru.exist(page)) {
258258
// it has already been verified succesfully and removed by checksumWorker
259259
return true;
@@ -265,7 +265,6 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
265265
TraceEvent(SevError, "AsyncFileLostWriteDetected")
266266
.error(checksum_failed())
267267
.detail("Filename", getFilename())
268-
.detail("Sweep", sweep)
269268
.detail("PageNumber", page)
270269
.detail("Size", lru.size())
271270
.detail("Start", (long)start)
@@ -287,23 +286,20 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
287286

288287
// Update or check checksum(s) in history for any full pages covered by this operation
289288
// return the updated pages when updateChecksum is true
290-
std::vector<uint32_t> updateChecksumHistory(bool updateChecksum,
291-
int64_t offset,
292-
int len,
293-
uint8_t* buf,
294-
bool sweep = false) {
289+
std::vector<uint32_t> updateChecksumHistory(bool updateChecksum, int64_t offset, int len, uint8_t* buf) {
295290
std::vector<uint32_t> pages;
296291
// Check or set each full block in the the range
297-
int page = offset / checksumHistoryPageSize; // First page number
292+
// page number starts at 1, as we use 0 to indicate invalid page
293+
uint32_t page = offset / checksumHistoryPageSize + 1; // First page number
298294
int slack = offset % checksumHistoryPageSize; // Bytes after most recent page boundary
299295
uint8_t* start = buf; // Position in buffer to start checking from
300296
// If offset is not page-aligned, move to next page and adjust start
301297
if (slack != 0) {
302298
++page;
303299
start += (checksumHistoryPageSize - slack);
304300
}
305-
int startPage = page;
306-
int pageEnd = (offset + len) / checksumHistoryPageSize; // Last page plus 1
301+
uint32_t startPage = page;
302+
uint32_t pageEnd = (offset + len) / checksumHistoryPageSize; // Last page plus 1
307303
while (page < pageEnd) {
308304
uint32_t checksum = crc32c_append(0xab12fd93, start, checksumHistoryPageSize);
309305
#if VALGRIND
@@ -332,7 +328,7 @@ class AsyncFileWriteChecker : public IAsyncFile, public ReferenceCounted<AsyncFi
332328
history.checksum = checksum;
333329
lru.update(page, history);
334330
} else {
335-
if (!verifyChecksum(page, checksum, start, sweep)) {
331+
if (!verifyChecksum(page, checksum, start)) {
336332
break;
337333
}
338334
}

flowbench/BenchAsyncFileWriteCheckerLRU.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static void lru_test(benchmark::State& state) {
2222
// [0.5, 1] update
2323
if (exist.size() < 2 || r > 0.5) {
2424
// to add/update
25-
uint32_t page = deterministicRandom()->randomInt(0, limit);
25+
uint32_t page = deterministicRandom()->randomInt(1, limit);
2626
// change the content each time
2727
auto wi = AsyncFileWriteChecker::WriteInfo();
2828
wi.timestamp = i;

0 commit comments

Comments
 (0)