;; @module memcached ;; @author Jeff Ober , Kanen Flowers ;; @version 0.3 ;; @location http://static.artfulcode.net/newlisp/memcached.lsp ;; @package http://static.artfulcode.net/newlisp/memcached.qwerty ;; @description Interface to libmemcached (http://tangent.org/552/libmemcached.html) (updated for newlisp 10) ;;

This module is a work-in-progress. Currently implemented functions work (or at least they ;; appear to). The full range of functionality is not nearly implemented, but it works well enough ;; to allocate, connect, get/set keys, and disconnect/deallocate.

;;

External libraries

;; • ;; @link http://tangent.org/552/libmemcached.html libmemcached
;; • ;; @link http://www.danga.com/memcached/download.bml memcached
;; • ;; @link http://monkey.org/~provos/libevent/ libevent (required by memcached) ;; ;;

Version history

;; 0.3 ;; • updated for newlisp 10 ;; ;; 0.2 ;; • cleaned up some functions ;; • added 'get-keys' ;; ;; 0.1 ;; • development release ;; ;; @example ;; (memcached:init) ;; (memcached:add-server "localhost" 8080) ;; (memcached:set-key "foo" "bar" 30) ;; (memcached:get-key "foo") ; within 30 seconds ;; => "bar" ;; (sleep 30000) ; wait 30 seconds ;; (memcached:get-key "foo") ; after 30+ seconds ;; => nil ;; (memcached:disconnect) (context 'memcached) ;;; note: technique robbed from mysql5.lsp (setq files '("/usr/local/lib/libmemcached.so" "/usr/local/lib/libmemcached.dylib")) (setq libmemcached (files (or (find true (map file? files)) (begin (println "cannot find libmemcached library") (exit))))) (import libmemcached "memcached_create") (import libmemcached "memcached_free") (import libmemcached "memcached_server_add") (import libmemcached "memcached_strerror") (import libmemcached "memcached_quit") (import libmemcached "memcached_set") (import libmemcached "memcached_get") (import libmemcached "memcached_mget") (import libmemcached "memcached_fetch") (import libmemcached "memcached_result_create") (setq MEMCACHED nil) (setq MEMCACHED_RETURN nil) (setq ERROR nil) ;; @syntax (memcached:init) ;;

Initializes the 'memcached' module.

(define (init) (if MEMCACHED (memcached_free MEMCACHED)) (setq MEMCACHED (memcached_create 0)) (if (zero? MEMCACHED) (setq MEMCACHED nil)) (not (nil? MEMCACHED))) ;; @syntax (memcached:disconnect) ;;

Disconnects from all servers and deallocates libmemcached structures.

(define (disconnect) (when MEMCACHED (memcached_quit MEMCACHED) (memcached_free MEMCACHED) true)) ;; @syntax (memcached:add-server ) ;; @param the hostname; required ;; @param the host port; required ;;

Adds a server to be used as a source of cached data. Returns true or nil, ;; depending on whether the server was successfully added or not.

;; @example ;; (memcached:add-server "localhost" 8000) ;; => true (define (add-server host port) (when MEMCACHED (setq MEMCACHED_RETURN (memcached_server_add MEMCACHED host port)) (= "SUCCESS" (result)))) ;; @syntax (memcached:result) ;;

Returns the result or error from the last operation.

(define (result) (if (and MEMCACHED MEMCACHED_RETURN) (get-string (memcached_strerror MEMCACHED MEMCACHED_RETURN)))) ;; @syntax (memcached:set-key []) ;; @param unique key to store under; required ;; @param value to store under ; required ;; @param seconds until will expire; optional ;;

Sets to on the memcached server. will be serialized ;; using 'string'. Keys that already exist are overwritten. Returns true for success, ;; nil for failure.

;; @example ;; (memcached:set-key "foo" "bar" 30) ; sets "foo" to "bar" for 30 seconds ;; => true (define (_set-key key value expiration) (when MEMCACHED (setq key (string key)) (setq value (string value)) (setq MEMCACHED_RETURN (memcached_set MEMCACHED key (length key) value (length value) expiration nil)) (= "SUCCESS" (result)))) (define (set-key key value expiration) (if (_set-key key value expiration) value)) ;; @syntax (memcached:get-key ) ;; @param the key to retrieve; required ;;

Retrieves the value associated with from the memcached server. If the ;; key does not exist or has expired, evaluates to nil. Otherwise, the string value ;; is returned.

;; @example ;; (memcached:set-key "foo" '("bar" "baz" "bat") (* 60 60)) ;; => true ;; ;; (memcached:get-key "foo") ;; => "(\"bar\" \"baz\" \"bat\")" ;; ;; (let ((res (memcached:get-key "foo"))) ;; (if res (eval-string (string "'" res)))) ; evaluate quoted ;; => ("bar" "baz" "bat") (define (get-key key , res (value-length 0) (flags 0)) (when MEMCACHED (setq res (memcached_get MEMCACHED key (length key) (address value-length) (address flags) (address MEMCACHED_RETURN))) (unless (zero? res) (get-string res)))) (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))) ;; @syntax (memcached:get-keys ) ;; @param a list of strings ;;

Fetches an association list of '(key value) pairs from the ;; server. Invalid or expired values return nil.

;; @example ;; (memcached:set-key "foo" "bar" 300) ;; => "bar" ;; (memcached:set-key "baz" "bat" 300) ;; => "bat" ;; (memcached:set-key "asdf" "qwerty" 300) ;; => "qwerty" ;; ;; (memcached:get-keys '("foo" "baz" "asdf") ;; => (("foo" "bar") ("baz" "bat") ("asdf" "qwerty")) ;; ;; (memcached:get-keys '("foo" "invalid" "expired")) ;; => (("foo" "bar") ("invalid" nil) ("expired" nil)) (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) s-keys (map string list-keys) keys (pack (dup "lu" num-keys) s-keys) len-s-keys (map length s-keys) lengths (pack (dup "lu" num-keys) len-s-keys) 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) (context 'MAIN)