[Gluster-devel] RFC: functions and structure for generic refcounting
Niels de Vos
ndevos at redhat.com
Thu Jun 4 10:56:27 UTC 2015
On Mon, Jun 01, 2015 at 06:28:18AM -0400, Krishnan Parthasarathi wrote:
>
> > 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
>
> Much needed unification of ref-counting mechanisms in our code base!
>
> We should avoid exporting gf_ref_{alloc, free}. It would make different life-times
> for the ref-counted object and the gf_ref_t object possible (without a seg-fault).
> i.e, ref-counted object could be around even after the last put has been called on
> the corresponding gf_ref_t object (if gf_release_t wasn't defined at all).
> It puts an extra burden on the reader trying to reason with ref-counted objects' lifetime
> during coredump analysis. If we made embedded gf_ref_t objects the only possible way
> to extend ref-counting to your favourite object, we would have the following neat property.
>
> - gf_ref_t->ref is "out of bounds" if the corresponding container is "out of bounds".
>
> and its converse. Two theorems for free, by construction.
Thanks for the comments. I've removed the gf_ref_alloc() and
gf_ref_free() functions in the updated change. Instead of a "struct
gf_ref", I made it a typedef "gf_ref_t" which hopefully is less likely
to get pointered at and more likely to get embedded in a struct.
For this change, and eventual follow up changes that rewrite existing
reference counters to use it, I have opened bug 1228157:
https://bugzilla.redhat.com/show_bug.cgi?id=1228157
Provide and use a common way to do reference counting of (internal) structures
More feedback on http://review.gluster.org/11022 is much appreciated.
Comments with "yes, I like the idea" are also good, if you do not feel
comfortable with reviewing the code.
Thanks,
Niels
> P.S This doesn't prevent consumers from defining their helpers for alloc/free
> where they absolutely need it. Niels' NFS netgroup fix didn't need it.
>
>
> > 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 ;-)
>
> Grape collection is a more fruitful name to what we have known as
> garbage collection all these years. sigh!
>
> >
> >
> > #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 :-( */
>
> sour grapes?
>
More information about the Gluster-devel
mailing list