Re: [PATCH 2/2] strbuf: allow to use preallocated memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



William Duclot <william.duclot@xxxxxxxxxxxxxxxxxxxxxxx> writes:

> Matthieu Moy <Matthieu.Moy@xxxxxxxxxxxxxxx> writes:
>
>> void strbuf_grow(struct strbuf *sb, size_t extra)
>> {
>> 	int new_buf = !sb->alloc;
>> ...
>> 	if (sb->flags & STRBUF_OWNS_MEMORY) {
>> 		if (new_buf) // <---------------------------------------- (1)
>> 			sb->buf = NULL;
>> 		ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
>> 	} else {
>> 		/*
>> 		 * The strbuf doesn't own the buffer: to avoid to realloc it,
>> 		 * the strbuf needs to use a new buffer without freeing the old
>> 		 */
>> 		if (sb->len + extra + 1 > sb->alloc) {
>> 			size_t new_alloc = MAX(sb->len + extra + 1, alloc_nr(sb->alloc));
>> 			char *buf = xmalloc(new_alloc);
>> 			memcpy(buf, sb->buf, sb->alloc);
>> 			sb->buf = buf;
>> 			sb->alloc = new_alloc;
>> 			sb->flags |= STRBUF_OWNS_MEMORY;
>> 		}
>> 	}
>> 
>> 	if (new_buf) // <---------------------------------------- (2)
>> 		sb->buf[0] = '\0';
>> }
>> 
>> I think (1) is now dead code, since sb->alloc == 0 implies that
>> STRBUF_OWNS_MEMORY is set. (2) seems redundant since you've just
>> memcpy-ed the existing '\0' into the buffer.
>
> You're right for (1), I hadn't noticed that.
> For (2), we'll still have to set sb->buf[new_alloc-1]='\0' after the memcpy, if we
> have sb->alloc==0 then the memcpy won't copy it.

That sounds like one more reason to memcpy len + 1 bytes, and you'll get
the '\0' copied.

>> After your patch, there are differences between
>> strbuf_wrap_preallocated() which I think are inconsistencies:
>> 
>> * strbuf_attach() does not check for NULL buffer, but it doesn't accept
>>   them either if I read correctly. It would make sense to add the check
>>   to strbuf_attach(), but it's weird to have the performance-critical
>>   oriented function do the expensive stuff that the
>>   non-performance-critical one doesn't.
>
> I agree that strbuf_attach should do the check (it seems strange that it
> doesn't already do it, as the "buffer never NULL" invariant is not new).
> I don't understand your "but" part, what "expensive stuff" are you talking
> about?

"expensive stuff" was an exageration for "== NULL" test. It's not that
expensive, but costs a tiny bit of CPU time.

> xmemdupz can only allocate the same size it will copy.

Indeed, so forget about it.

>>> +/**
>>> + * Allow the caller to give a pre-allocated piece of memory for the strbuf
>>> + * to use and indicate that the strbuf must use exclusively this buffer,
>>> + * never realloc() it or allocate a new one. It means that the string can
>>> + * be manipulated but cannot overflow the pre-allocated buffer. The
>>> + * pre-allocated buffer will never be freed.
>>> + */
>> 
>> Perhaps say explicitly that although the allocated buffer has a fixed
>> size, the string itself can grow as long as it does not overflow the
>> buffer?
>
> That's what I meant by "the string can be manipulated but cannot overflow
> the pre-allocated buffer". I'll try to reformulate

Maybe "the string can grow, but cannot overflow"?

>>> @@ -91,6 +116,8 @@ extern void strbuf_release(struct strbuf *);
>>>   * Detach the string from the strbuf and returns it; you now own the
>>>   * storage the string occupies and it is your responsibility from then on
>>>   * to release it with `free(3)` when you are done with it.
>>> + * Must allocate a copy of the buffer in case of a preallocated/fixed
>>> buffer.
>>> + * Performance-critical operations have to be aware of this.
>> 
>> Better than just warn about performance, you can give the alternative.
>
> I'm not sure what you mean, I don't think there really is an alternative for
> detaching a string?

So, is the comment above saying "You're doomed, there's no way you can
get good performance anyway"?

The alternative is just that you don't have to call strbuf_release since
the caller can access the .buf field and is already the one responsible
for freeing it when needed, and it's safe to just call strbuf_init() if
one needs to re-initialize the stbuf structure.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]