From: Jeff King Date: Thu, 24 Jun 2021 20:00:46 GMT Subject: Re: [PATCH 3/4] midx: don't reuse corrupt MIDXs when writing Message-ID: In-Reply-To: On Wed, Jun 23, 2021 at 02:39:12PM -0400, Taylor Blau wrote: > Suppose we experience a memory corruption while writing a MIDX such that > we write an incorrect object offset (or alternatively, the disk corrupts > the data after being written, but before being reused). Then when we go > to write a new MIDX, we'll reuse the bad object offset without checking > its validity. This means that the MIDX we just wrote is broken, but its > trailing checksum is in-tact, since we never bothered to look at the > values before writing. > > In the above, a "git multi-pack-index verify" would have caught the > problem before writing, but writing a new MIDX wouldn't have noticed > anything wrong, blindly carrying forward the corrupt offset. > > Individual pack indexes check their validity by verifying the crc32 > attached to each entry when carrying data forward during a repack. > We could solve this problem for MIDXs in the same way, but individual > crc32's don't make much sense, since their entries are so small. > Likewise, checking the whole file on every read may be prohibitively > expensive if a repository has a lot of objects, packs, or both. > > But we can check the trailing checksum when reusing an existing MIDX > when writing a new one. And a corrupt MIDX need not stop us from writing > a new one, since we can just avoid reusing the existing one at all and > pretend as if we are writing a new MIDX from scratch. Nicely explained. This is not saving us from any corruption, but it is noticing it sooner and helping us better diagnose the root problem (e.g., in our real-world case it is still only a guess that the data was corrupted after write, though there was strong correlating evidence). I wondered what the performance implications might be. In my fully-packed clone of linux.git with no midx, I get (before your patch): $ time git multi-pack-index write real 0m1.358s user 0m1.119s sys 0m0.185s Running again immediately is much faster, because we realize there's nothing new to pack: $ time git multi-pack-index write real 0m0.007s user 0m0.000s sys 0m0.007s If we create a dummy pack, then we do real work, which seems to take about the same amount of time as generating from scratch: $ git pack-objects .git/objects/pack/pack