libmemcache, various minor questions

John McCaskey johnm at klir.com
Tue Dec 7 11:32:04 PST 2004


Thanks Sean!

On Tue, 2004-12-07 at 11:25 -0800, Sean Chittenden wrote:
> > I believe that the following lines in libmemcache.c are causing free on
> > delete to always be set when using mc_aget()...
> >
> > (lines 482, 483)
> > if (res->_flags & (MC_RES_FREE_ON_DELETE | MC_RES_NO_FREE_ON_DELETE))
> >       mc_res_free_on_delete(res, (res->size > 0 ? 0 : 1));
> >
> >
> > Looks like if either free_on_delete, or no_free_on delete was set, then
> > the check based off res->size occurs, res->size seems to always be 0 at
> > this point when using mc_aget, so free_on_delete gets reset to be on,
> > even though it was explicitly set off just moments ago in the mc_aget
> > function.
> 
> I'm using (MC_RES_FREE_ON_DELETE | MC_RES_NO_FREE_ON_DELETE) as the 
> default value meaning it hasn't been set and the library should try to 
> automatically detect if it should free on delete or not.  Imagine the 
> following:
> 
> > struct memcache_res *res = mc_req_add(req, key3, key3_len);
> > res->size = 1024;				/* Allocate our own memory a head of time (useful 
> > for loops) */
> > res->val = malloc(res->size);
> > mc_get(mc, req);
> > mc_res_free(req, res);
> 
> The 'res->size = 1024' bit tells libmemcache(3) to not worry about the 
> allocation/deallocation of res->val.  One can also call
> 
> > mc_res_free_on_delete(res, 1);
> 
> so that when someone does
> 
> > mc_res_free(req, res);
> 
> it will free res and res->val.
> 
> > Am I right?  I'm not clear to me what should be done about this, 
> > because
> > I think the check is there to allow the memory pre-allocation that I 
> > see
> > in some of your examples, but on the other hand it looks like it's
> > causing all users of mc_aget to recieve a pointer to already freed
> > memory.
> 
> The problem that I ran into (and I pushed this out without much 
> testing, I apologize), was that I needed a way of detecting successful 
> fetches of keys that had zero length responses.  Originally I was 
> testing for valid keys based off of res->size, but this doesn't work in 
> the previous situation.  So instead I changed the previous 
> res->free_on_delete to res->_flags that was a bit options field.  As a 
> result, one can now fetch keys with zero length... but apparently I 
> didn't do this 100% right.  I don't use mc_aget() anywhere any more in 
> my apps and didn't run my little regression test (stupid, yeah, I 
> know... normally I do but it was late and I wanted to leave the colo).
> 
> > Perhaps rather than trying to autodetect this users who are
> > preallocating memory should simply have to call mc_res_free_on_delete
> > themselves, and then the value of the flags should never get modified 
> > by
> > this apparent auto-detection routine?
> 
> Well, that's just it.  mc_res_free_on_delete(3) sets the value to 
> either one bit or the other, not both.  If both bits are set, however, 
> then it means that the library needs to look at res->size to see if it 
> should free on delete or not.  The logic is simple, but the coding 
> wasn't 100% correct.  If you apply the following:
> 
> Index: memcache.c
> ===================================================================
> RCS file: /opt/cvsroot/nexadesic/src/lib/libmemcache/memcache.c,v
> retrieving revision 1.1
> diff -u -r1.1 memcache.c
> --- memcache.c  7 Dec 2004 01:17:11 -0000       1.1
> +++ memcache.c  7 Dec 2004 19:08:20 -0000
> @@ -493,7 +493,8 @@
> 
>       /* While we're looping, might as well see if we should be auto
>        * deleting any of these keys. */
> -    if (res->_flags & (MC_RES_FREE_ON_DELETE | 
> MC_RES_NO_FREE_ON_DELETE))
> +    if (res->_flags & (MC_RES_FREE_ON_DELETE | 
> MC_RES_NO_FREE_ON_DELETE) ==
> +       (MC_RES_FREE_ON_DELETE | MC_RES_FREE_ON_DELETE))
>         mc_res_free_on_delete(res, (res->size > 0 ? 0 : 1));
>     }
>     rv[i].iov_base = str_endl;
> @@ -686,7 +687,8 @@
>         /* Make sure we are where we think we are. */
>         if (mc->start[rb - 2] != '\r' && mc->start[rb - 1] != '\n') {
>          warnx("%s:%u\tProtocol Error", __FILE__, __LINE__);
> -       if (!(res->_flags & (MC_RES_FREE_ON_DELETE | 
> MC_RES_NO_FREE_ON_DELETE)) ||
> +       if ((res->_flags & (MC_RES_FREE_ON_DELETE | 
> MC_RES_NO_FREE_ON_DELETE) ==
> +            (MC_RES_FREE_ON_DELETE | MC_RES_NO_FREE_ON_DELETE)) ||
>              (res->_flags & MC_RES_FREE_ON_DELETE)) {
>            mcFree(res->val);
>            res->val = NULL;
> @@ -1072,7 +1074,8 @@
>   void
>   mc_res_free(struct memcache_req *req, struct memcache_res *res) {
>     TAILQ_REMOVE(&req->query, res, entries);
> -  if (res->_flags & (MC_RES_FREE_ON_DELETE | MC_RES_NO_FREE_ON_DELETE) 
> ||
> +  if ((res->_flags & (MC_RES_FREE_ON_DELETE | 
> MC_RES_NO_FREE_ON_DELETE) ==
> +       (MC_RES_FREE_ON_DELETE | MC_RES_NO_FREE_ON_DELETE)) ||
>         res->_flags & MC_RES_FREE_ON_DELETE) {
>       if (res->size > 0)
>         mcFree(res->val);
> 
> you should be good to go.  Or, conversely, you could get the 1.0.1 
> release which can be found here:
> 
> http://people.FreeBSD.org/~seanc/libmemcache/
> 
> -sc
> 
-- 
John A. McCaskey
Software Development Engineer
Klir Technologies, Inc.
johnm at klir.com
206.902.2027


More information about the memcached mailing list