author | Alberto Bertogli
<albertito@gmail.com> 2007-04-29 06:37:46 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-04-29 06:37:46 UTC |
parent | 2c23a7bb908b3dbbe91b02cb687326a32bd0926c |
libnmdb/libnmdb.3 | +26 | -6 |
libnmdb/libnmdb.c | +82 | -0 |
libnmdb/net-const.h | +4 | -0 |
libnmdb/nmdb.h | +8 | -0 |
diff --git a/libnmdb/libnmdb.3 b/libnmdb/libnmdb.3 index 27306d8..7426529 100644 --- a/libnmdb/libnmdb.3 +++ b/libnmdb/libnmdb.3 @@ -32,6 +32,15 @@ libnmdb - Library for interacting with a nmdb server .BI " const unsigned char *" key ", size_t " ksize ");" .BI "int nmdb_cache_del(nmdb_t *" db "," .BI " const unsigned char *" key ", size_t " ksize ");" +.sp +.BI "int nmdb_cas(nmdb_t *" db "," +.BI " const unsigned char *" key " , size_t " ksize "," +.BI " const unsigned char *" oldval ", size_t " ovsize "," +.BI " const unsigned char *" newval ", size_t " nvsize ")" +.BI "int nmdb_cache_cas(nmdb_t *" db "," +.BI " const unsigned char *" key " , size_t " ksize "," +.BI " const unsigned char *" oldval ", size_t " ovsize "," +.BI " const unsigned char *" newval ", size_t " nvsize ")" .fi .SH DESCRIPTION @@ -70,14 +79,19 @@ of the keys and values apply: keys can't exceed 64Kb, values can't exceed 64Kb, and the size of a key + the size of it's associated value can't exceed 64Kb. -There are three kinds of operations: +There are four kinds of operations: .IR set , -.I get -and +which sets pairs; +.IR get , +which gets pairs; .IR del , -with their obvious meaning. The normal set and del operations return as soon -as they've been queued on the server for asynchronous completion. Note that in -this case no message is sent to the client when the operation completes. +which removes pairs; +and +.IR cas , +which compares-and-sets values. The normal set and del operations return as +soon as they've been queued on the server for asynchronous completion. Note +that in this case no message is sent to the client when the operation +completes. Each operation has variants, that make it behave in a different way. All three have "cache" variants, that only affect the cache and not the database; and @@ -113,6 +127,12 @@ returns 1 if it was queued successfuly, or < 0 on failure. The cache and synchronous variant return 1 if the key was removed successfuly, 0 if the key was not in the database/cache, or < 0 on failure. +.BR nmdb_cas () +is used to compare-and-swap a key's value. It takes an old value to compare +with the one in the database, and if they match, it sets the key to the given +new value. Returns 2 if the swap was performed, 1 if the values didn't match, +0 if the key was not on in the database/cache, and < 0 on failure. + .SH SEE ALSO .BR nmdb (1), diff --git a/libnmdb/libnmdb.c b/libnmdb/libnmdb.c index f581169..6e482e4 100644 --- a/libnmdb/libnmdb.c +++ b/libnmdb/libnmdb.c @@ -451,3 +451,85 @@ int nmdb_cache_del(nmdb_t *db, const unsigned char *key, size_t ksize) } +static int do_cas(nmdb_t *db, const unsigned char *key, size_t ksize, + const unsigned char *oldval, size_t ovsize, + const unsigned char *newval, size_t nvsize, + int impact_db) +{ + ssize_t rv, t; + unsigned char *buf, *p; + size_t bsize; + uint32_t request, reply; + struct nmdb_srv *srv; + + request = REQ_CACHE_CAS; + if (impact_db) + request = REQ_CAS; + + + /* Use the same buffer for the request and the reply. + * Request: 4 bytes ver+id, 4 bytes request code, 4 bytes ksize, 4 + * bytes ovsize, 4 bytes nvsize, ksize bytes key, + * ovsize bytes oldval, nvsize bytes newval. + * Reply: 4 bytes id, 4 bytes reply code. + */ + bsize = 4 + 4 + 4 + 4 + 4 + ksize + ovsize + nvsize; + buf = malloc(bsize); + if (buf == NULL) + return -1; + + * (uint32_t *) buf = htonl( (PROTO_VER << 28) | ID_CODE ); + * ((uint32_t *) buf + 1) = htonl(request); + * ((uint32_t *) buf + 2) = htonl(ksize); + * ((uint32_t *) buf + 3) = htonl(ovsize); + * ((uint32_t *) buf + 4) = htonl(nvsize); + p = buf + 5 * 4; + memcpy(p, key, ksize); + p += ksize; + memcpy(p, oldval, ovsize); + p += ovsize; + memcpy(p, newval, nvsize); + + srv = select_srv(db, key, ksize); + t = srv_send(db, srv, buf, bsize); + if (t <= 0) { + rv = -1; + goto exit; + } + + reply = get_rep(db, srv, buf, bsize, NULL, NULL); + + if (reply == REP_OK) { + rv = 2; + goto exit; + } else if (reply == REP_NOMATCH) { + rv = 1; + goto exit; + } else if (reply == REP_NOTIN) { + rv = 0; + goto exit; + } + + /* REP_ERR or invalid response */ + rv = -1; + +exit: + free(buf); + return rv; + +} + +int nmdb_cas(nmdb_t *db, const unsigned char *key, size_t ksize, + const unsigned char *oldval, size_t ovsize, + const unsigned char *newval, size_t nvsize) +{ + return do_cas(db, key, ksize, oldval, ovsize, newval, nvsize, 1); +} + +int nmdb_cache_cas(nmdb_t *db, const unsigned char *key, size_t ksize, + const unsigned char *oldval, size_t ovsize, + const unsigned char *newval, size_t nvsize) +{ + return do_cas(db, key, ksize, oldval, ovsize, newval, nvsize, 0); +} + diff --git a/libnmdb/net-const.h b/libnmdb/net-const.h index a382490..127b9b9 100644 --- a/libnmdb/net-const.h +++ b/libnmdb/net-const.h @@ -23,6 +23,8 @@ #define REQ_DEL_SYNC 0x106 #define REQ_SET_ASYNC 0x107 #define REQ_DEL_ASYNC 0x108 +#define REQ_CACHE_CAS 0x109 +#define REQ_CAS 0x110 /* Network replies (different namespace from requests) */ #define REP_ERR 0x800 @@ -30,6 +32,7 @@ #define REP_CACHE_MISS 0x802 #define REP_OK 0x803 #define REP_NOTIN 0x804 +#define REP_NOMATCH 0x805 /* Network error replies */ #define ERR_VER 0x101 /* Version mismatch */ @@ -39,5 +42,6 @@ #define ERR_MEM 0x105 /* Memory allocation error */ #define ERR_DB 0x106 /* Database error */ + #endif diff --git a/libnmdb/nmdb.h b/libnmdb/nmdb.h index ea86356..7fc0994 100644 --- a/libnmdb/nmdb.h +++ b/libnmdb/nmdb.h @@ -38,5 +38,13 @@ int nmdb_del(nmdb_t *db, const unsigned char *key, size_t ksize); int nmdb_del_sync(nmdb_t *db, const unsigned char *key, size_t ksize); int nmdb_cache_del(nmdb_t *db, const unsigned char *key, size_t ksize); +int nmdb_cas(nmdb_t *db, const unsigned char *key, size_t ksize, + const unsigned char *oldval, size_t ovsize, + const unsigned char *newval, size_t nvsize); +int nmdb_cache_cas(nmdb_t *db, const unsigned char *key, size_t ksize, + const unsigned char *oldval, size_t ovsize, + const unsigned char *newval, size_t nvsize); + + #endif