toolbox/update-all-config.pl: quiet means quiet
[girocco.git] / docs / technical / gc.txt
blob0cc092ac24c9acde66d68d7940b4a7c524a52346
1 =============================
2 Garbage Collection in Girocco
3 =============================
5 Girocco suppresses the normal Git on-demand garbage collection that could be
6 triggered automatically by many Git commands.
8 It does this by setting the gc.auto config value to 0.  This is a good thing
9 because it prevents awkward and unwanted pauses during normal repository
10 operations.  It also prevents the standard garbage collection algorithm from
11 running which could potentially prune and remove objects still in use by forks.
13 What this means is that Girocco must schedule and perform its own garbage
14 collection by using lower-level (sometimes called "plumbing") Git commands to
15 accomplish the same thing in a non-disruptive fashion that leaves forks intact.
17 This file describes the approach used by Girocco to perform garbage collection
18 on its repositories and also discusses the pitfalls (aka race conditions)
19 inherently present in Git when garbage collection is performed simultaneously
20 with other repository-changing operations.
22 -----------
23 Git Gotchas
24 -----------
26 There are three primary gotchas in Git when preforming garbage collection
27 simultaneously with other repository operations:
29   i) An object present in the repository (loose or packed) that is in the
30      process of transitioning from being unreachable to becoming reachable
31      (due to a ref change) could be removed by a simulataneous garbage
32      collection that continues to see the object as unreachable due to various
33      race conditions.
35  ii) An incoming push that pushes a pack that already exists while garbage
36      collection is in progress could result in that pack being removed even
37      though it has a `.keep` file.
39 iii) Two (or more) simultaneous push operations combined with simultaneous
40      garbage collection could result in one of the pushes failing to transfer
41      all the objects required for its ref change.
44 Unreachable Objects
45 ~~~~~~~~~~~~~~~~~~~
47 What happens in case (i) is that an object is initially unreachable, garbage
48 collection starts and determines that it really is unreachable and then just
49 before it deletes the object (or the pack containing the object), a push comes
50 in that uses the object -- and then garbage collection goes ahead and removes
51 it anyway.
53 This happens when incoming pushes unpack their objects and any of the objects
54 already exist in the repository -- in which case the same objects from the
55 incoming push are ignored; in an unshared repository they (or their
56 containing pack) should end up with a "freshened" modification time.  But all
57 that does is shrink the window for the race condition, not eliminate it.
59 This can be avoided by never unpacking incoming pushes (by setting the config
60 item transfer.unpackLimit to 1).  This works because the remote client that
61 sends the push can only see reachable objects that the server has and sends
62 everything that is not reachable from any of the server's refs in its push
63 pack.
65 The push pack may, indeed, contain duplicates of pre-existing unreachable
66 objects in the repository, but since that push pack will not be unpacked they
67 will be kept and even if the pre-existing unreachable duplicate objects are
68 removed no corruption will occur because the push pack contains those objects.
70 This works because the incoming push pack will be in a `.keep` state
71 (preventing it from being removed) until _after_ the objects in it have been
72 made reachable by a ref update.  But see the next section for an exception.
74 Girocco sets transfer.unpackLimit to 1 for exactly this reason.
77 Push Pack Redux
78 ~~~~~~~~~~~~~~~
80 For case (ii) consider a repository with only a `master` branch with its
81 current tip commit at "C".  This repository has been pushed up to a server but
82 everything's currently quiescent.
84  1. A client pushes a fast-forward to `master` containing commits "D", "E" and
85     "F".
87     If transfer.unpackLimit is set to 1 or the pack contains enough objects
88     the push will result in a new pack on the server.  Call it pack "X".
90  2. Now the client immediately decides that was a mistake and pushes a "rewind"
91     of `master` back to commit "C".
93     But wait, nope, that's not right after all...
95  3. Meanwhile the server starts garbage collection and notices pre-existing
96     pack "X".  It completes the reachability trace and determines that none of
97     the objects in pack "X" are reachable but has not yet removed pack "X".
99  4. The client re-pushes a fast-forward to `master` containing exactly the same
100     three commits "D", "E" and "F".
102     This causes exactly the same push pack that was sent with the original
103     fast-forward push in (1) to be sent again.
105  5. Garbage collection removes pack "X" corrupting the repository.
107 If the push pack gets unpacked on push (depending on the setting of
108 transfer.unpackLimit) then the situation just described doesn't apply and the
109 scenario becomes the same as explained in the previous section for case (i).
111 What does Git do when the same pack is pushed again?  Well, it leaves the
112 pre-existing pack alone (not even "freshening" it).  It will, however, create
113 the corresponding `.keep` file (since there would not be one for the
114 pre-existing pack) and then removes that `.keep` after refs have been updated.
116 The problem with this is `git repack -a -d`.
118 When a `git repack -a -d` completes it removes all packs that a) existed when
119 the repack started and b) did not have a `.keep` file and c) do not have the
120 same name as any pack(s) created by the repack operation.
122 The solution to this is to never, ever, ever use `git repack -a -d` when there
123 is a possibility of a simultaneous push operation.
125 Girocco does not use `git repack -a -d` for garbage collection.
127 (Girocco had a dubious flirtation with `-a -d` until [a7ea68a8a80e43d5][1].)
129 Girocco does, however, use a technique that bears some resemblance to the
130 mechanism that `git repack -a -d` uses in that it records the names of all
131 preexisting non-keep packs just before starting gc and then removes them
132 after gc completes (provided they have not been "freshened" in the meantime).
134 Girocco deals with the "Push Pack Redux" problem by renaming the preexisting
135 packs while collecting their names.  After the rename is complete it checks to
136 see if any .keep files have appeared for the original name and creates a
137 corresponding .keep file for the new name (and excludes it from the list).
139 If the rename happens in the midst of a "Push Pack Redux", only the renamed
140 version might be left (hence the transfer of the .keep file).  If there is
141 no .keep file then either no "Push Pack Redux" has started or it's already
142 finished its ref updates in which case it will be picked up by the future
143 reachability trace that hasn't started yet.
145 The renamed packs get an added suffix so that no incoming push can ever
146 possibly generate a pack name collision thereby avoiding the problem.
149 Simultaneous Pushes
150 ~~~~~~~~~~~~~~~~~~~
152 For case (iii), consider a repository with only a `master` branch.
154 Client A works on a "topic" branch called `some-topic` and finally pushes it
155 for public inspection.  At push time it is a new branch on the server.
157 Client B has decided that the tip of the `master` branch needs to be dropped
158 (in other words `master` needs to be rewound by one commit).
160  1. Client A does a fetch and verifies that the `some-topic` branch is rebased
161     onto the latest `master` commit and then does a `git push` of the new
162     `some-topic` branch.
164     The push starts and receives the ref advertisements from the server and
165     the client determines what objects it needs to send and starts building
166     its pack for pushing.
168  2. While Client A is building its pack for pushing, Client B pushes a rewind
169     of branch `master` by one commit.  This operation completes while Client A
170     is still continuing to build its pack (hey, it's a big topic branch).
172  3. Now, garbage collection just happens to kick off and start its reachability
173     trace.  It grabs all the refs and starts walking the DAG.  It has just
174     finished determining what's unreachable but not yet removed anything.
176  4. That push from Client A finally finishes computing its pack and sends it
177     up and the new `some-topic` branch ref is updated.  This will work because
178     even though Client B rewound `master` and Client A's push pack did not
179     include that rewound and discarded commit, that commit hasn't been removed
180     by garbage collection just yet so the `some-topic` ref update still
181     succeeds even if it does a full connectivity check.
183     No atomic ref pushing or force-with-lease options will prevent this ref
184     update from occurring since the `some-topic` branch is new on the server
185     and the rewind of the `master` branch has no effect on that.
187  5. Now garbage collection removes the unreachable objects (another lovely
188     race condition) including the rewound and discarded commit from the
189     `master` branch that the new `some-topic` branch needs thereby making the
190     `some-topic` branch corrupt.
192 Yes, a bunch of things have to happen in just the right order and at just the
193 right time for this to go wrong, but the race condition is there and there's
194 nothing that can be done to get rid of it (other than disallowing simultaneous
195 pushes which is not an available configuration option nor is it desirable).
197 The window for the race can be shrunk to a very small size, but there will
198 always be a moment after garbage collection does one last check to make sure
199 no refs have changed and it starts removing objects -- it is in that moment
200 that a ref can be changed to make the about-to-be-removed object reachable
201 again.  But then it gets removed anyway.
203 Girocco deals with this problem by making sure that objects stay around for
204 at least one day after they initially become unreachable.
206 It uses two mechanisms in combination to achieve this:
208  1. A pre-receive hook records both the old and new hash values for all ref
209     changes in a file in the `reflogs` subdirectory.  If it cannot record the
210     hash values for some reason it aborts the push.  (The update.sh script does
211     the same thing for mirrors to guarantee availability for ref change
212     notifications.)
214  2. As described later, Girocco's garbage collection consists of four phases.
215     During phase II, all valid recent hashes from the `reflogs` directory are
216     briefly resurrected to create a pack that contains all recently reachable
217     objects that are now unreachable.
219 The result is that any objects that have become unreachable within the last
220 day are always kept during gc.  (The interval is configurable to be longer,
221 but is always forced to be a minimum of one day.)
223 This gc behavior effectively eliminates the problem provided pushes don't take
224 more than a day (but that time limit could easily be extended if necessary by
225 simply bumping up the config item from the default of one day).
228 Shared Repositories
229 ~~~~~~~~~~~~~~~~~~~
231 Girocco keeps its Git repositories in shared mode.  In other words, the config
232 value core.sharedRepository is set to 1.
234 Unfortunately this creates issues.
236 Girocco runs various tasks as its "mirror" user.  These include jobd and taskd
237 which are together responsible for fetching new mirror updates, performing
238 garbage collection, cloning new repositories to be mirrored and sending out
239 ref change notifications.
241 Incoming pushes, however, run as either the web server user (for https pushes)
242 or one of various different ssh chroot jail users (for ssh pushes).
244 All three of these ("mirror" user, web server user and ssh chroot jail users)
245 need to be able to write to the repositories.  Hence core.sharedRepository = 1.
247 Regardless of the core.sharedRepository setting, Git insists on making loose
248 objects and pack files have file mode 0444 (readable by all, writable and
249 executable by none).
251 But this has an undesirable side effect.  Since mode 0444 files can only be
252 "touched" by the owner, only the initial creator of the loose object or pack
253 will be able to change its modification time (aka "freshen" it).
255 Girocco does not rely on "freshening" happening for normal Girocco operations.
257 However, Girocco now "tolerates" linked working trees to its repositories and
258 while it's not possible to eliminate the race described in (i) from occurring
259 when non-Girocco activities transition loose objects from unreachable to
260 reachable during a garbage collection, it can be minimized.
262 The "freshening" of loose objects (or their containing packs) plays a crucial
263 role in minimizing the race condition window.
265 For this reason, both the pre-receive hook and the garbage collection script
266 take great pains to make sure that loose objects and packs remain writable by
267 both owner and group.  By doing this the "touch"ing that happens when an object
268 that already exists is re-created will always effect a change in the
269 modification time of the files being touched thereby "freshening" them.
271 ------------
272 Fork Follies
273 ------------
275 Now that the simultaneous push and garbage collection are out of the way, what
276 about forks?
278 Forks use the Git alternates mechanism to borrow objects from their parent (aka
279 the "forkee") so they are not needlessly duplicated potentially wasting huge
280 amounts of space in the presence of many forks of the same large project.
282 The parent project has no way of knowing which, if any, of its objects are
283 reachable from its forks.  It could potentially discover that by doing a
284 reachability trace on the union of the refs from the entire set of forks of the
285 project, but that would be somewhat expensive and again subject to a race
286 condition with regard to incoming pushes during the reachability trace.
288 One way to prevent corruption of the forks would be to never remove any objects
289 at all.  Not very conducive to efficient disk space usage.
291 If a project has forks, during phase III of garbage collection, any objects
292 that are found to be unreachable and are currently in packs are repacked into
293 their own pack which is then hard-linked down to all child forks (but removed
294 from the project itself).
296 These special "unreachable" packs are given a unique extension and any such
297 packs received from a parent project are treated as .keep packs and also
298 hard-linked down into child forks along with any freshly generated phase III
299 pack.
301 Since Girocco garbage collection never removes loose objects but only redundant
302 packs this is enough to eliminate the problem.
304 (Loose objects are migrated into a "loose objects pack" but that pack then
305 remains until the following gc cycle thereby guaranteeing all loose objects a
306 minimum lifetime not withstanding untimely administrator intervention.)
308 --------------------
309 Linked Working Trees
310 --------------------
312 Along with the new order for garbage collection, Girocco now "tolerates" use
313 of linked working trees on its repositories.  Since there's little difference
314 between a linked working tree and a non-bare repository this could allow use
315 of non-bare repositories with Girocco too, but that's highly discouraged due
316 to the problems with pushing to a non-bare HEAD branch and shall not be
317 discussed any further.  ;)
319 (For those determined to pursue this option a `push-to-checkout` hook will
320 likely be required as well as setting the `receive.denyCurrentBranch` config
321 option along with Git version 2.4.0 or later.)
323 Girocco supports linked working trees by making sure that all objects reachable
324 from any index, ref log or detached HEAD that do not end up in the phase I pack
325 (and are not borrowed from an alternate) end up in the phase II pack.
327 Additionally, in order to minimize the window for race condition loss of
328 objects due to simultaneous garbage collection while, for example, creating a
329 new commit in a linked working tree, Girocco attempts to make sure that all
330 unreachable loose objects persist for at least one min_gc_interval time period.
332 Furthermore, if one of the redundant packs gets "freshened" during garbage
333 collection (which could happen during commit creation if one of the loose
334 objects being created already exists contained in a pack), that pack will not
335 be removed.  There's a very miniscule window where the check for "freshened"
336 packs could take place, not find any "freshened" packs, the pack gets freshened
337 immediately thereafter and then it gets removed anyway.
339 Can't be helped, Git does not have any <looseobject>.keep mechanism.  Girocco
340 itself avoids the problem, case (i) above, by preventing incoming pushes from
341 unpacking their packs.
343 If the miniscule race condition risk remains unacceptable, either linked
344 working trees must not be used, the time when Girocco garbage collection runs
345 must be strictly controlled or all updates must be pushed in from a clone that
346 does _not_ use the `--reference` mechanism to refer to the Girocco repository.
348 ----------------------------------
349 Girocco Garbage Collection Process
350 ----------------------------------
352 Girocco now uses the new order for garbage collection.
354 None of the "git gc", "git repack" or "git prune" commands are run either
355 directly or indirectly.  New packs are created via use of the
356 "git pack-objects" command.  The limited "pruning" that takes places involves
357 only pruning loose objects that are packed and removing redundant packs after
358 creating new all-in-one packs.
360 It is the removal of redundant packs that can permanently remove some
361 unreachable objects.
363 Girocco uses a four phase garbage collection strategy (the new order):
365   I) Create a new all-in-one pack (this pack may have a bitmap)
366  II) Create a pack of "recently reachable" objects and "friends"
367 III) Create a pack of "unreachable" objects if any child forks exist
368  IV) Migrate all remaining loose objects into a pack
370 Phase I corresponds basically to "git repack -a".  Note that there's no
371 deletion or removal going on during phase I.  Non-forks will get a bitmap (with
372 Git v2.1.0 or later) and this pack will serve as the "virtual bundle".
374 Phase II became possible when Girocco started keeping a record of ref changes
375 in the reflogs subdirectory (the pre-receive hook and the update.sh script are
376 responsible for this).  We simply do another full packing after adding
377 temporary refs for everything in the reflogs directory (that's not too old).
378 In a nod to linked working trees, anything reachable from ref logs, index files
379 or detached HEADs is included as "friends".  By manipulating the packing
380 options it's easy to exclude everything that was already packed in phase I.
382 Phase III will be skipped unless forks are present.  One more iteration over
383 the same set of refs Phase II used but passing the "--keep-unreachable" option
384 and excluding everything packed in either phase I or phase II (or in phase III
385 packs hard-linked into the fork from its parent) gives us this pack.  It won't
386 appear in the project itself, but will be hard-linked to all immediate child
387 forks (along with any phase III packs from the parent) which will in turn
388 hard-link it (and them) down to their children, if any, when they run gc.
390 At this point any non-keep packs that existed prior to phase I are removed
391 (this includes phase III packs that had been hard-linked down from the parent).
392 Special techniques are used to avoid a "Push Pack Redux" race and to not remove
393 any packs that have been "freshened" by some kind of simultaneous non-Girocco
394 loose object activity.
396 Phase IV is accomplished simply by packing all loose objects that are not
397 already in a phase I or phase II pack.  Any phase III packs are deliberately
398 excluded here in an attempt to make sure that any unreachable loose objects
399 live on for at least one min_gc_interval.
401 A final "git prune-packed" takes care of removing loose object detritus.
403 Unless there's some non-Girocco activity going on (such as in a linked working
404 tree) or objects are being discarded (non-fast-forward ref changes or ref
405 deletions), phases II, III and IV will never create any packs.
407 Phase III packs are hard-linked all the way to the bottom of the project's
408 fork tree as gc progresses through the tree so that the space they occupy does
409 not balloon up and get multiplied by the total number of forks as it would if
410 they were allowed to be repacked into a new phase III pack in each fork.
412 While this strategy may seem complex, it:
414  a) avoids ever creating loose objects for much better efficiency and speed
415  b) avoids corrupting forks that use the `alternates` mechanism
416  c) avoids using large amounts of disk space for packs containing mostly
417     redundant objects
418  d) maintains "recently become unreachable" objects long enough for meaningful
419     ref change notifications
420  e) presents a risk of corruption when simultaneous garbage collection occurs
421     during new commit creation that's approximately the same as non-Girocco
422     Git use would have
424 Overall this represents a huge improvement over hard-linking all the loose
425 object splatter created by "git repack -A -d" into child forks.
427 As part of this "new order," non-Girocco operations on the repository (such as
428 use of linked working trees) are now reluctantly "tolerated."
432 [1]: http://repo.or.cz/girocco.git/a7ea68a8a80e43d5
433      "gc: retain recently unreferenced objects for 1 day, 2015-10-02"