{"thread":{"id":"44813","subject":"Re: Preserve/Prune Old Pack Files","startedAt":"2017-01-04T16:12:04Z","lastAt":"2017-01-10T09:16:10Z","messageCount":7,"participants":["Martin Fick","Jeff King","Mike Hommey"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"308773","messageId":"5172470.bsscxDU4yv@mfick1-lnx","threadId":"44813","inReplyTo":"24abd0ed58c25ce832014f9bd5bb2090@codeaurora.org","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Martin Fick","fromEmail":"mfick@codeaurora.org","sentAt":"2017-01-04T16:11:55Z","receivedAt":"2017-01-04T16:12:04Z","isPatch":false,"sender":{"key":"mfick@codeaurora.org","avatar":null},"body":"I am replying to this email across lists because I wanted to \nhighlight to the git community this jgit change to repacking \nthat we have up for review\n\n https://git.eclipse.org/r/#/c/87969/\n\nThis change introduces a new convention for how to preserve \nold pack files in a staging area \n(.git/objects/packs/preserved) before deleting them.  I \nwanted to ensure that the new proposed convention would be \ndone in a way that would be satisfactory to the git \ncommunity as a whole so that it would be more easy to \nprovide the same behavior in git eventually.  The preserved \npack files (and accompanying index and bitmap files), are not \nonly moved, but they are also renamed so that they no longer \nwill match recursive finds looking for pack files.\n\nI look forward to any review (it need not happen on the \nchange, replies to this email would be fine also), in \nparticular with respect to the approach and naming \nconventions.\n\nThanks,\n\n-Martin\n\n\nOn Tuesday, January 03, 2017 02:46:12 PM \njmelvin@codeaurora.org wrote:\n> We’ve noticed cases where Stale File Handle Exceptions\n> occur during git operations, which can happen on users of\n> NFS repos when repacking is done on them.\n> \n> To address this issue, we’ve added two new options to the\n> JGit GC command:\n> \n> --preserve-oldpacks: moves old pack files into the\n> preserved subdirectory instead of deleting them after\n> repacking\n> \n> --prune-preserved: prunes old pack files from the\n> preserved subdirectory after repacking, but before\n> potentially moving the latest old pack files to this\n> subdirectory\n> \n> The strategy is to preserve old pack files around until\n> the next repack with the hopes that they will become\n> unreferenced by then and not cause any exceptions to\n> running processes when they are finally deleted (pruned).\n> \n> Change is uploaded for review here:\n> https://git.eclipse.org/r/#/c/87969/\n> \n> Thanks,\n> James\n\n-- \nThe Qualcomm Innovation Center, Inc. is a member of Code \nAurora Forum, hosted by The Linux Foundation\n\n"},{"id":"309000","messageId":"20170109062137.zghmurndlbts5x44@sigill.intra.peff.net","threadId":"44813","inReplyTo":"5172470.bsscxDU4yv@mfick1-lnx","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-09T06:21:37Z","receivedAt":"2017-01-09T06:21:45Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 04, 2017 at 09:11:55AM -0700, Martin Fick wrote:\n\n> I am replying to this email across lists because I wanted to \n> highlight to the git community this jgit change to repacking \n> that we have up for review\n> \n>  https://git.eclipse.org/r/#/c/87969/\n> \n> This change introduces a new convention for how to preserve \n> old pack files in a staging area \n> (.git/objects/packs/preserved) before deleting them.  I \n> wanted to ensure that the new proposed convention would be \n> done in a way that would be satisfactory to the git \n> community as a whole so that it would be more easy to \n> provide the same behavior in git eventually.  The preserved \n> pack files (and accompanying index and bitmap files), are not \n> only moved, but they are also renamed so that they no longer \n> will match recursive finds looking for pack files.\n\nIt looks like objects/pack/pack-123.pack becomes\nobjects/pack/preserved/pack-123.old-pack, and so forth.\nWhich seems reasonable, and I'm happy that:\n\n  find objects/pack -name '*.pack'\n\nwould not find it. :)\n\nI suspect the name-change will break a few tools that you might want to\nuse to look at a preserved pack (like verify-pack). I know that's not\nyour primary use case, but it seems plausible that somebody may one day\nwant to use a preserved pack to try to recover from corruption. I think\n\"git index-pack --stdin <objects/packs/preserved/pack-123.old-pack\"\ncould always be a last-resort for re-admitting the objects to the\nrepository.\n\nI notice this doesn't do anything for loose objects. I think they\ntechnically suffer the same issue, though the race window is much\nshorter (we mmap them and zlib inflate immediately, whereas packfiles\nmay stay mapped across many object requests).\n\nI have one other thought that's tangentially related.\n\nI've wondered if we could make object pruning more atomic by\nspeculatively moving items to be deleted into some kind of \"outgoing\"\nobject area. Right now you can have a case like:\n\n  0. We have a pack that has commit X, which is reachable, and commit Y,\n     which is not.\n\n  1. Process A is repacking. It walks the object graph and finds that X\n     is reachable. It begins creating a new pack with X and its\n     dependent objects.\n\n  2. Meanwhile, process B pushes up a merge of X and Y, and updates a\n     ref to point to it.\n\n  3. Process A finishes writing the new pack, and deletes the old one,\n     removing Y. The repository is now corrupt.\n\nI don't have a solution here.  I don't think we want to solve it by\nlocking the repository for updates during a repack. I have a vague sense\nthat a solution could be crafted around moving the old pack into a\nholding area instead of deleting (during which time nobody else would\nsee the objects, and thus not reference them), while the repacking\nprocess checks to see if the actual deletion would break any references\n(and rolls back the deletion if it would).\n\nThat's _way_ more complicated than your problem, and as I said, I do not\nhave a finished solution. But it seems like they touch on a similar\nconcept (a post-delete holding area for objects). So I thought I'd\nmention it in case if spurs any brilliance.\n\n-Peff\n"},{"id":"309001","messageId":"20170109070119.lite2o7k3t2wuvtt@glandium.org","threadId":"44813","inReplyTo":"20170109062137.zghmurndlbts5x44@sigill.intra.peff.net","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Mike Hommey","fromEmail":"mh@glandium.org","sentAt":"2017-01-09T07:01:19Z","receivedAt":"2017-01-09T07:01:29Z","isPatch":false,"sender":{"key":"mh@glandium.org","avatar":"https://avatars.githubusercontent.com/u/1038527?v=4"},"body":"On Mon, Jan 09, 2017 at 01:21:37AM -0500, Jeff King wrote:\n> On Wed, Jan 04, 2017 at 09:11:55AM -0700, Martin Fick wrote:\n> \n> > I am replying to this email across lists because I wanted to \n> > highlight to the git community this jgit change to repacking \n> > that we have up for review\n> > \n> >  https://git.eclipse.org/r/#/c/87969/\n> > \n> > This change introduces a new convention for how to preserve \n> > old pack files in a staging area \n> > (.git/objects/packs/preserved) before deleting them.  I \n> > wanted to ensure that the new proposed convention would be \n> > done in a way that would be satisfactory to the git \n> > community as a whole so that it would be more easy to \n> > provide the same behavior in git eventually.  The preserved \n> > pack files (and accompanying index and bitmap files), are not \n> > only moved, but they are also renamed so that they no longer \n> > will match recursive finds looking for pack files.\n> \n> It looks like objects/pack/pack-123.pack becomes\n> objects/pack/preserved/pack-123.old-pack, and so forth.\n> Which seems reasonable, and I'm happy that:\n> \n>   find objects/pack -name '*.pack'\n> \n> would not find it. :)\n> \n> I suspect the name-change will break a few tools that you might want to\n> use to look at a preserved pack (like verify-pack). I know that's not\n> your primary use case, but it seems plausible that somebody may one day\n> want to use a preserved pack to try to recover from corruption. I think\n> \"git index-pack --stdin <objects/packs/preserved/pack-123.old-pack\"\n> could always be a last-resort for re-admitting the objects to the\n> repository.\n> \n> I notice this doesn't do anything for loose objects. I think they\n> technically suffer the same issue, though the race window is much\n> shorter (we mmap them and zlib inflate immediately, whereas packfiles\n> may stay mapped across many object requests).\n> \n> I have one other thought that's tangentially related.\n> \n> I've wondered if we could make object pruning more atomic by\n> speculatively moving items to be deleted into some kind of \"outgoing\"\n> object area. Right now you can have a case like:\n> \n>   0. We have a pack that has commit X, which is reachable, and commit Y,\n>      which is not.\n> \n>   1. Process A is repacking. It walks the object graph and finds that X\n>      is reachable. It begins creating a new pack with X and its\n>      dependent objects.\n> \n>   2. Meanwhile, process B pushes up a merge of X and Y, and updates a\n>      ref to point to it.\n> \n>   3. Process A finishes writing the new pack, and deletes the old one,\n>      removing Y. The repository is now corrupt.\n> \n> I don't have a solution here.  I don't think we want to solve it by\n> locking the repository for updates during a repack. I have a vague sense\n> that a solution could be crafted around moving the old pack into a\n> holding area instead of deleting (during which time nobody else would\n> see the objects, and thus not reference them), while the repacking\n> process checks to see if the actual deletion would break any references\n> (and rolls back the deletion if it would).\n> \n> That's _way_ more complicated than your problem, and as I said, I do not\n> have a finished solution. But it seems like they touch on a similar\n> concept (a post-delete holding area for objects). So I thought I'd\n> mention it in case if spurs any brilliance.\n\nSomething that is kind-of in the same family of problems is the\n\"loosening\" or objects on repacks, before they can be pruned.\n\nWhen you have a large repository and do large rewrite operations\n(extreme case, a filter-branch on a multi-hundred-thousands commits),\nand you gc for the first time, git will possibly create a *lot* of loose\nobjects, each of which will consume an inode and a file system block. In\nthe extreme case, you can end up with git gc filling up multiple extra\ngigabytes on your disk.\n\nMike\n"},{"id":"309020","messageId":"20170109105545.gchfklcuzwhlfbtf@sigill.intra.peff.net","threadId":"44813","inReplyTo":"20170109070119.lite2o7k3t2wuvtt@glandium.org","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-09T10:55:45Z","receivedAt":"2017-01-09T10:57:09Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 09, 2017 at 04:01:19PM +0900, Mike Hommey wrote:\n\n> > That's _way_ more complicated than your problem, and as I said, I do not\n> > have a finished solution. But it seems like they touch on a similar\n> > concept (a post-delete holding area for objects). So I thought I'd\n> > mention it in case if spurs any brilliance.\n> \n> Something that is kind-of in the same family of problems is the\n> \"loosening\" or objects on repacks, before they can be pruned.\n> \n> When you have a large repository and do large rewrite operations\n> (extreme case, a filter-branch on a multi-hundred-thousands commits),\n> and you gc for the first time, git will possibly create a *lot* of loose\n> objects, each of which will consume an inode and a file system block. In\n> the extreme case, you can end up with git gc filling up multiple extra\n> gigabytes on your disk.\n\nI think we're getting pretty far off-field here. :)\n\nYes, this can be a problem. The repack is smart enough not to write out\nobjects which would just get pruned immediately, but since the grace\nperiod is 2 weeks, that can include a lot of objects (especially with\nhistory rewriting as you note). It would be possible to write those\nloose objects to a \"cruft\" pack, but there are some management issues\naround the cruft pack. You do not want to keep repacking them into a new\ncruft pack at each repack, since then they would never expire. So you\nneed some way of marking the pack as cruft, letting it age out, and then\ndeleting it after the grace period expires.\n\nI don't think it would be _that_ hard, but AFAIK nobody has ever made\npatches.\n\n-Peff\n"},{"id":"309040","messageId":"1802755.dVE0WDQbpH@mfick1-lnx","threadId":"44813","inReplyTo":"20170109062137.zghmurndlbts5x44@sigill.intra.peff.net","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Martin Fick","fromEmail":"mfick@codeaurora.org","sentAt":"2017-01-09T16:17:56Z","receivedAt":"2017-01-09T16:18:16Z","isPatch":false,"sender":{"key":"mfick@codeaurora.org","avatar":null},"body":"On Monday, January 09, 2017 01:21:37 AM Jeff King wrote:\n> On Wed, Jan 04, 2017 at 09:11:55AM -0700, Martin Fick \nwrote:\n> > I am replying to this email across lists because I\n> > wanted to highlight to the git community this jgit\n> > change to repacking that we have up for review\n> > \n> >  https://git.eclipse.org/r/#/c/87969/\n> > \n> > This change introduces a new convention for how to\n> > preserve old pack files in a staging area\n> > (.git/objects/packs/preserved) before deleting them.  I\n> > wanted to ensure that the new proposed convention would\n> > be done in a way that would be satisfactory to the git\n> > community as a whole so that it would be more easy to\n> > provide the same behavior in git eventually.  The\n> > preserved pack files (and accompanying index and bitmap\n> > files), are not only moved, but they are also renamed\n> > so that they no longer will match recursive finds\n> > looking for pack files.\n> It looks like objects/pack/pack-123.pack becomes\n> objects/pack/preserved/pack-123.old-pack,\n\nYes, that's the idea.\n\n> and so forth. Which seems reasonable, and I'm happy that:\n> \n>   find objects/pack -name '*.pack'\n> \n> would not find it. :)\n\nCool.\n\n> I suspect the name-change will break a few tools that you\n> might want to use to look at a preserved pack (like\n> verify-pack).  I know that's not your primary use case,\n> but it seems plausible that somebody may one day want to\n> use a preserved pack to try to recover from corruption. I\n> think \"git index-pack --stdin\n> <objects/packs/preserved/pack-123.old-pack\" could always\n> be a last-resort for re-admitting the objects to the\n> repository.\n\nor even a simple manual rename/move back to its orginal \nplace?\n\n> I notice this doesn't do anything for loose objects. I\n> think they technically suffer the same issue, though the\n> race window is much shorter (we mmap them and zlib\n> inflate immediately, whereas packfiles may stay mapped\n> across many object requests).\n\nHmm, yeah that's the next change, didn't you see it? :)  No, \nactually I forgot about those.  Our server tends to not have \ntoo many of those (loose objects), and I don't think we have \nseen any exceptions yet for them.  But, of course, you are \nright, they should get fixed too.  I will work on a followup \nchange to do that.\n\nWhere would you suggest we store those?  Maybe under \n\".git/objects/preserved/<xx>/<sha1>\"?  Do they need to be \nrenamed also somehow to avoid a find?\n\n...\n> I've wondered if we could make object pruning more atomic\n> by speculatively moving items to be deleted into some\n> kind of \"outgoing\" object area.\n...\n> I don't have a solution here.  I don't think we want to\n> solve it by locking the repository for updates during a\n> repack. I have a vague sense that a solution could be\n> crafted around moving the old pack into a holding area\n> instead of deleting (during which time nobody else would\n> see the objects, and thus not reference them), while the\n> repacking process checks to see if the actual deletion\n> would break any references (and rolls back the deletion\n> if it would).\n> \n> That's _way_ more complicated than your problem, and as I\n> said, I do not have a finished solution. But it seems\n> like they touch on a similar concept (a post-delete\n> holding area for objects). So I thought I'd mention it in\n> case if spurs any brilliance.\n\nI agree, this is a problem I have wanted to solve also.  I \nthink having a \"preserved\" directory does open the door to \nsuch \"recovery\" solutions, although I think you would \nactually want to modify the many read code paths to fall \nback to looking at the preserved area and performing \nimmediate \"recovery\" of the pack file if it ends up being \nneeded.  That's a lot of work, but having the packs (and \neventually the loose objects) preserved into a location \nwhere no new references will be built to depend on them is \nlikely the first step.  Does the name \"preserved\" do well for \nthat use case also, or would there be some better name, what \nwould a transactional system call them?\n\nThanks for the review Peff!\n\n-Martin\n\n\n-- \nThe Qualcomm Innovation Center, Inc. is a member of Code \nAurora Forum, hosted by The Linux Foundation\n\n"},{"id":"309041","messageId":"3341131.K6hMDMB8iT@mfick1-lnx","threadId":"44813","inReplyTo":"20170109105545.gchfklcuzwhlfbtf@sigill.intra.peff.net","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Martin Fick","fromEmail":"mfick@codeaurora.org","sentAt":"2017-01-09T16:20:05Z","receivedAt":"2017-01-09T16:22:59Z","isPatch":false,"sender":{"key":"mfick@codeaurora.org","avatar":null},"body":"On Monday, January 09, 2017 05:55:45 AM Jeff King wrote:\n> On Mon, Jan 09, 2017 at 04:01:19PM +0900, Mike Hommey \nwrote:\n> > > That's _way_ more complicated than your problem, and\n> > > as I said, I do not have a finished solution. But it\n> > > seems like they touch on a similar concept (a\n> > > post-delete holding area for objects). So I thought\n> > > I'd mention it in case if spurs any brilliance.\n> > \n> > Something that is kind-of in the same family of problems\n> > is the \"loosening\" or objects on repacks, before they\n> > can be pruned.\n...\n> Yes, this can be a problem. The repack is smart enough not\n> to write out objects which would just get pruned\n> immediately, but since the grace period is 2 weeks, that\n> can include a lot of objects (especially with history\n> rewriting as you note). It would be possible to write\n> those loose objects to a \"cruft\" pack, but there are some\n> management issues around the cruft pack. You do not want\n> to keep repacking them into a new cruft pack at each\n> repack, since then they would never expire. So you need\n> some way of marking the pack as cruft, letting it age\n> out, and then deleting it after the grace period expires.\n> \n> I don't think it would be _that_ hard, but AFAIK nobody\n> has ever made patches.\n\nFYI, jgit does this,\n\n-Martin\n\n-- \nThe Qualcomm Innovation Center, Inc. is a member of Code \nAurora Forum, hosted by The Linux Foundation\n\n"},{"id":"309131","messageId":"20170110091426.n6qnh6szgdojp6zw@sigill.intra.peff.net","threadId":"44813","inReplyTo":"1802755.dVE0WDQbpH@mfick1-lnx","subject":"Re: Preserve/Prune Old Pack Files","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-01-10T09:14:26Z","receivedAt":"2017-01-10T09:16:10Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 09, 2017 at 09:17:56AM -0700, Martin Fick wrote:\n\n> > I suspect the name-change will break a few tools that you\n> > might want to use to look at a preserved pack (like\n> > verify-pack).  I know that's not your primary use case,\n> > but it seems plausible that somebody may one day want to\n> > use a preserved pack to try to recover from corruption. I\n> > think \"git index-pack --stdin\n> > <objects/packs/preserved/pack-123.old-pack\" could always\n> > be a last-resort for re-admitting the objects to the\n> > repository.\n> \n> or even a simple manual rename/move back to its orginal \n> place?\n\nYes, that would work. There's not a tool to do it, but it's a fairly\nstraightforward transformation.\n\n> [loose objects]\n> Where would you suggest we store those?  Maybe under \n> \".git/objects/preserved/<xx>/<sha1>\"?  Do they need to be \n> renamed also somehow to avoid a find?\n\nIt would make sense to me to have a single \"preserved\" root, with\n\"<xx>/<sha1>.old\" and \"packs/pack-<sha1>.old-pack\" together under it.\n\nYou could also move the objects out of objects/ entirely. Say, to\n\".git/preserved-objects\" or something. Then you could probably do away\nwith the filename munging altogether, and \"restoring\" an object or pack\nwould be a simple \"mv\" or \"cp\" (or you could even add preserved-objects\nto $GIT_ALTERNATE_OBJECT_DIRECTORIES if you wanted to do a single\noperation looking at both sets).\n\nThat's all outside the scope of your original purpose (which I think was\njust to keep the files _somewhere_ so that the open descriptor stays\nvalid on NFS). But maybe it would make other related things more\nconvenient. I dunno. I'm just speaking off the top of my head.\n\n> > That's _way_ more complicated than your problem, and as I\n> > said, I do not have a finished solution. But it seems\n> > like they touch on a similar concept (a post-delete\n> > holding area for objects). So I thought I'd mention it in\n> > case if spurs any brilliance.\n> \n> I agree, this is a problem I have wanted to solve also.  I \n> think having a \"preserved\" directory does open the door to \n> such \"recovery\" solutions, although I think you would \n> actually want to modify the many read code paths to fall \n> back to looking at the preserved area and performing \n> immediate \"recovery\" of the pack file if it ends up being \n> needed.\n\nIn my (admittedly not very concrete) plan, the read code paths\n_wouldn't_ know to look in the preserved area. It would be up to the\nrepacking process to rollback in case of a race. That does open a period\n(between the faux delete and the rollback) where readers may be broken.\nBut that's much better than the state today, which is that the readers\nare broken, and that breakage persists forever.\n\nBut there may be other better ways of doing it.  What we're really\ntalking about is a transactional system where neither side locks (or at\nleast not for an appreciable amount of time), and one side is capable of\nfalling back and modifying its operation when there's a relevant race.\nThere's probably some research in this area and some standard solutions,\nbut it's not an area I'm overly familiar with (and building any solution\non top of POSIX filesystem semantics adds an extra challenge).\n\n> That's a lot of work, but having the packs (and \n> eventually the loose objects) preserved into a location \n> where no new references will be built to depend on them is \n> likely the first step.  Does the name \"preserved\" do well for \n> that use case also, or would there be some better name, what \n> would a transactional system call them?\n\nI wasn't going to bikeshed, but since you ask...:)\n\n\"preserved\" to me sounds like something we'd be keeping forever. These\nobjects are more in a \"pending delete\" state, or a purgatory. Maybe\nsomething along those lines would be more appropriate.\n\n-Peff\n"}]}