| 541 | } |
| 542 | |
| 543 | ACTOR static Future<Void> recover(KeyValueStoreMemory* self, bool exactRecovery) { |
| 544 | loop { |
| 545 | // 'uncommitted' variables track something that might be rolled back by an OpRollback, and are copied into |
| 546 | // permanent variables (in self) in OpCommit. OpRollback does the reverse (copying the permanent versions |
| 547 | // over the uncommitted versions) the uncommitted and committed variables should be equal initially (to |
| 548 | // whatever makes sense if there are no committed transactions recovered) |
| 549 | state Key uncommittedNextKey = self->recoveredSnapshotKey; |
| 550 | state IDiskQueue::location uncommittedPrevSnapshotEnd = self->previousSnapshotEnd = |
| 551 | self->log->getNextReadLocation(); // not really, but popping up to here does nothing |
| 552 | state IDiskQueue::location uncommittedSnapshotEnd = self->currentSnapshotEnd = uncommittedPrevSnapshotEnd; |
| 553 | |
| 554 | state int zeroFillSize = 0; |
| 555 | state int dbgSnapshotItemCount = 0; |
| 556 | state int dbgSnapshotEndCount = 0; |
| 557 | state int dbgMutationCount = 0; |
| 558 | state int dbgCommitCount = 0; |
| 559 | state double startt = now(); |
| 560 | state UID dbgid = self->id; |
| 561 | |
| 562 | state Future<Void> loggingDelay = delay(1.0); |
| 563 | |
| 564 | state OpQueue recoveryQueue; |
| 565 | state OpHeader h; |
| 566 | state Standalone<StringRef> lastSnapshotKey; |
| 567 | state bool isZeroFilled; |
| 568 | |
| 569 | TraceEvent("KVSMemRecoveryStarted", self->id).detail("SnapshotEndLocation", uncommittedSnapshotEnd); |
| 570 | |
| 571 | try { |
| 572 | loop { |
| 573 | { |
| 574 | Standalone<StringRef> data = wait(self->log->readNext(sizeof(OpHeader))); |
| 575 | if (data.size() != sizeof(OpHeader)) { |
| 576 | if (data.size()) { |
| 577 | CODE_PROBE(true, "zero fill partial header in KeyValueStoreMemory"); |
| 578 | memset(&h, 0, sizeof(OpHeader)); |
| 579 | memcpy(&h, data.begin(), data.size()); |
| 580 | zeroFillSize = sizeof(OpHeader) - data.size() + h.len1 + h.len2 + 1; |
| 581 | if (h.op == OpEncrypted) { |
| 582 | // encryption header, plus the real (encrypted) op type |
| 583 | zeroFillSize += BlobCipherEncryptHeader::headerSize + sizeof(int); |
| 584 | } |
| 585 | } |
| 586 | TraceEvent("KVSMemRecoveryComplete", self->id) |
| 587 | .detail("Reason", "Non-header sized data read") |
| 588 | .detail("DataSize", data.size()) |
| 589 | .detail("ZeroFillSize", zeroFillSize) |
| 590 | .detail("SnapshotEndLocation", uncommittedSnapshotEnd) |
| 591 | .detail("NextReadLoc", self->log->getNextReadLocation()); |
| 592 | break; |
| 593 | } |
| 594 | h = *(OpHeader*)data.begin(); |
| 595 | } |
| 596 | state Standalone<StringRef> data = wait(readOpData(self, &h, &isZeroFilled, &zeroFillSize)); |
| 597 | if (zeroFillSize > 0) { |
| 598 | TraceEvent("KVSMemRecoveryComplete", self->id) |
| 599 | .detail("Reason", "data specified by header does not exist") |
| 600 | .detail("DataSize", data.size()) |
nothing calls this directly
no test coverage detected