[syslog-ng] Per-thread scratch buffers

Balazs Scheidler bazsi at balabit.hu
Mon Oct 31 21:38:50 CET 2011


On Mon, 2011-10-31 at 10:16 +0100, Gergely Nagy wrote:
> Balazs Scheidler <bazsi at balabit.hu> writes:
> 
> > The alternative idea I was playing with was to create a new API for
> > managing per-thread scratch buffers that could be reused even between
> > multiple independent portions of syslog-ng.
> >
> > The way it would work:
> >   - scratch buffers are a numbered array of GString buffers, allocated
> >     for _each_ thread.
> 
> Any reason we want per-thread scratch buffers? Apart from not needing to
> use a lock in this case..

that's the point, and to keep GString instances around.

> 
> As a first step in implementing this, I had something like the following
> in mind:
> 
> static GTrashStack *scratch_buffers;
> 
> GString *scratch_buffer_acquite (void)

a typo in the function name.

> {
>   GString *s;
> 
>   s = g_trash_stack_pop (scratch_buffers);
>   if (!s)
>     s = g_string_new (NULL);
>   else
>     g_string_set_size (s, 0);
>   return s;
> }

are you sure that once you get your GString instance back from
GTrashStack, it'll be a valid GString?

GTrashStack seems to corrupt the first pointer of each data block pushed
to it (which is the "str" pointer in this case).

> 
> void scratch_buffer_release (GString *s)
> {
>   g_trash_stack_push (s);
> }
> 
> void scratch_buffers_reset (void)
> {
>   GString *s;
> 
>   while ((s = g_trash_stack_pop (scratch_buffers)) != NULL)
>     g_string_free (s, TRUE);
> }

I wouldn't want to free the GString instances, but reuse them. This is
the other point: to avoid having to allocate new GString instances all
the time.

The implementation I had in mind was:
  - dynamically sized array of GString instances (per-thread)
  - a stack pointer that contains the index within the array where we
    are at. Items below the pointer are used, above are not.
  - acquire: if there are unused items in the array, return it and
    increase the pointer. if there are no unused items, allocate new and
    store it in the array.
  - release: if the item to be freed is the one handed out last,
    decrement the pointer, else do nothing.
  - reset: reset the pointer to 0.

This way: 
  - the number of GString instances depend on their usage.
  - GStrings are only allocated rarely, if the parallel number of
    GString buffers increase for some reason.
  - no need for locking as scratch buffers are per-thread

Of course it only shows its potential if all the similar cases already
in the code are converted to scratch buffers (log_template_format,
template functions, value-pairs, etc).

> 
> The expected usage is to acquire a buffer when needed, and release it
> whenever we don't need it anymore.
> 
> Spice it up with some __tls_deref & similar, and we're pretty much done,
> I think.
> 
> What do you think? (Meanwhile, I'll go ahead and see if this works)
> 

-- 
Bazsi




More information about the syslog-ng mailing list