Brad Fitzpatrick brad@danga.com
Fri, 16 Jan 2004 09:27:37 -0800 (PST)

I'm thinking something like this would be better:

/* gets a handle for a group of servers.  could set the servers here,
   the domain, the time-out restrictions, etc.  like the Perl API.
   also, perhaps a function pointer to the memory allocator, if not
   malloc.  */

memcached_client* memcached_client_new(opts...);

/* for add/replace/set/delete: return boolean if "STORED" or "DELETED" */
int memcached_VERB(memcached_client* mc, const char *key, ushort flags,
                   time_t seconds, const char *data, size_t data_len);

/* gets a single item, using mc's allocator, or nothing. */
char* memcached_get(memcached_client* mc, const char *key);

/* same, with an explicit hash value */
char* memcached_get(memcached_client* mc, uint hv, const char *key);

/* get multi, returns count of items retrieved */
struct mc_iovec {
        char *key;        /* set by caller */
 	int hv;           /* set by caller.  -1 means no explicit hashvalue */
        int length;       /* set by caller to -1, set to length by get_multi */
        char *pointer;    /* set by get_multi if length > 0 */

int memcached_get_multi(memcached_client* mc, struct mc_iovec *vector,
                        size_t count);

The "connect" stuff is an internal detail, not part of the public API.
You don't make clients deal with that.  They just want to get/set and not
know from where.

But if you're doing cache-sensitive stuff (like MySQL's row cache) you
will need to know things like connect failures, so you'll probably need
another struct for each server, hanging off *memcached_client, which you
can check for errors.

Also, you'll want internal functions which return the non-blocking
socket fds to wait on in your select loop.  (memcached should never assume
a server is up or functioning quickly.  your select timeout is specified
in *memcached_client.... something like a half second or a second at

Avva--- anything I'm forgetting?

On Fri, 16 Jan 2004, Brian Aker wrote:

> I posted this last night to my blog and decided to repost it here to get
> a little more feedback (and possibly some suggestions on the API):
> Thus far I have something like this:
> void connect_memcached();
> void stats_memcached();
> void delete_memcached(const char *key, time_t seconds);
> void add_memcached(const char *key, int flags, time_t seconds, const
> char *data, size_t data_len);
> void replace_memcached(const char *key, int flags, time_t seconds, const
> char *data, size_t data_len);
> void set_memcached(const char *key, int flags, time_t seconds, const
> char *data, size_t data_len);
> void get_memcached(const char *key);
> void close_memcached();
> I am thinking about defining some sort of client structure that will be
> passed into connect_memcached().
> Store in it:
> socket
> buffer
> some sort of len about the data in the buffer
> "buffer" I would like to define.... not sure what. Part of me is tempted
> to define it as default tcp packet size so that I know I am fetching all
> data each read.
> Need to add a fetch method where you pass in buffer and I then copy from
> client structure. Dealing with multiple get requests is somewhat of a
> pain I might add.
> Same with error messages since they are completely made up of strings
> (do a bunch of strcmp and return integer equivs?).
> Memecache's protocol is a half text/half binary protocol. Shame its not
> a complete binary protocol since I could avoid a bit of parsing that
> way. Though its text base it has no parser and its not very wordy (I
> have to say I have become accustom to just pulling out YACC/LEX and
> going to town (though I am becoming fond of PCCTS)).
> No authentication currently.
> Trying to avoid malloc() calls since they basically suck for
> performance.
> Need to think a bit a more on the stats method too...
> --
> _______________________________________________________
> Brian "Krow" Aker, brian@tangent.org
> Seattle, Washington
> http://krow.net/
> http://askbrian.org/
> _______________________________________________________
> You can't grep a dead tree.