| 302 | } |
| 303 | |
| 304 | void checkpoint(bool restart) { |
| 305 | int logSize = 0, checkpointCount = 0; |
| 306 | // double t = timer(); |
| 307 | while (true) { |
| 308 | int rc = sqlite3_wal_checkpoint_v2( |
| 309 | db, 0, restart ? SQLITE_CHECKPOINT_RESTART : SQLITE_CHECKPOINT_FULL, &logSize, &checkpointCount); |
| 310 | if (!rc) |
| 311 | break; |
| 312 | |
| 313 | // In simulation, if the process is shutting down then do not wait/retry on a busy result because the wait |
| 314 | // or the retry could take too long to complete such that the virtual process is forcibly destroyed first, |
| 315 | // leaking all outstanding actors and their related states which would include references to the SQLite |
| 316 | // data files which would remain open. This would cause the replacement virtual process to fail an assert |
| 317 | // when opening the SQLite files as they would already be in use. |
| 318 | if (g_network->isSimulated() && g_simulator.getCurrentProcess()->shutdownSignal.isSet()) { |
| 319 | VFSAsyncFile::setInjectedError(rc); |
| 320 | checkError("checkpoint", rc); |
| 321 | ASSERT(false); // should never reach this point |
| 322 | } else if ((sqlite3_errcode(db) & 0xff) == SQLITE_BUSY) { |
| 323 | // printf("#"); |
| 324 | // threadSleep(.010); |
| 325 | sqlite3_sleep(10); |
| 326 | } else |
| 327 | checkError("checkpoint", rc); |
| 328 | } |
| 329 | // printf("Checkpoint (%0.1f ms): %d frames in log, %d checkpointed\n", (timer()-t)*1000, logSize, |
| 330 | // checkpointCount); |
| 331 | } |
| 332 | uint32_t freePages() { |
| 333 | u32 fp = 0; |
| 334 | sqlite3BtreeGetMeta(btree, BTREE_FREE_PAGE_COUNT, &fp); |
no test coverage detected