C Api difficulty

Started by Jeff, July 22, 2008, 10:23:46 AM

Previous topic - Next topic

Jeff

I'm having some difficulty with the following prototypes:


memcached_return
memcached_mget (memcached_st *ptr,
                char **keys,
                size_t *key_length,
                unsigned int number_of_keys);

char *memcached_fetch (memcached_st *ptr,
                       char *key,
                       size_t *key_length,
                       size_t *value_length,
                       uint32_t *flags,
                       memcached_return *error);


I have MEMCACHED, in which I'm holding the pointer to memcached_st.  I have MEMCACHED_RETURN, which I use to store the return pointer from various functions.



memcached_mget asynchronously gets the passed keys' values, and memcached_fetch retrieves them one by one.  However, when watching the server debug output, when memcached_fetch is called, it's reporting an error (either SERVER_END or PROTOCOL_ERROR, and I can find documentation for neither).  However, I think that the problem is newlisp dies with a bus error and disconnects in the middle of a transaction.



Here is the function I'm using (it's not yet cleaned up):


(define (get-keys list-keys , res)
  (when MEMCACHED
    (letn ((num-keys (length list-keys))
           (keys (pack (trim (dup "lu " num-keys)) (map 'string list-keys)))
           (lengths (pack (trim (dup "d " num-keys)) (map 'length (map 'string list-keys)))))
      (setq MEMCACHED_RETURN (memcached_mget MEMCACHED keys lengths num-keys))
      (when (= (result) "SUCCESS")
        (setq res '())
        (dolist (key list-keys)
          (let ((key-length (length key))
                (val-length 0)
                (flags 0)
                (val nil))
            (setq val (memcached_fetch MEMCACHED
                                       key (address key-length)
                                       (address val-length) (address flags)
                                       (address MEMCACHED_RETURN)))
            (push (list key (get-string val)) res -1))))))
  res)


At the end, that get-string is where the bus error happens.  memcached_fetch is returning 0 (NULL), which, according to libmemcached's docs, means I've retrieved all of the values... but it does this on the first call.  Not quite sure where to go from here; the docs are not clear and I'm no expert in C.



Note: that 'result' function reads the error/status of MEMCACHED_RETURN.  Success returns the string "SUCCESS", which suggests that the memcached_mget call succeeded.



Any ideas?



PS docs for libmemcached: http://docs.tangent.org/libmemcached/memcached.html">http://docs.tangent.org/libmemcached/memcached.html
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Lutz

#1
Here are some comments:



(1) char * * keys, array of string pointers



The string (array) addresses have to be anchored to a symbol, so the strings don't get moved around (memory managed), but stay in a fixed place in memory.



Instead of:


(set 'keys (pack (trim (dup "lu " num-keys)) (map string list-keys)))

do:


(set 's-keys (map string list-keys))
(set 'keys (pack (dup "lu" num-keys) s-keys)


Here is a simple example to illustrate the same:


(set 'sa '("ABC" "DEF" "GHI"))
(set 'ptr (pack "lululu" sa)) ; ptr -> char * *, ptr to array of ptrs
> (get-string (get-int (+ (address ptr) 0)))
"ABC"
> (get-string (get-int (+ (address ptr) 4)))
"DEF"
> (get-string (get-int (+ (address ptr) 8)))
"GHI"


(2) size_t *key_length



size_t should be 32-bit not 16-bit. And as in (1) you have to anchor addresses in memory to build an array of size_t unsigned integers.



Instead of:


(set 'lengths (pack (trim (dup "d " num-keys)) (map 'length (map 'string list-keys))))

do:


(set 'len-s-keys (map length (map string list-keys)))
; or using the previous s-keys
(set 'len-s-keys (map length s-keys))
(set 'lengths (pack (dup "lu" num-keys) len-s-keys))


Simple explicit example:


(set 'sa '("A" "BC" "DEF"))
(set 'ptr (pack "lululu" sa))

(set 'l-sa (map length sa))
(set 'lengths (pack (dup "lu" 3) l-sa))

> (get-int (+ (address lengths) 0))
1
> (get-int (+ (address lengths) 4))
2
> (get-int (+ (address lengths) 8))
3


So now you can do:


(setq MEMCACHED_RETURN (memcached_mget MEMCACHED keys lengths num-keys))

Hope this helps ;-)

Jeff

#2
Is let-binding not sufficient?  When I write the function with symbols locally bound in the variable and your tips:


(define (fetch key , klen vlen flags res)
  (setq klen (address (length key))
        vlen (address 0)
        flags (address 0))
  (setq res (memcached_fetch MEMCACHED key klen vlen flags (address MEMCACHED_RETURN)))
  (if (= 0 res) nil (get-string res)))

(define (get-keys list-keys , res num-keys s-keys keys len-s-keys lengths)
  (setq MEMCACHED_RETURN nil)
  (when MEMCACHED
    (setq num-keys (length list-keys))
    (setq s-keys (map string list-keys))
    (setq keys (pack (dup "lu" num-keys) s-keys))
    (setq len-s-keys (map length s-keys))
    (setq lengths (pack (dup "lu" num-keys) len-s-keys))
    (setq MEMCACHED_RETURN (memcached_mget MEMCACHED keys lengths num-keys))
    (when (= (result) "SUCCESS")
      (setq res '())
      (dolist (key list-keys)
        (push (list key (fetch key)) res -1))))
  res)


...it works perfectly (and thanks!).  Don't let-bound variables have their own addresses, or did I simply not bind enough of the intermediate variables to symbols?
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Lutz

#3
QuoteIs let-binding not sufficient?


Yes, absolutely sufficient, I was just to lazy to write out the whole 'let' -form and used 'set' for that reason, 'let' should work just the same.

Jeff

#4
I've posted the new code to artful code (static.artfulcode.net/modules).  Thanks for your help, Lutz.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code