Returns number of pages which failed checksum.
| 1308 | |
| 1309 | // Returns number of pages which failed checksum. |
| 1310 | int SQLiteDB::checkAllPageChecksums() { |
| 1311 | ASSERT(!haveMutex); |
| 1312 | ASSERT(page_checksums); // This should never be called on SQLite databases that do not have page checksums. |
| 1313 | |
| 1314 | double startT = timer(); |
| 1315 | |
| 1316 | // First try to open an existing file |
| 1317 | std::string apath = abspath(filename); |
| 1318 | std::string walpath = apath + "-wal"; |
| 1319 | |
| 1320 | /* REMOVE THIS BEFORE CHECKIN */ if (!fileExists(apath)) |
| 1321 | return 0; |
| 1322 | |
| 1323 | TraceEvent("SQLitePageChecksumScanBegin").detail("File", apath); |
| 1324 | |
| 1325 | ErrorOr<Reference<IAsyncFile>> dbFile = waitForAndGet( |
| 1326 | errorOr(IAsyncFileSystem::filesystem()->open(apath, IAsyncFile::OPEN_READONLY | IAsyncFile::OPEN_LOCK, 0))); |
| 1327 | ErrorOr<Reference<IAsyncFile>> walFile = waitForAndGet( |
| 1328 | errorOr(IAsyncFileSystem::filesystem()->open(walpath, IAsyncFile::OPEN_READONLY | IAsyncFile::OPEN_LOCK, 0))); |
| 1329 | |
| 1330 | if (dbFile.isError()) |
| 1331 | throw dbFile.getError(); // If we've failed to open the file, throw an exception |
| 1332 | if (walFile.isError()) |
| 1333 | throw walFile.getError(); // If we've failed to open the file, throw an exception |
| 1334 | |
| 1335 | // Now that the file itself is open and locked, let sqlite open the database |
| 1336 | // Note that VFSAsync will also call g_network->open (including for the WAL), so its flags are important, too |
| 1337 | // TODO: If better performance is needed, make AsyncFileReadAheadCache work and be enabled by SQLITE_OPEN_READAHEAD |
| 1338 | // which was added for that purpose. |
| 1339 | int result = sqlite3_open_v2(apath.c_str(), &db, SQLITE_OPEN_READONLY, nullptr); |
| 1340 | checkError("open", result); |
| 1341 | |
| 1342 | // This check has the useful side effect of actually opening/reading the database. If we were not doing this, |
| 1343 | // then we could instead open a read cursor for the same effect, as currently tryReadEveryDbPage() requires it. |
| 1344 | Statement* jm = new Statement(*this, "PRAGMA journal_mode"); |
| 1345 | ASSERT(jm->nextRow()); |
| 1346 | if (jm->column(0) != LiteralStringRef("wal")) { |
| 1347 | TraceEvent(SevError, "JournalModeError").detail("Filename", filename).detail("Mode", jm->column(0)); |
| 1348 | ASSERT(false); |
| 1349 | } |
| 1350 | delete jm; |
| 1351 | |
| 1352 | btree = db->aDb[0].pBt; |
| 1353 | initPagerCodec(); |
| 1354 | sqlite3_extended_result_codes(db, 1); |
| 1355 | |
| 1356 | sqlite3_mutex_enter(db->mutex); |
| 1357 | haveMutex = true; |
| 1358 | |
| 1359 | pPagerCodec->silent = true; |
| 1360 | Pgno p = 1; |
| 1361 | int readErrors = 0; |
| 1362 | int corruptPages = 0; |
| 1363 | int totalErrors = 0; |
| 1364 | |
| 1365 | while (1) { |
| 1366 | int type; |
| 1367 | int zero; |
no test coverage detected