Fix stack overflow when destroying long Journal

Summary:
While destroying JournalDelta entries, unzip the chain as we go and
destroy each entry one by one. This prevents the stack from
overflowing on long JournalDelta chains and should fix some flaky
tests.

Reviewed By: wez

Differential Revision: D9355365

fbshipit-source-id: 31af124d318ca5d7a84314b707e1b3c71b2ccaa9
This commit is contained in:
Chad Austin 2018-08-17 21:04:08 -07:00 committed by Facebook Github Bot
parent 8b4841ef82
commit e6ab9d58a2
3 changed files with 29 additions and 0 deletions

View File

@ -50,6 +50,17 @@ JournalDelta::JournalDelta(
: changedFilesInOverlay{{oldName.copy(), PathChangeInfo{true, false}},
{newName.copy(), PathChangeInfo{true, true}}} {}
JournalDelta::~JournalDelta() {
// O(1) stack space destruction of the delta chain.
JournalDeltaPtr p{std::move(previous)};
while (p && p.unique()) {
// We know we have the only reference to p, so cast away constness because
// we need to unset p->previous.
JournalDelta* q = const_cast<JournalDelta*>(p.get());
p = std::move(q->previous);
}
}
std::unique_ptr<JournalDelta> JournalDelta::merge(
SequenceNumber limitSequence,
bool pruneAfterLimit) const {

View File

@ -72,6 +72,8 @@ class JournalDelta {
*/
JournalDelta(RelativePathPiece oldName, RelativePathPiece newName, Replaced);
~JournalDelta();
/** the prior delta and its chain */
JournalDeltaPtr previous;
/** The current sequence range.

View File

@ -155,3 +155,19 @@ TEST(Journal, mergeRemoveCreateUpdate) {
true,
merged->changedFilesInOverlay[RelativePath{"test.txt"}].existedAfter);
}
TEST(Journal, destruction_does_not_overflow_stack_on_long_chain) {
Journal journal;
size_t N =
#ifdef NDEBUG
200000 // Passes in under 200ms.
#else
40000 // Passes in under 400ms.
#endif
;
for (size_t i = 0; i < N; ++i) {
auto delta = std::make_unique<JournalDelta>(
"foo/bar"_relpath, JournalDelta::CHANGED);
journal.addDelta(std::move(delta));
}
}