git » nmdb » commit 4d3dba5

[API BREAK] Make increment return the incremented value

author Alberto Bertogli
2008-06-23 00:09:40 UTC
committer Alberto Bertogli
2008-06-23 00:15:17 UTC
parent e97b3e9ab8aca33f481f1fea2479fa6a328eb4f7

[API BREAK] Make increment return the incremented value

It is often useful to have the result of the increment atomically.

This patch modifies the server and the client to return the incremented
value, and updates the documentation and bindings accordingly.

Signed-off-by: Alberto Bertogli <albertito@gmail.com>

bindings/bigloo/nmdb.scm +6 -3
bindings/d/nmdb.d +11 -9
bindings/d/nmdb_ll.d +2 -2
bindings/d/testt.d +6 -2
bindings/haskell/Nmdb.hs +13 -4
bindings/newlisp/nmdb.lsp +5 -2
bindings/python/nmdb.py +2 -2
bindings/python/nmdb_ll.c +6 -4
bindings/ruby/nmdb.rb +2 -2
bindings/ruby/nmdb_ll.c +6 -5
doc/network.rst +3 -1
libnmdb/libnmdb.3 +6 -3
libnmdb/libnmdb.c +14 -8
libnmdb/nmdb.skel.h +2 -2
nmdb/cache.c +9 -5
nmdb/cache.h +1 -1
nmdb/dbloop.c +4 -1
nmdb/parse.c +9 -5
tests/c/incr.c +5 -3

diff --git a/bindings/bigloo/nmdb.scm b/bindings/bigloo/nmdb.scm
index 014dbdb..3b086bb 100644
--- a/bindings/bigloo/nmdb.scm
+++ b/bindings/bigloo/nmdb.scm
@@ -6,6 +6,7 @@
 	;; C functions
 	(extern
 	  (type _nmdb_t (pointer void) "void *")
+	  (type long* (pointer long) "int64_t *")
 
 	  (macro _nmdb_init::_nmdb_t () "nmdb_init")
 	  (macro _nmdb_free::int (::_nmdb_t) "nmdb_free")
@@ -54,10 +55,10 @@
 		 "nmdb_cache_cas")
 
 	  (macro _nmdb_incr::int
-		 (::_nmdb_t ::string ::uint ::long)
+		 (::_nmdb_t ::string ::uint ::long ::long*)
 		 "nmdb_incr")
 	  (macro _nmdb_cache_incr::int
-		 (::_nmdb_t ::string ::uint ::long)
+		 (::_nmdb_t ::string ::uint ::long ::long*)
 		 "nmdb_cache_incr")
 
 	  )
@@ -147,7 +148,9 @@
 
 ;; incr functions
 (define (nmdb-generic-incr func db key increment)
-  (func db key (string-length key) increment ) )
+  (define newval (make-long* 1))
+  (define res (func db key (string-length key) increment newval) )
+  (list res (long*-ref newval 0) ) )
 (define (nmdb-incr db key increment)
   (nmdb-generic-incr _nmdb_incr db key increment))
 (define (nmdb-cache-incr db key increment)
diff --git a/bindings/d/nmdb.d b/bindings/d/nmdb.d
index 9c96062..e668bf9 100644
--- a/bindings/d/nmdb.d
+++ b/bindings/d/nmdb.d
@@ -165,15 +165,17 @@ class DB
 		return res;
 	}
 
-	private int do_incr(char[] key, long increment, int mode)
+	private int do_incr(char[] key, long increment, long *newval,
+			int mode)
 	{
 		ubyte* k = cast(ubyte *) key.ptr;
 		int res = 0;
 
 		if (mode == MODE_NORMAL || mode == MODE_SYNC) {
-			res = nmdb_incr(db, k, key.length, increment);
+			res = nmdb_incr(db, k, key.length, increment, newval);
 		} else if (mode == MODE_CACHE) {
-			res = nmdb_cache_incr(db, k, key.length, increment);
+			res = nmdb_cache_incr(db, k, key.length, increment,
+					newval);
 		} else {
 			throw new Exception("Invalid mode");
 		}
@@ -255,19 +257,19 @@ class DB
 	}
 
 
