[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