git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Achieving efficient storage of weirdly structured repos

From
RSRoman Shaposhnik <rvs@sun.com>
Date
Apr 6, 2008, 00:13 UTC
Message-ID
<4A31E284-E7F1-4748-A2CB-D8682748D3D6@sun.com>
In-Reply-To
<alpine.LFD.1.00.0804041634180.14670@woody.linux-foundation.org>
Hi Linus,
On Apr 4, 2008, at 4:57 PM, Linus Torvalds wrote:
Show 6 quoted lines
> On Fri, 4 Apr 2008, Roman Shaposhnik wrote:
>>
>> That turned out to be a perfect suggestion. Thank you. I'm now the
>> happiest camper ever. And I'm also also pretty dumbfounded ;-)
>
> Ok, the dumbfounded we can help with.
Great!
Show 14 quoted lines
>> Here's what happened.
>>
>> I started with a a repository filled with "loose" (one object per  
>> file)
>> objects (the reason I needed it was for the ease of sleuthing through
>> individual objects and it was created by git-unpack-objects from that
>> initial 1.1Gb pack). And I tried to pack it exactly like you
>> suggested:
>>    $ git-pack-objects --depth=100 --window=100 --delta-base-offset  
>> --progress pack < objects
>
> Well, that's not exactly like I suggested, that's a *really* old- 
> fashioned
> way.

It sure is old-fashioned. My only excuse is that since git repack is a shell script around git-pack-objects I've always felt comfortable just using the lower level utility.

> But the part you left off was what the "objects" file contained?

It was pretty much the result of (cd .git/objects ; find . -type f | tr -d './') Omitting that was quite silly on my part, but I was really convinced that because of the internal sorting the original ordering of objects wouldn't matter at all.

Show 11 quoted lines
> In particular, "git pack-objects" can take just a raw list of  
> objects, and
> it will *work*, but without the naming information and without the
> ordering information on the objects, the end result will generally  
> suck.
>
> So how did you generate the "objects" file? You can do it by just  
> listing
> every single loose object you have, and it will work, but the end  
> result
> won't be very pretty.
So it seems that my list of objects was different from what git-rev- 
list/setup_revisions()
would have provided in two ways:
     1. the order of objects was arbitrary
     2. the naming of blobs and trees was missing
#2 was, indeed, a huge oversight on my part. At the same time, I've  
always thought
that #1 shouldn't matter, because, as you pointed out, the objects get
sorted by <type, namehash, length> anyway. However, it seems that  
because
of the lack of naming there was much less sorting done by  
type_size_sort()
and the original order persevered (at least within type-size  
partitions).
It did matter after all!

Now, in my particular case, the ordering was braindead and it resulted in a highly visible inefficiency. On the other hand, it seems that creative ordering could very well be used to exploit localities which go beyond how default name hashing in builtin-pack-objects.c works.

In fact, it starts to look awfully like custom MPEG profiles where if you know your footage you can achieve a much higher compression ratio compared to what the default might give you. It also makes it very clear that Git's approach of doing away with per-file content tracking is quite superior to the in-file deltas. Cool!

Here's my final question on that issue: wouldn't it be great to give users a direct control over specifying the list of objects in exactly the order they would like them to be tried for deltifying? Something like -- preserve-order option available for git-pack-objects?

Show 11 quoted lines
>>     Total 1159628 (delta 614516), reused 0 (delta 0)
>
> Ie you got a much better 60% delta ratio, and obviously a much smaller
> pack. But it's not just smaller, because the resulting pack will  
> also have
> the objects in topological order, so that objects that are "new"
> (ie more closely reachable from the top-of-tree) will be at the  
> front of
> the pack, so you'll also generally have better IO patterns in the  
> packfile
> itself.
Got it! This makes total sense.
Show 71 quoted lines
>> Is there any documentation that describes the heuristics involved in
>> creating a pack?
>
> It's been explained a few times on the mailing list, but I don't  
> know if
> there is some write-up.
>
> The git pack format is a bit more relaxed than any other SCM format  
> I know
> about, since it literally is just a "bunch of objects with deltas  
> randomly
> between them". So a pack can look just about any way it wants -  
> there are
> no real ordering requirements (--delta-base-offset does require  
> that the
> delta follows the base, but even that is really just a trivial  
> practical
> "because otherwise you could never know what the offset in the pack- 
> file
> was" issue rather than anything else).
>
> So you can order the objects and make deltas just about any way you  
> want.
> What "git repack" will do is to sort objects by <type, namehash,  
> length>,
> and then walk the list with the window of the specified size to see  
> the
> best pairing it can do.
>
> The "namehash" is just designed so that files that have the same  
> name sort
> together (and it's also not a real "hash" - it's really a meaningless
> number, but one that is designed so that even if the names aren't  
> exactly
> the same, they sort closer together if they end in similar character
> sequences - so a file that moves from one directory to another but  
> keeps
> the same basename will sort source and destination together).
>
> See "type_size_sort()" in builtin-pack-objects.c to see what's up.
>
> (The preferred_base thing is just to keep objects we actually want to
> *keep* in the pack separated from the objects we may be using for
> references - but that is only used for transferring objects over  
> the wire,
> never for standalone packs).
>
> Oh. And now I notice that there is *some* documentation on this in
>
> 	Documentation/technical/pack-heuristics.txt
>
> but that's pretty old (not that I think it has really changed) and not
> very deep. Just taken from some #irc discussion.
>
>> P.S. Oh, and here's one extra tiny question that I also have: what
>> does the output:
>>    Total 1159628 (delta 614516), reused 0 (delta 0)
>> really mean?
>
> It just means that there were a million objects total, the pack was
> created with 614k of them as deltas against other objects, and none of
> them were re-used from previous packs.
>
> You'll see that when you do incremental repacks, 99% of all the  
> objects
> and deltas get re-used from the old pack, which is how we can make
> repacking fairly efficient. That's imporant because the native git
> protocol format itself is just a pack-file (plus the handshake to  
> figure
> out what both sides have, of course). So a "git clone" implies a  
> repack.
Very nice summary! Many, many thanks for providing it!

Thanks, Roman.

Previous: Linus TorvaldsNext: Linus Torvalds
Message 9 of 14 in “Achieving efficient storage of weirdly structured repos”
  1. Roman ShaposhnikApr 3, 2008
  2. Linus TorvaldsApr 3, 2008
  3. Jakub NarebskiApr 4, 2008
  4. Nicolas PitreApr 4, 2008
  5. Pieter de BieApr 4, 2008
  6. Shawn O. PearceApr 5, 2008
  7. Roman ShaposhnikApr 4, 2008
  8. Linus TorvaldsApr 4, 2008
  9. Roman ShaposhnikApr 6, 2008
  10. Linus TorvaldsApr 6, 2008
  11. Jeff KingApr 6, 2008
  12. Nicolas PitreApr 7, 2008
  13. Jeff KingApr 7, 2008
  14. Nicolas PitreApr 7, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.