-	int incr(char[] key, long increment)
+	int incr(char[] key, long increment, long *newval)
 	{
-		return do_incr(key, increment, mode);
+		return do_incr(key, increment, newval, mode);
 	}
 
-	int incr_normal(char[] key, long increment)
+	int incr_normal(char[] key, long increment, long *newval)
 	{
-		return do_incr(key, increment, MODE_NORMAL);
+		return do_incr(key, increment, newval, MODE_NORMAL);
 	}
 
-	int cache_incr(char[] key, long increment)
+	int cache_incr(char[] key, long increment, long *newval)
 	{
-		return do_incr(key, increment, MODE_CACHE);
+		return do_incr(key, increment, newval, MODE_CACHE);
 	}
 
 
diff --git a/bindings/d/nmdb_ll.d b/bindings/d/nmdb_ll.d
index beb28d3..03c2426 100644
--- a/bindings/d/nmdb_ll.d
+++ b/bindings/d/nmdb_ll.d
@@ -65,7 +65,7 @@ extern (C) int nmdb_cache_cas(nmdb_t *db, ubyte *key, size_t ksize,
 		ubyte *oldval, size_t ovsize, ubyte *newval, size_t nvsize);
 
 extern (C) int nmdb_incr(nmdb_t *db, ubyte *key, size_t ksize,
-		long increment);
+		long increment, long *newval);
 extern (C) int nmdb_cache_incr(nmdb_t *db, ubyte *key, size_t ksize,
-		long increment);
+		long increment, long *newval);
 
diff --git a/bindings/d/testt.d b/bindings/d/testt.d
index e2b820c..a70441d 100644
--- a/bindings/d/testt.d
+++ b/bindings/d/testt.d
@@ -7,16 +7,20 @@ import std.stream;
 int main()
 {
 	char[] val1;
+	long newval, ret;
 
 	nmdb.DB db = new nmdb.DB();
 	db.add_tipc_server();
 
 	db.mode = MODE_CACHE;
-	db["1"] = "D";
-	val1 = db["1"];
+	db["D"] = "1\0";
+	val1 = db["D"];
 
 	writefln(val1);
 
+	ret = db.incr("D", 4, &newval);
+	writefln(newval, " ", db["D"]);
+
 	return 0;
 }
 
diff --git a/bindings/haskell/Nmdb.hs b/bindings/haskell/Nmdb.hs
index 735385a..fe621d0 100644
--- a/bindings/haskell/Nmdb.hs
+++ b/bindings/haskell/Nmdb.hs
@@ -14,7 +14,9 @@ module Nmdb (
 	nmdbIncr, nmdbCacheIncr,
 ) where
 
+import Foreign
 import Foreign.Ptr
+import Foreign.Storable
 import Foreign.C.Types
 import Foreign.C.String
 import Foreign.Marshal.Alloc
@@ -158,15 +160,22 @@ nmdbCacheCAS = nmdbGenericCAS llNmdbCacheCAS
 
 -- Incr functions
 foreign import ccall "nmdb.h nmdb_incr" llNmdbIncr ::
-	NmdbPtr -> CString -> Int -> Int -> IO Int
+	NmdbPtr -> CString -> Int -> Int64 -> Ptr Int64 -> IO Int
 foreign import ccall "nmdb.h nmdb_cache_incr" llNmdbCacheIncr ::
-	NmdbPtr -> CString -> Int -> Int -> IO Int
+	NmdbPtr -> CString -> Int -> Int64 -> Ptr Int64 -> IO Int
 
 nmdbGenericIncr llfunc db key increment = do
 	kl <- newCStringLen key
-	r <- llfunc db (fst kl) (snd kl) increment
+	newval <- malloc
+	r <- llfunc db (fst kl) (snd kl) increment newval
+	v <- (peek newval)
 	free (fst kl)
