Lookups returning wrong data?
John McCaskey
johnm at klir.com
Wed Feb 16 07:56:12 PST 2005
On Wed, 2005-02-16 at 12:50 +0100, Andy Powell wrote:
> Hi,
>
> I've recently stated testing memcached (memcached-1.1.11) using libmemcache (libmemcache-1.2.3) which appears to work quite well, but I'm running into a few problems.
>
> I'll explain what I'm using memcached for, perhaps it's not what you'd call 'normal' :P
>
> I use asterisk, it's an IP pbx with a bucket load of features, one of which is to allow the use of SIP phones. Trying to balance the load and protect against loss of connectivity I'm configuring each phone so that it has a primary and secondary registration server. So, for example PhoneA would user ServerB as it's primary and ServerC as it's backup. This all works fine except for one thing. Since the phone will only be registered to one PBX at a time the gateway machine, serving PSTN calls to the phone has to try both pbx's since there's no way to know which phone is currently registered to which pbx: ie
>
> If a call comes in for phoneA then
>
> PSTN -> Gateway1 -> pbx1 -> phoneA (we try pbx 1 first to see if we get anything)
> PSTN -> Gateway1 -> pbx2 -> phoneA (then we try pbx 2)
>
> This is where memcached comes in. There's no way for the pbx's and gateway to currently share information, so what I've done is modify the SIP channel so that when a phone registers with either PBX, an entry is placed in the cache (a simple PEER_<name> with a value of what I would need to route the call). When a call comes in the gateway looks in the cache to see which pbx the call should be routed to. eg:
>
> if PEER_2000 had a value of @192.168.1.203/ - I'd use that in my routing to do Dial(IAX2/username:password${RETURNED_VAR}${EXTEN}) which would give
>
> Dial(IAX2/username:password at 192.168.1.203/2000)
>
> and thus route the call to the appropriate pbx. I've done a pretty picture which is at http://www.automated.it/files/ if you want to take a peek at the idea of what I'm calling an SRI...
>
> That's the background, here are the problems...
>
> I've greated a small application within asterisk to allow me to share variables, is also allows me to perform a lookup on a cache entry from the asterisk cli. eg:
>
> CLI> univar PEER_200
> Universal variable PEER_200 has a value of @192.168.1.203/
>
>
> this is all well and good, except even when I haven't defined a value for a variable I still get a value
>
>
> CLI> univar PEER_FDGDDFSdzxsg
> Universal variable PEER_FDGDDFSdzxsg has a value of @192.168.1.203/
>
>
> somewhere, something seems to be matching on the first 4 characters of the key, since if I slightly modify the key used to lookup:
>
> betterthanlife CLI> univar PfEER_201
> Universal variable PfEER_201 has no value, or does not exist. Check your case, variables are case sensitive
>
> Which is what I would expect to happen with a nonexistant key. I've added a little debugging to my 'keyexists' routing which simply checks for the existance of a key using the result of a lookup and checking the size, ie res->size ... if it's <= 0 then we assume the key doesn't exist. This is what I got from a check of the key PEER_FDGDDFSdzxsg which I know does not exist.
>
This sounds like when you are making the mc_set() and mc_req_add() calls
you are passing an incorrect key_len value causing only the first part
of the key to get used... I'd check to make sure that's not the case.
Apart from that I can't think of any other reason this should be
happening.
> Feb 16 12:33:09: /usr/include/aefirion/caching.h:60 keyexists: key is PEER_FDGDDFSdzxsg, result size = 15
>
> Why would a result be returned where there is no valid key?
>
>
> The next problem is probably related but I'm unsure. Part of the process of adding a variable is to check for it's key as existance if it exists then I replace it if it does not exist I add it.. simple enough.. However I did a very simple test where I attempted to set the variable again and again in rapid sucession, this resulted in libmemcache reporting the error " memcache.c:2239 Unable to store" .. is there an issue with the rate at which I bombard the cache? My connections to the cache are made, the query sent, then disconnected for each try...
>
As for this part, with the way you are doing a check if it is set, then
add, or replace you could have a race condition with 2 processes or 2
threads checking at the same time, both finding it not set, then both
trying to add. One of them failing.
In general this check, then add or replace is a wasteful way to do
things. The set() command does an add if the key doesn't exist, or a
replace if it does and should never fail like this. I'd use it instead.
> Many thanks for any help or insights you can provide...
>
>
> Andy
>
>
>
>
>
>
More information about the memcached
mailing list