- network development overview
- memcached client - storage API
- memcached client - retrieval and deletion API, and the rest
- distributed hash table frontend for memcached
Allright - it's not that dramatic, but I've made the memcached client available as a DBI driver via planet, so you can use it with the DBI interface.
The nicest thing about DBI is the ease for extension. You can - say - create your own driver to wrap around the memcached driver and the postgresql driver, so you do not have to sprinkle your code with calls to both drivers everywhere.
You'll find the tutorial of using
bzlib/dbd-memcached after the integration section. Integrate with DBI
The last stop is to integrate both the single instance and the distributed hashtable instance into DBI, so we can use it with the DBI interface.
As you remember from the create a DBI driver series, we basically have to create the following functions and register them as a driver with DBI:
connect- wrap around the creation of the connectiondisconnect- disconnect the underlying connectionprepare- for memcached it's a NOOPquery- the majority of work is herebegin-trans(optional) - for memcached it's a NOOPcommit(optional) - for memcached it's a NOOProllback(optional) - for memcached it's a NOOP
memcached/dht is left as an exercise:
(define (m-connect driver host port)
(make-handle driver (memcached-connect host port) (make-immutable-hash-registry) 0))
(define (m-disconnect handle)
(memcached-disconnect (handle-conn handle)))
(define (m-prepare handle stmt)
(void))
(define (make-query set! add! replace! append! prepend! cas! get gets delete! incr! decr! flush-all!)
(lambda (handle stmt (args '()))
(let ((client (handle-conn handle)))
(case stmt
((set! add! replace! append! prepend!)
(let/assert! ((key (assoc/cdr 'key args))
(value (assoc/cdr 'value args))
(flags (assoc/cdr 'flags args 0))
(exp-time (assoc/cdr 'exp-time args 0)))
((case stmt
((set!) set!)
((add!) add!)
((replace!) replace!)
((append!) append!)
((prepend!) prepend!))
client key value
#:exp-time exp-time #:flags flags
#:noreply? (assoc/cdr 'noreply? args))))
((cas!)
(let/assert! ((key (assoc/cdr 'key args))
(value (assoc/cdr 'value args))
(cas (assoc/cdr 'cas args))
(flags (assoc/cdr 'flags args 0))
(exp-time (assoc/cdr 'exp-time args 0)))
(cas! client key value cas
#:exp-time exp-time #:flags flags #:noreply? (assoc/cdr 'noreply? args))))
((get gets)
(cons (list "key" "value" "flags" "cas")
(apply (case stmt
((get) get)
((gets) gets))
client (map cdr (filter (lambda (kv)
(equal? (car kv) 'key))
args)))))
((delete!)
(let/assert! ((key (assoc/cdr 'key args))
(delay (assoc/cdr 'delay args 0)))
(delete! client key delay (assoc/cdr 'noreply? args))))
((incr! decr!)
(let/assert! ((key (assoc/cdr 'key args))
(value (assoc/cdr 'value args)))
((case stmt
((incr!) incr!)
((decr!) decr!))
client key value (assoc/cdr 'noreply? args))))
((flush-all!)
(let/assert! ((delay (assoc/cdr 'key args 10)))
(flush-all! client delay (assoc/cdr 'noreply? args))))
(else
(error 'query "invalid stmt: ~a" stmt))))))