-	return r
+	free newval
+	if r == 2
+	  then do
+		return $ Just v
+	  else
+		return Nothing
 
 nmdbIncr = nmdbGenericIncr llNmdbIncr
 nmdbCacheIncr = nmdbGenericIncr llNmdbCacheIncr
diff --git a/bindings/newlisp/nmdb.lsp b/bindings/newlisp/nmdb.lsp
index 640bfe7..713d300 100644
--- a/bindings/newlisp/nmdb.lsp
+++ b/bindings/newlisp/nmdb.lsp
@@ -142,8 +142,11 @@
 
 ; *-incr functions
 (define (priv-incr func key increment)
-  (letn ( (keylen (length key)) )
-    (func NMDB key keylen increment) ) )
+  (letn ( (keylen (length key))
+	  (newval 0)
+	)
+    (set 'ret (func NMDB key keylen increment (address newval)) )
+    (list ret newval) ) )
 
 (define (db-incr key increment) (priv-incr nmdb_incr key increment))
 (define (cache-incr key increment) (priv-incr nmdb_cache_incr key increment))
diff --git a/bindings/python/nmdb.py b/bindings/python/nmdb.py
index 38f7366..406c653 100644
--- a/bindings/python/nmdb.py
+++ b/bindings/python/nmdb.py
@@ -172,10 +172,10 @@ class GenericDB (object):
 		key by the given increment."""
 		if self.autopickle:
 			key = str(hash(key))
-		r = incrf(key, increment)
+		r, v = incrf(key, increment)
 		if r == 2:
 			# success
-			return 2
+			return v
 		elif r == 1:
 			# no match, because the value didn't have the right
 			# format
diff --git a/bindings/python/nmdb_ll.c b/bindings/python/nmdb_ll.c
index 2374118..e2ef5ca 100644
--- a/bindings/python/nmdb_ll.c
+++ b/bindings/python/nmdb_ll.c
@@ -189,6 +189,7 @@ static PyObject *db_cache_incr(nmdbobject *db, PyObject *args)
 	int ksize;
 	int rv;
 	long long int increment;
+	int64_t newval;
 
 	if (!PyArg_ParseTuple(args, "s#L:cache_incr", &key, &ksize,
 				&increment)) {
@@ -196,10 +197,10 @@ static PyObject *db_cache_incr(nmdbobject *db, PyObject *args)
 	}
 
 	Py_BEGIN_ALLOW_THREADS
-	rv = nmdb_cache_incr(db->db, key, ksize, increment);
+	rv = nmdb_cache_incr(db->db, key, ksize, increment, &newval);
 	Py_END_ALLOW_THREADS
 
-	return PyLong_FromLong(rv);
+	return Py_BuildValue("LL", rv, newval);
 }
 
 
@@ -303,16 +304,17 @@ static PyObject *db_incr(nmdbobject *db, PyObject *args)
 	int ksize;
 	int rv;
 	long long int increment;
+	int64_t newval;
 
 	if (!PyArg_ParseTuple(args, "s#L:incr", &key, &ksize, &increment)) {
 		return NULL;
 	}
 
 	Py_BEGIN_ALLOW_THREADS
-	rv = nmdb_incr(db->db, key, ksize, increment);
+	rv = nmdb_incr(db->db, key, ksize, increment, &newval);
 	Py_END_ALLOW_THREADS
 
-	return PyLong_FromLong(rv);
+	return Py_BuildValue("LL", rv, newval);
 }
 
 
diff --git a/bindings/ruby/nmdb.rb b/bindings/ruby/nmdb.rb
index 09672af..4d38d82 100644
--- a/bindings/ruby/nmdb.rb
+++ b/bindings/ruby/nmdb.rb
@@ -142,14 +142,14 @@ class GenericDB
 		if @automarshal then
 			key = Marshal.dump(key)
 		end
-		r = gfunc.call(key, increment)
+		r, v = gfunc.call(key, increment)
 		if r == 0 then
 			# key not in the database
 			return nil
 		elsif r == 1 or r < 0 then
 			raise NetworkException
 		else
-			return r
+			return v
 		end
 	end
 
diff --git a/bindings/ruby/nmdb_ll.c b/bindings/ruby/nmdb_ll.c
index 1ef13cc..a07e274 100644
--- a/bindings/ruby/nmdb_ll.c
+++ b/bindings/ruby/nmdb_ll.c
@@ -202,23 +202,24 @@ static VALUE m_cache_cas(VALUE self, VALUE key, VALUE oldval, VALUE newval) {
 }
 
 
-/* Del functions */
+/* Increment functions */
 typedef int (*incrf_t) (nmdb_t *db, const unsigned char *k, size_t ks,
-		int64_t increment);
+		int64_t increment, int64_t *newval);
 VALUE generic_incr(VALUE self, VALUE key, VALUE increment, incrf_t incr_func)
 {
 	ssize_t rv;
 	unsigned char *k;
 	size_t ksize;
-	int64_t cincr;
+	int64_t cincr, newval;
 	nmdb_t *db;
 	Data_Get_Struct(self, nmdb_t, db);
 
 	k = rb_str2cstr(key, &ksize);
 	cincr = rb_num2ll(increment);
 
-	rv = incr_func(db, k, ksize, cincr);
-	return INT2NUM(rv);
+	rv = incr_func(db, k, ksize, cincr, &newval);
+
+	return rb_ary_new3(2, INT2NUM(rv), rb_ll2inum(newval));
 }
 
 VALUE m_incr(VALUE self, VALUE key, VALUE increment) {
diff --git a/doc/network.rst b/doc/network.rst
index 0c5030e..f9f4313 100644
--- a/doc/network.rst
+++ b/doc/network.rst
@@ -157,7 +157,9 @@ REP_CACHE_HIT
 REP_OK
   Depending on the request, this reply does or doesn't have an associated
   value. For *REQ_SET**, *REQ_DEL** and *REQ_CAS** there is no payload. But
-  for *REQ_GET* the first 32 bits are the value size, and then the value.
+  for *REQ_GET* the first 32 bits are the value size, and then the value; and
+  for *REQ_INCR* the first 32 bits are the payload size, and then the
+  post-increment value as a signed 64-bit integer in network byte order.
 
 
 Reply error codes
diff --git a/libnmdb/libnmdb.3 b/libnmdb/libnmdb.3
index 5b3c1e4..a7a1058 100644
--- a/libnmdb/libnmdb.3
+++ b/libnmdb/libnmdb.3
@@ -47,10 +47,10 @@ libnmdb - Library for interacting with a nmdb server
 .sp
 .BI "int nmdb_incr(nmdb_t *" db ","
 .BI "             const unsigned char *" key " , size_t " ksize ","
-.BI "             int64_t " increment ");"
+.BI "             int64_t " increment ", int64_t *" newval ");"
 .BI "int nmdb_cache_incr(nmdb_t *" db ","
 .BI "             const unsigned char *" key " , size_t " ksize ","
-.BI "             int64_t " increment ");"
+.BI "             int64_t " increment ", int64_t *" newval ");"
 .fi
 .SH DESCRIPTION
 
@@ -157,7 +157,10 @@ bit number to add to the value (it can be negative), and returns 2 if the
 increment was performed, 1 if the value was not in the appropriate format, 0
 if the key was not in the database/cache, or < 0 on failure.
 The value MUST be a NULL-terminated string with only a number in base 10 in it
-(i.e. it must be parseable by strtoll(3)).
+(i.e. it must be parseable by strtoll(3)). If the number was incremented
+correctly and the
+.I newval
+parameter is not NULL, it will be set to the resulted value.
 
 .SH SEE ALSO
 
diff --git a/libnmdb/libnmdb.c b/libnmdb/libnmdb.c
index fd52306..800d43b 100644
--- a/libnmdb/libnmdb.c
+++ b/libnmdb/libnmdb.c
@@ -573,11 +573,11 @@ int nmdb_cache_cas(nmdb_t *db, const unsigned char *key, size_t ksize,
 
 
 static int do_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
-		int64_t increment, unsigned short flags)
+		int64_t increment, int64_t *newval, unsigned short flags)
 {
 	ssize_t rv, t;
-	unsigned char *buf;
-	size_t bufsize, payload_offset, reqsize;
+	unsigned char *buf, *payload;
+	size_t bufsize, payload_offset, reqsize, psize;
 	uint32_t reply;
 	struct nmdb_srv *srv;
 
@@ -602,11 +602,17 @@ static int do_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bufsize, NULL, NULL);
+	psize = sizeof(int64_t);
+	reply = get_rep(srv, buf, bufsize, &payload, &psize);
 
 	switch (reply) {
 		case REP_OK:
 			rv = 2;
+			if (newval != NULL && psize == sizeof(int64_t) + 4) {
+				/* skip the 4 bytes of length */
+				*newval = *((int64_t *) (payload + 4));
+				*newval = ntohll(*newval);
+			}
 			break;
 		case REP_NOMATCH:
 			rv = 1;
@@ -626,15 +632,15 @@ exit:
 }
 
 int nmdb_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
-		int64_t increment)
+		int64_t increment, int64_t *newval)
 {
-	return do_incr(db, key, ksize, increment, 0);
+	return do_incr(db, key, ksize, increment, newval, 0);
 }
 
 int nmdb_cache_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
-		int64_t increment)
+		int64_t increment, int64_t *newval)
 {
-	return do_incr(db, key, ksize, increment, NMDB_CACHE_ONLY);
+	return do_incr(db, key, ksize, increment, newval, NMDB_CACHE_ONLY);
 }
 
 
diff --git a/libnmdb/nmdb.skel.h b/libnmdb/nmdb.skel.h
index 1c21a14..448fb15 100644
--- a/libnmdb/nmdb.skel.h
+++ b/libnmdb/nmdb.skel.h
@@ -90,9 +90,9 @@ int nmdb_cache_cas(nmdb_t *db, const unsigned char *key, size_t ksize,
 		const unsigned char *newval, size_t nvsize);
 
 int nmdb_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
-		                int64_t increment);
+		int64_t increment, int64_t *newval);
 int nmdb_cache_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
-		                int64_t increment);
+                int64_t increment, int64_t *newval);
 
 int nmdb_stats(nmdb_t *db, unsigned char *buf, size_t bsize,
 		unsigned int *nservers, unsigned int *nstats);
diff --git a/nmdb/cache.c b/nmdb/cache.c
index 5f8ae14..522ac4d 100644
--- a/nmdb/cache.c
+++ b/nmdb/cache.c
@@ -363,12 +363,15 @@ exit:
  *   -1 if the value was not in the cache.
  *   -2 if the value was not null terminated.
  *   -3 if there was a memory error.
+ *
+ * The new value will be set in the newval parameter if the increment was
+ * successful.
  */
 int cache_incr(struct cache *cd, const unsigned char *key, size_t ksize,
-		int64_t increment)
+		int64_t increment, int64_t *newval)
 {
 	uint32_t h = 0;
-	unsigned char *val, *newval;
+	unsigned char *val;
 	int64_t intval;
 	size_t vsize;
 	struct cache_chain *c;
@@ -397,15 +400,16 @@ int cache_incr(struct cache *cd, const unsigned char *key, size_t ksize,
 	 * and strlen('18446744073709551615') = 20, so if the value is smaller
 	 * than 24 (just in case) we create a new buffer. */
 	if (vsize < 24) {
-		newval = malloc(24);
-		if (newval == NULL)
+		unsigned char *nv = malloc(24);
+		if (nv == NULL)
 			return -3;
 		free(val);
-		e->val = val = newval;
+		e->val = val = nv;
 		e->vsize = vsize = 24;
 	}
 
 	snprintf((char *) val, vsize, "%23lld", (long long int) intval);
+	*newval = intval;
 
 	return 1;
 }
diff --git a/nmdb/cache.h b/nmdb/cache.h
index c4d3d7f..039dd91 100644
--- a/nmdb/cache.h
+++ b/nmdb/cache.h
@@ -49,7 +49,7 @@ int cache_cas(struct cache *cd, const unsigned char *key, size_t ksize,
 		const unsigned char *oldval, size_t ovsize,
 		const unsigned char *newval, size_t nvsize);
 int cache_incr(struct cache *cd, const unsigned char *key, size_t ksize,
-		int64_t increment);
+		int64_t increment, int64_t *newval);
 
 #endif
 
diff --git a/nmdb/dbloop.c b/nmdb/dbloop.c
index e50901d..0a7e4a7 100644
--- a/nmdb/dbloop.c
+++ b/nmdb/dbloop.c
@@ -13,6 +13,7 @@
 #include "net-const.h"
 #include "req.h"
 #include "log.h"
+#include "netutils.h"
 
 
 static void *db_loop(void *arg);
@@ -216,7 +217,9 @@ static void process_op(db_t *db, struct queue_entry *e)
 			return;
 		}
 
-		e->req->reply_mini(e->req, REP_OK);
+		intval = htonll(intval);
+		e->req->reply_long(e->req, REP_OK,
+				(unsigned char *) &intval, sizeof(intval));
 
 		free(dbval);
 
diff --git a/nmdb/parse.c b/nmdb/parse.c
index 57a2ba8..90d6670 100644
--- a/nmdb/parse.c
+++ b/nmdb/parse.c
@@ -455,7 +455,7 @@ static void parse_incr(struct req_info *req)
 	int cres, cache_only;
 	const unsigned char *key;
 	uint32_t ksize;
-	int64_t increment;
+	int64_t increment, newval;
 	const int max = 65536;
 
 	/* Request format:
@@ -481,7 +481,7 @@ static void parse_incr(struct req_info *req)
 	key = req->payload + sizeof(uint32_t);
 	increment = ntohll( * (int64_t *) (key + ksize) );
 
-	cres = cache_incr(cache_table, key, ksize, increment);
+	cres = cache_incr(cache_table, key, ksize, increment, &newval);
 	if (cres == -3) {
 		req->reply_err(req, ERR_MEM);
 		return;
@@ -510,10 +510,14 @@ static void parse_incr(struct req_info *req)
 
 		queue_signal(op_queue);
 	} else {
-		if (cres == -1)
+		if (cres == -1) {
 			req->reply_mini(req, REP_NOTIN);
-		else
-			req->reply_mini(req, REP_OK);
+		} else {
+			newval = htonll(newval);
+			req->reply_long(req, REP_OK,
+					(unsigned char *) &newval,
+					sizeof(newval));
+		}
 	}
 
 	return;
diff --git a/tests/c/incr.c b/tests/c/incr.c
index a0604d1..f0036a3 100644
--- a/tests/c/incr.c
+++ b/tests/c/incr.c
@@ -18,6 +18,7 @@ int main(int argc, char **argv)
 	char *initval = "0";
 	size_t ksize;
 	long long int increment;
+	int64_t newval;
 	nmdb_t *db;
 
 	if (argc != 3) {
@@ -49,16 +50,17 @@ int main(int argc, char **argv)
 
 	timer_start();
 	for (i = 0; i < times; i++) {
-		r = NINCR(db, (unsigned char *) key, ksize, increment);
+		r = NINCR(db, (unsigned char *) key, ksize, increment,
+				&newval);
 		if (r != 2) {
-			printf("result: %d\n", r);
+			printf("result: %d %lld\n", r, (long long) newval);
 			perror("Incr");
 			return 1;
 		}
 	}
 	s_elapsed = timer_stop();
 
-	printf("%lu\n", s_elapsed);
+	printf("%lu %lld\n", s_elapsed, (long long) newval);
 
 	nmdb_free(db);