Web lists-archives.com

Re: [PATCH v3 1/3] refs/files-backend: add longer-scoped copy of string to list




On Tue, Sep 5, 2017 at 10:45 AM, Jeff King <peff@xxxxxxxx> wrote:
> On Tue, Aug 29, 2017 at 07:18:22PM +0200, Martin Ågren wrote:
>
>> [...]
>> Rearrange the handling of `referent`, so that we don't add it directly
>> to `affected_refnames`. Instead, first just check whether `referent`
>> exists in the string list, and later add `new_update->refname`.
>
> Coincidentally[1] I came across this same leak, and my solution ended up
> slightly different. I'll share it here in case it's of interest.
>
> In your solution we end up searching the string list twice: once to see
> if we have the item, and then again to insert it. Whereas in the
> original we did both with a single search.
>
> But we can observe that either:
>
>   1. The item already existed, in which case our insert was a noop, and
>      we're good.
>
> or
>
>   2. We inserted it, in which case we proceed with creating new_update.
>
>      We can then in O(1) replace the pointer in the string list item
>      with the storage in new_update. We know we're not violating any
>      string_list invariants because the strings contain the same bytes.
>
> I.e.:
>
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 9266f5ab9d..1d16c1b33e 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -2178,6 +2178,11 @@ static int split_symref_update(struct files_ref_store *refs,
>         update->flags |= REF_LOG_ONLY | REF_NODEREF;
>         update->flags &= ~REF_HAVE_OLD;
>
> +       /*
> +        * Re-point at the storage provided by our ref_update, which we know
> +        * will last as long as the affected_refnames list.
> +        */
> +       item->string = new_update->refname;
>         item->util = new_update;
>
>         return 0;
>
> It feels pretty dirty, though. It would certainly be a bug if we ever
> decided to switch affected_refnames to duplicate its strings.
>
> So given that your solution is only a constant-time factor worse in
> efficiency, we should probably prefer it as the more maintainable
> option.

This is clever, but I don't like that it requires outside code to
change internal `string_list` structures in a way that is not
documented to be OK.

If we cared about getting rid of the extra `O(lg N)` search (and I
agree with you that it doesn't matter in this case), I think the clean
way to do it would be for `string_list` to expose a method like

    struct string_list_item *string_list_insert_at_index(struct
string_list *list, size_t index, const char *string);

and to use it, together with `string_list_find_insert_index()`, to
avoid having to search twice.

Michael