| 322 | } |
| 323 | |
| 324 | void redisDbPersistentData::endSnapshot(const redisDbPersistentDataSnapshot *psnapshot) |
| 325 | { |
| 326 | serverAssert(GlobalLocksAcquired()); |
| 327 | |
| 328 | if (m_spdbSnapshotHOLDER.get() != psnapshot) |
| 329 | { |
| 330 | if (m_spdbSnapshotHOLDER == nullptr) |
| 331 | { |
| 332 | // This is an orphaned snapshot |
| 333 | redisDbPersistentDataSnapshot::gcDisposeSnapshot(const_cast<redisDbPersistentDataSnapshot*>(psnapshot)); |
| 334 | return; |
| 335 | } |
| 336 | m_spdbSnapshotHOLDER->endSnapshot(psnapshot); |
| 337 | return; |
| 338 | } |
| 339 | |
| 340 | mstime_t latency_endsnapshot; |
| 341 | latencyStartMonitor(latency_endsnapshot); |
| 342 | |
| 343 | // Alright we're ready to be free'd, but first dump all the refs on our child snapshots |
| 344 | if (m_spdbSnapshotHOLDER->m_refCount == 1) |
| 345 | recursiveFreeSnapshots(m_spdbSnapshotHOLDER.get()); |
| 346 | |
| 347 | m_spdbSnapshotHOLDER->m_refCount--; |
| 348 | if (m_spdbSnapshotHOLDER->m_refCount > 0) |
| 349 | return; |
| 350 | |
| 351 | size_t sizeStart = size(); |
| 352 | serverAssert(m_spdbSnapshotHOLDER->m_refCount == 0); |
| 353 | serverAssert((m_refCount == 0 && m_pdict->pauserehash == 0) || (m_refCount != 0 && m_pdict->pauserehash == 1)); |
| 354 | |
| 355 | serverAssert(m_spdbSnapshotHOLDER->m_pdict->pauserehash == 1); // All iterators should have been free'd except the fake one from createSnapshot |
| 356 | if (m_refCount == 0) |
| 357 | { |
| 358 | dictResumeRehashing(m_spdbSnapshotHOLDER->m_pdict); |
| 359 | } |
| 360 | |
| 361 | if (m_pdbSnapshot == nullptr) |
| 362 | { |
| 363 | // the database was cleared so we don't need to recover the snapshot |
| 364 | dictEmpty(m_pdictTombstone, nullptr); |
| 365 | m_spdbSnapshotHOLDER = std::move(m_spdbSnapshotHOLDER->m_spdbSnapshotHOLDER); |
| 366 | return; |
| 367 | } |
| 368 | |
| 369 | // Stage 1 Loop through all the tracked deletes and remove them from the snapshot DB |
| 370 | dictIterator *di = dictGetIterator(m_pdictTombstone); |
| 371 | dictEntry *de; |
| 372 | dictPauseRehashing(m_spdbSnapshotHOLDER->m_pdict); |
| 373 | auto splazy = std::make_unique<LazyFree>(); |
| 374 | while ((de = dictNext(di)) != NULL) |
| 375 | { |
| 376 | dictEntry **dePrev; |
| 377 | dictht *ht; |
| 378 | // BUG BUG Why not a shallow search? |
| 379 | dictEntry *deSnapshot = dictFindWithPrev(m_spdbSnapshotHOLDER->m_pdict, dictGetKey(de), (uint64_t)dictGetVal(de), &dePrev, &ht, false /*!!sdsisshared((sds)dictGetKey(de))*/); |
| 380 | if (deSnapshot == nullptr && m_spdbSnapshotHOLDER->m_pdbSnapshot) |
| 381 | { |
no test coverage detected