[Gluster-devel] RFC: functions and structure for generic refcounting

Niels de Vos ndevos at redhat.com
Sun May 31 23:20:23 UTC 2015


While looking into some of the races that seem possible in the new
auth-cache and netgroup/export features for Gluster/NFS, I noticed that
we do not really have a common way to do reference counting. I could
really use that, so I've put something together and would like to
request some comments on it.

Patch: http://review.gluster.org/11022

I'll add an example below, but the functions in the header are
commented too.

My plan is to use it to track and release auth-cache entries when the
exports/netgroups get refreshed (auth-cache invalidated). Because other
threads can still have a reference to the auth-cache entry, refcounting
(and appropriate locking of the main structure) is needed. A first shot
at the implementation is available too: http://review.gluster.org/11023
More datails about the actual issue have been sent to this list before:
http://thread.gmane.org/gmane.comp.file-systems.gluster.devel/11052/focus=11109

Comments are much appreciated. Thanks,
Niels


It can be used to automatically recylce a twig when all the grapes
attached to the twig have been plucked. For the record, we keep a
reference to all grapes in our 'growing_grapes' list too. Lets assume
our record keeping is *so* good, that we only need to go by the list to
know which grapes are ripe enough to pluck.

You might notice that I'm not a grape farmer ;-)


#include "refcount.h"

/* we track all the grapes of the plant, but only pluck the ripe ones */
list_head growing_grapes;
/* ripe grapes are removed from growing_grapes, and put in the basket */
list_head grape_basket;


/* a twig with grapes */
struct twig {
    struct gf_ref *ref;  /* for refcounting */

    struct plant *plant; /* plant attached to this twig */
}

/* a grape that is/was attached to a twig */
struct grape {
    struct twig *twig;   /* twig when still growing */
    unsigned int tasty;  /* mark from 1-10 on tastiness */
};


/* called by gf_ref_put() when all grapes have been plucked */
void
recycle_twig (void *to_free)
{
    struct twig *twig = (struct twig *) to_free;

    cut_from_plant (twig->plant);
    GF_FREE (twig);
}

/* you'll execute this whenever you pass the grapes plant */
void
check_grapes ()
{
    struct grape *grape = NULL;

    foreach_grape (grape, growing_grapes) {
        if (is_ripe (grape)) {
            list_del (grape, growing_grapes);

            /* the grape has been removed from the twig */
            twig = grape->twig;
            grape->twig = NULL;
            gf_ref_put (&twig->ref);
            /* the last gf_ref_put() will call recyle_twig() */

            /* put the grape in the basket */
            list_add (grape_basket, grape);
        }
    }
}

void
grow_new_grape (struct twig *twig)
{
    struct grape *grape = GF_MALLOC (sizeof (struct grape), gf_mt_grapes);

    if (gf_ref_get (&twig->ref) == 0) {
        /* oops, something went wrong! no locking implemented yet? */
        GF_FREE (grape);
        return;
    }

    grape->twig = twig;
    /* the grape has just started to grow */
    list_add (growing_grapes, grape);
}

/* there are many twigs with grapes on this plant */
struct twig *
grow_twig_with_grapes (struct plant *plant, int grape_count)
{
    int i = 0;
    struct twig *twig = GF_MALLOC (sizeof (struct twig), gf_mt_grapes);

    gf_ref_init (&twig->ref, recycle_twig, twig);
    /* recount has been set to 1 */

    grape->plant = plant;

    for (i = 0; i < grape_count; i++) {
        /* each grape increments the refcount on the twig */
        grow_grape (twig);
    }

    /* all grapes have been added and will start to grow */
    gf_ref_put (&twig->ref);
}

/* at one point you want to share your grapes with your colleagues */
void
eat_grapes()
{
    struct grape *grape = NULL;
    if (list_empty (grape_basket))
        /* sorry, no more grapes :-( */
        return;

    grape = list_remove_last (grape_backet);
    hmmm (grape);
}



More information about the Gluster-devel mailing list