{"thread":{"id":"38479","subject":"[PATCH 1/2] t5710-info-alternate: demonstrate bug in unpacked pruning","startedAt":"2015-02-01T21:55:00Z","lastAt":"2015-02-02T18:37:57Z","messageCount":5,"participants":["Jonathon Mah","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"255492","messageId":"BF4AA771-DEB5-4DED-9C74-768036C1E2DD@jonathonmah.com","threadId":"38479","inReplyTo":null,"subject":"[PATCH 1/2] t5710-info-alternate: demonstrate bug in unpacked pruning","fromName":"Jonathon Mah","fromEmail":"me@jonathonmah.com","sentAt":"2015-02-01T21:55:00Z","receivedAt":"2015-02-01T21:55:00Z","isPatch":true,"sender":{"key":"me@jonathonmah.com","avatar":"https://avatars.githubusercontent.com/u/2748?v=4"},"body":"Signed-off-by: Jonathon Mah <me@JonathonMah.com>\n---\n t/t5710-info-alternate.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh\nindex 5a6e49d..d82844a 100755\n--- a/t/t5710-info-alternate.sh\n+++ b/t/t5710-info-alternate.sh\n@@ -18,6 +18,7 @@ reachable_via() {\n \n test_valid_repo() {\n \tgit fsck --full > fsck.log &&\n+\tgit prune &&\n \ttest_line_count = 0 fsck.log\n }\n \n@@ -47,8 +48,7 @@ test_expect_success 'preparing third repository' \\\n 'git clone -l -s B C && cd C &&\n echo \"Goodbye, cruel world\" > file3 &&\n git add file3 &&\n-git commit -m \"one more\" file3 &&\n-git repack -a -d -l &&\n+git commit -m \"one more without packing\" file3 &&\n git prune'\n \n cd \"$base_dir\"\n-- \n2.3.0.rc2.2.g184f7a0\n"},{"id":"255493","messageId":"50251CB8-0885-40FF-A7C9-9C9460266E14@jonathonmah.com","threadId":"38479","inReplyTo":"BF4AA771-DEB5-4DED-9C74-768036C1E2DD@jonathonmah.com","subject":"[PATCH 2/2] sha1_file: fix iterating loose alternate objects","fromName":"Jonathon Mah","fromEmail":"me@jonathonmah.com","sentAt":"2015-02-01T21:55:33Z","receivedAt":"2015-02-01T21:55:33Z","isPatch":true,"sender":{"key":"me@jonathonmah.com","avatar":"https://avatars.githubusercontent.com/u/2748?v=4"},"body":"The string in 'base' contains a path suffix to a specific object; when\nits value is used, the suffix must either be filled (as in\nstat_sha1_file, open_sha1_file, check_and_freshen_nonlocal) or cleared\n(as in prepare_packed_git) to avoid junk at the end.  loose_from_alt_odb\n(introduced in 660c889e46d185dc98ba78963528826728b0a55d) did neither and\ntreated 'base' as a complete path to the \"base\" object directory,\ninstead of a pointer to the \"base\" of the full path string.\n\nThe trailing path after 'base' is still initialized to NUL, hiding the\nbug in some common cases.  Additionally the descendent\nfor_each_file_in_obj_subdir function swallows ENOENT, so an error only\nshows if the alternate's path was last filled with a valid object\n(where statting /path/to/existing/00/0bjectfile/00 fails).\n\nSigned-off-by: Jonathon Mah <me@JonathonMah.com>\n---\n sha1_file.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 30995e6..fcb1c4b 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3396,9 +3396,13 @@ static int loose_from_alt_odb(struct alternate_object_database *alt,\n \t\t\t      void *vdata)\n {\n \tstruct loose_alt_odb_data *data = vdata;\n-\treturn for_each_loose_file_in_objdir(alt->base,\n-\t\t\t\t\t     data->cb, NULL, NULL,\n-\t\t\t\t\t     data->data);\n+\tint r;\n+\talt->name[-1] = 0;\n+\tr = for_each_loose_file_in_objdir(alt->base,\n+\t\t\t\t\t  data->cb, NULL, NULL,\n+\t\t\t\t\t  data->data);\n+\talt->name[-1] = '/';\n+\treturn r;\n }\n \n int for_each_loose_object(each_loose_object_fn cb, void *data)\n-- \n2.3.0.rc2.2.g184f7a0\n"},{"id":"255518","messageId":"20150202175259.GA24025@peff.net","threadId":"38479","inReplyTo":"50251CB8-0885-40FF-A7C9-9C9460266E14@jonathonmah.com","subject":"Re: [PATCH 2/2] sha1_file: fix iterating loose alternate objects","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-02-02T17:53:00Z","receivedAt":"2015-02-02T17:53:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Feb 01, 2015 at 01:55:33PM -0800, Jonathon Mah wrote:\n\n> The string in 'base' contains a path suffix to a specific object; when\n> its value is used, the suffix must either be filled (as in\n> stat_sha1_file, open_sha1_file, check_and_freshen_nonlocal) or cleared\n> (as in prepare_packed_git) to avoid junk at the end.  loose_from_alt_odb\n> (introduced in 660c889e46d185dc98ba78963528826728b0a55d) did neither and\n> treated 'base' as a complete path to the \"base\" object directory,\n> instead of a pointer to the \"base\" of the full path string.\n> \n> The trailing path after 'base' is still initialized to NUL, hiding the\n> bug in some common cases.  Additionally the descendent\n> for_each_file_in_obj_subdir function swallows ENOENT, so an error only\n> shows if the alternate's path was last filled with a valid object\n> (where statting /path/to/existing/00/0bjectfile/00 fails).\n\nThanks for catching this, and for a nice explanation.\n\n> diff --git a/sha1_file.c b/sha1_file.c\n> index 30995e6..fcb1c4b 100644\n> --- a/sha1_file.c\n> +++ b/sha1_file.c\n> @@ -3396,9 +3396,13 @@ static int loose_from_alt_odb(struct alternate_object_database *alt,\n>  \t\t\t      void *vdata)\n>  {\n>  \tstruct loose_alt_odb_data *data = vdata;\n> -\treturn for_each_loose_file_in_objdir(alt->base,\n> -\t\t\t\t\t     data->cb, NULL, NULL,\n> -\t\t\t\t\t     data->data);\n> +\tint r;\n> +\talt->name[-1] = 0;\n> +\tr = for_each_loose_file_in_objdir(alt->base,\n> +\t\t\t\t\t  data->cb, NULL, NULL,\n> +\t\t\t\t\t  data->data);\n> +\talt->name[-1] = '/';\n> +\treturn r;\n>  }\n\nI think this is probably the best fix, and is the pattern we use\nelsewhere when touching alt->base.\n\nWe _could_ further change this to have for_each_loose_file_in_objdir\nactually use alt->base as its scratch buffer, writing the object\nfilenames into the end of it (i.e., what it was designed for). But:\n\n  1. We still need a strbuf scratch-buffer for the non-alternate object\n     directory. So we'd have to push more code there to over-allocate\n     the buffer, and then for_each_loose_file_in_objdir would assume\n     we always feed it a buffer with the extra slop. That would work,\n     but I find the strbuf approach a little safer; there's not an\n     implicit over-allocation far away in the code preventing us from\n     overflowing a buffer.\n\n  2. The reason for the existing alt->base behavior is that the\n     sha1_file code gets fed objects one at a time, and don't want to\n     pay strbuf overhead for each. With the iterator, we know we are\n     going to hit a bunch of objects, so we only have to pay the strbuf\n     overhead once for the iteration. So there's not the same\n     performance penalty, and we can stick with the strbuf if we prefer\n     it.\n\n-Peff\n"},{"id":"255519","messageId":"20150202175622.GB24025@peff.net","threadId":"38479","inReplyTo":"BF4AA771-DEB5-4DED-9C74-768036C1E2DD@jonathonmah.com","subject":"Re: [PATCH 1/2] t5710-info-alternate: demonstrate bug in unpacked pruning","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-02-02T17:56:22Z","receivedAt":"2015-02-02T17:56:22Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Feb 01, 2015 at 01:55:00PM -0800, Jonathon Mah wrote:\n\n> Signed-off-by: Jonathon Mah <me@JonathonMah.com>\n> ---\n>  t/t5710-info-alternate.sh | 4 ++--\n>  1 file changed, 2 insertions(+), 2 deletions(-)\n> \n> diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh\n> index 5a6e49d..d82844a 100755\n> --- a/t/t5710-info-alternate.sh\n> +++ b/t/t5710-info-alternate.sh\n> @@ -18,6 +18,7 @@ reachable_via() {\n>  \n>  test_valid_repo() {\n>  \tgit fsck --full > fsck.log &&\n> +\tgit prune &&\n>  \ttest_line_count = 0 fsck.log\n>  }\n>  \n> @@ -47,8 +48,7 @@ test_expect_success 'preparing third repository' \\\n>  'git clone -l -s B C && cd C &&\n>  echo \"Goodbye, cruel world\" > file3 &&\n>  git add file3 &&\n> -git commit -m \"one more\" file3 &&\n> -git repack -a -d -l &&\n> +git commit -m \"one more without packing\" file3 &&\n>  git prune'\n\nModifying a test like this makes me a little nervous because now the old\ntest is not checking the same thing (pruning when we are packed), and\nit's not obvious whether the packing was important to the original test.\n\nAnd it's not clear that this change is testing a totally unrelated\nthing.  I haven't looked closely, but would it be hard to introduce a\nnew test that more explicitly checks for the breakage?\n\n-Peff\n"},{"id":"255523","messageId":"9215E7CF-4A6C-48ED-8A63-76085D5B151A@jonathonmah.com","threadId":"38479","inReplyTo":"20150202175259.GA24025@peff.net","subject":"Re: [PATCH 2/2] sha1_file: fix iterating loose alternate objects","fromName":"Jonathon Mah","fromEmail":"me@jonathonmah.com","sentAt":"2015-02-02T18:37:57Z","receivedAt":"2015-02-02T18:37:57Z","isPatch":true,"sender":{"key":"me@jonathonmah.com","avatar":"https://avatars.githubusercontent.com/u/2748?v=4"},"body":"> On 2015-02-02, at 09:53, Jeff King <peff@peff.net> wrote:\n> \n> I think this is probably the best fix, and is the pattern we use\n> elsewhere when touching alt->base.\n> \n> We _could_ further change this to have for_each_loose_file_in_objdir\n> actually use alt->base as its scratch buffer, writing the object\n> filenames into the end of it (i.e., what it was designed for). But:\n> \n>  1. We still need a strbuf scratch-buffer for the non-alternate object\n>     directory. So we'd have to push more code there to over-allocate\n>     the buffer, and then for_each_loose_file_in_objdir would assume\n>     we always feed it a buffer with the extra slop. That would work,\n>     but I find the strbuf approach a little safer; there's not an\n>     implicit over-allocation far away in the code preventing us from\n>     overflowing a buffer.\n> \n>  2. The reason for the existing alt->base behavior is that the\n>     sha1_file code gets fed objects one at a time, and don't want to\n>     pay strbuf overhead for each. With the iterator, we know we are\n>     going to hit a bunch of objects, so we only have to pay the strbuf\n>     overhead once for the iteration. So there's not the same\n>     performance penalty, and we can stick with the strbuf if we prefer\n>     it.\n\nThanks for your feedback. I considered the same, and came to a similar conclusion. The strbuf cost is only once per alternate, so I feel on balance it's more robust to use alt->base consistently inside each function, rather than have this a more fragile special case to save allocation of only one path.\n\nUpdated the test patch.\n\n\nJonathon Mah\nme@JonathonMah.com\n"}]}