git » nmdb » commit f815f63

Make common functions for request handling in the library

author Alberto Bertogli
2008-06-04 04:19:02 UTC
committer Alberto Bertogli
2008-06-04 04:19:02 UTC
parent 2af0a2049e9807d797f0bd06abc1fc9177ae82d9

Make common functions for request handling in the library

Instead of having duplicate code for creating the request buffer, setting
the header and adding the payload, use some simple common functions.

They're obviously not exported and quite specific to this use, but make
the resulting code much nicer.

Tested extensively with the random1.py test.

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

libnmdb/libnmdb.c +116 -141

diff --git a/libnmdb/libnmdb.c b/libnmdb/libnmdb.c
index b5271cc..e2ffc59 100644
--- a/libnmdb/libnmdb.c
+++ b/libnmdb/libnmdb.c
@@ -242,15 +242,80 @@ static struct nmdb_srv *select_srv(nmdb_t *db,
 	return &(db->servers[n]);
 }
 
+/* Creates a new buffer for packets */
+static unsigned char *new_packet(struct nmdb_srv *srv, unsigned int request,
+		size_t *bufsize, size_t *payload_offset, ssize_t payload_size)
+{
+	unsigned char *buf, *p;
+	unsigned int moff = srv_get_msg_offset(srv);
+
+	if (payload_size == -1) {
+		/* Because our callers will reuse the buffer to get the reply,
+		 * and we don't know how big it will be, we just alloc a bit
+		 * over the max packet (64kb) */
+		*bufsize = 68 * 1024;
+	} else {
+		*bufsize = moff + 8 + payload_size;
+	}
+	buf = malloc(*bufsize);
+	if (buf == NULL)
+		return NULL;
+
+	p = buf + moff;
+
+	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
+	* ((uint32_t *) p + 1) = htonl(request);
+
+	if (payload_offset != NULL)
+		*payload_offset = moff + 8;
+
+	return buf;
+}
+
+/* Functions to append different numbers of (value, len) to the given buffer;
+ * it's not worth the trouble of making this generic because we never go past
+ * three and they're quite trivial */
+static size_t append_1v(unsigned char *buf,
+		const unsigned char *datum, size_t dsize)
+{
+	* ((uint32_t *) buf) = htonl(dsize);
+	memcpy(buf + 4, datum, dsize);
+	return 4 + dsize;
+}
+
+static size_t append_2v(unsigned char *buf,
+		const unsigned char *datum1, size_t dsize1,
+		const unsigned char *datum2, size_t dsize2)
+{
+	* ((uint32_t *) buf) = htonl(dsize1);
+	* ((uint32_t *) buf + 1) = htonl(dsize2);
+	memcpy(buf + 8, datum1, dsize1);
+	memcpy(buf + 8 + dsize1, datum2, dsize2);
+	return 8 + dsize1 + dsize2;
+}
+
+static size_t append_3v(unsigned char *buf,
+		const unsigned char *datum1, size_t dsize1,
+		const unsigned char *datum2, size_t dsize2,
+		const unsigned char *datum3, size_t dsize3)
+{
+	* ((uint32_t *) buf) = htonl(dsize1);
+	* ((uint32_t *) buf + 1) = htonl(dsize2);
+	* ((uint32_t *) buf + 2) = htonl(dsize3);
+	memcpy(buf + 12, datum1, dsize1);
+	memcpy(buf + 12 + dsize1, datum2, dsize2);
+	memcpy(buf + 12 + dsize1 + dsize2, datum3, dsize3);
+	return 12 + dsize1 + dsize2 + dsize3;
+}
+
 
 static ssize_t do_get(nmdb_t *db,
 		const unsigned char *key, size_t ksize,
 		unsigned char *val, size_t vsize, int impact_db)
 {
-	int moff;
 	ssize_t rv, t;
 	unsigned char *buf, *p;
-	size_t bsize, reqsize, psize = 0;
+	size_t bufsize, reqsize, payload_offset, psize = 0;
 	uint32_t request, reply;
 	struct nmdb_srv *srv;
 
@@ -261,37 +326,19 @@ static ssize_t do_get(nmdb_t *db,
 	}
 
 	srv = select_srv(db, key, ksize);
-	moff = srv_get_msg_offset(srv);
-
-	/* Use the same buffer for the request and the reply.
-	 * Request: 4 bytes ver+id, 4 bytes request code, 4 bytes ksize,
-	 * 		ksize bytes key.
-	 * Reply: 4 bytes id, 4 bytes reply code, 4 bytes vsize,
-	 * 		vsize bytes key.
-	 *
-	 * We don't know vsize beforehand, but we do know our max packet size
-	 * is 64kb. We malloc 68kb just in case.
-	 */
-	bsize = 68 * 1024;
-	buf = malloc(bsize);
+	buf = new_packet(srv, request, &bufsize, &payload_offset, -1);
 	if (buf == NULL)
 		return -1;
+	reqsize = payload_offset;
+	reqsize += append_1v(buf + payload_offset, key, ksize);
 
-	p = buf + moff;
-
-	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-	* ((uint32_t *) p + 1) = htonl(request);
-	* ((uint32_t *) p + 2) = htonl(ksize);
-	memcpy(p + 3 * 4, key, ksize);
-	reqsize = 3 * 4 + ksize;
-
-	t = srv_send(srv, buf, moff + reqsize);
+	t = srv_send(srv, buf, reqsize);
 	if (t <= 0) {
 		rv = -2;
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bsize, &p, &psize);
+	reply = get_rep(srv, buf, bufsize, &p, &psize);
 
 	if (reply == REP_CACHE_MISS || reply == REP_NOTIN) {
 		rv = -1;
@@ -339,10 +386,9 @@ static int do_set(nmdb_t *db, const unsigned char *key, size_t ksize,
 		const unsigned char *val, size_t vsize,
 		int impact_db, int async)
 {
-	int moff;
 	ssize_t rv, t;
-	unsigned char *buf, *p;
-	size_t bsize;
+	unsigned char *buf;
+	size_t bufsize, payload_offset, reqsize;
 	uint32_t request, reply;
 	struct nmdb_srv *srv;
 
@@ -356,34 +402,21 @@ static int do_set(nmdb_t *db, const unsigned char *key, size_t ksize,
 	}
 
 	srv = select_srv(db, key, ksize);
-	moff = srv_get_msg_offset(srv);
-
-	/* Use the same buffer for the request and the reply.
-	 * Request: 4 bytes ver+id, 4 bytes request code, 4 bytes ksize, 4
-	 *		bytes vsize, ksize bytes key, vsize bytes val.
-	 * Reply: 4 bytes id, 4 bytes reply code.
-	 */
-	bsize = moff + 4 + 4 + 4 + 4 + ksize + vsize;
-	buf = malloc(bsize);
+
+	buf = new_packet(srv, request, &bufsize, &payload_offset,
+			4 * 2 + ksize + vsize);
 	if (buf == NULL)
 		return -1;
+	reqsize = payload_offset;
+	reqsize += append_2v(buf + payload_offset, key, ksize, val, vsize);
 
-	p = buf + moff;
-
-	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-	* ((uint32_t *) p + 1) = htonl(request);
-	* ((uint32_t *) p + 2) = htonl(ksize);
-	* ((uint32_t *) p + 3) = htonl(vsize);
-	memcpy(p + 4 * 4, key, ksize);
-	memcpy(p + 4 * 4 + ksize, val, vsize);
-
-	t = srv_send(srv, buf, bsize);
+	t = srv_send(srv, buf, reqsize);
 	if (t <= 0) {
 		rv = -1;
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bsize, NULL, NULL);
+	reply = get_rep(srv, buf, bufsize, NULL, NULL);
 
 	if (reply == REP_OK) {
 		rv = 1;
@@ -422,10 +455,9 @@ int nmdb_cache_set(nmdb_t *db, const unsigned char *key, size_t ksize,
 static int do_del(nmdb_t *db, const unsigned char *key, size_t ksize,
 		int impact_db, int async)
 {
-	int moff;
 	ssize_t rv, t;
-	unsigned char *buf, *p;
-	size_t bsize;
+	unsigned char *buf;
+	size_t bufsize, payload_offset, reqsize;
 	uint32_t request, reply;
 	struct nmdb_srv *srv;
 
@@ -439,32 +471,20 @@ static int do_del(nmdb_t *db, const unsigned char *key, size_t ksize,
 	}
 
 	srv = select_srv(db, key, ksize);
-	moff = srv_get_msg_offset(srv);
-
-	/* Use the same buffer for the request and the reply.
-	 * Request: 4 bytes ver+id, 4 bytes request code, 4 bytes ksize,
-	 * 		ksize bytes key.
-	 * Reply: 4 bytes id, 4 bytes reply code.
-	 */
-	bsize = moff + 8 + 4 + ksize;
-	buf = malloc(bsize);
+
+	buf = new_packet(srv, request, &bufsize, &payload_offset, 4 + ksize);
 	if (buf == NULL)
 		return -1;
+	reqsize = payload_offset;
+	reqsize += append_1v(buf + payload_offset, key, ksize);
 
-	p = buf + moff;
-
-	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-	* ((uint32_t *) p + 1) = htonl(request);
-	* ((uint32_t *) p + 2) = htonl(ksize);
-	memcpy(p + 3 * 4, key, ksize);
-
-	t = srv_send(srv, buf, bsize);
+	t = srv_send(srv, buf, reqsize);
 	if (t <= 0) {
 		rv = -1;
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bsize, NULL, NULL);
+	reply = get_rep(srv, buf, bufsize, NULL, NULL);
 
 	if (reply == REP_OK) {
 		rv = 1;
@@ -504,10 +524,9 @@ static int do_cas(nmdb_t *db, const unsigned char *key, size_t ksize,
 		const unsigned char *newval, size_t nvsize,
 		int impact_db)
 {
-	int moff;
 	ssize_t rv, t;
-	unsigned char *buf, *p, *q;
-	size_t bsize;
+	unsigned char *buf;
+	size_t bufsize, payload_offset, reqsize;
 	uint32_t request, reply;
 	struct nmdb_srv *srv;
 
@@ -516,41 +535,22 @@ static int do_cas(nmdb_t *db, const unsigned char *key, size_t ksize,
 		request = REQ_CAS;
 
 	srv = select_srv(db, key, ksize);
-	moff = srv_get_msg_offset(srv);
-
-	/* 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 = moff + 4 + 4 + 4 + 4 + 4 + ksize + ovsize + nvsize;
-	buf = malloc(bsize);
+
+	buf = new_packet(srv, request, &bufsize, &payload_offset,
+			4 * 3 + ksize + ovsize + nvsize);
 	if (buf == NULL)
 		return -1;
+	reqsize = payload_offset;
+	reqsize += append_3v(buf + payload_offset, key, ksize, oldval, ovsize,
+			newval, nvsize);
 
-	p = buf + moff;
-
-	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-	* ((uint32_t *) p + 1) = htonl(request);
-	* ((uint32_t *) p + 2) = htonl(ksize);
-	* ((uint32_t *) p + 3) = htonl(ovsize);
-	* ((uint32_t *) p + 4) = htonl(nvsize);
-	q = p + 5 * 4;
-	memcpy(q, key, ksize);
-	q += ksize;
-	memcpy(q, oldval, ovsize);
-	q += ovsize;
-	memcpy(q, newval, nvsize);
-
-	srv = select_srv(db, key, ksize);
-	t = srv_send(srv, buf, bsize);
+	t = srv_send(srv, buf, reqsize);
 	if (t <= 0) {
 		rv = -1;
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bsize, NULL, NULL);
+	reply = get_rep(srv, buf, bufsize, NULL, NULL);
 
 	if (reply == REP_OK) {
 		rv = 2;
@@ -618,10 +618,9 @@ static uint64_t htonll(uint64_t x)
 static int do_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
 		int64_t increment, int impact_db)
 {
-	int moff;
 	ssize_t rv, t;
-	unsigned char *buf, *p;
-	size_t bsize;
+	unsigned char *buf;
+	size_t bufsize, payload_offset, reqsize;
 	uint32_t request, reply;
 	struct nmdb_srv *srv;
 
@@ -631,35 +630,25 @@ static int do_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
 		request = REQ_CACHE_INCR;
 
 	srv = select_srv(db, key, ksize);
-	moff = srv_get_msg_offset(srv);
-
-	/* Use the same buffer for the request and the reply.
-	 * Request: 4 bytes ver+id, 4 bytes request code, 4 bytes ksize,
-	 *		ksize bytes key, 8 bytes increment.
-	 * Reply: 4 bytes id, 4 bytes reply code.
-	 */
-	bsize = moff + 4 + 4 + 4 + ksize + 8;
-	buf = malloc(bsize);
-	if (buf == NULL)
-		return -1;
 
 	increment = htonll(increment);
 
-	p = buf + moff;
-
-	* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-	* ((uint32_t *) p + 1) = htonl(request);
-	* ((uint32_t *) p + 2) = htonl(ksize);
-	memcpy(p + 3 * 4, key, ksize);
-	memcpy(p + 3 * 4 + ksize, &increment, sizeof(int64_t));
+	buf = new_packet(srv, request, &bufsize, &payload_offset,
+			4 + ksize + sizeof(int64_t));
+	if (buf == NULL)
+		return -1;
+	reqsize = payload_offset;
+	reqsize += append_1v(buf + payload_offset, key, ksize);
+	memcpy(buf + reqsize, &increment, sizeof(int64_t));
+	reqsize += sizeof(int64_t);
 
-	t = srv_send(srv, buf, bsize);
+	t = srv_send(srv, buf, reqsize);
 	if (t <= 0) {
 		rv = -1;
 		goto exit;
 	}
 
-	reply = get_rep(srv, buf, bsize, NULL, NULL);
+	reply = get_rep(srv, buf, bufsize, NULL, NULL);
 
 	switch (reply) {
 		case REP_OK:
@@ -698,9 +687,10 @@ int nmdb_cache_incr(nmdb_t *db, const unsigned char *key, size_t ksize,
 int nmdb_stats(nmdb_t *db, unsigned char *buf, size_t bsize,
 		unsigned int *nservers, unsigned int *nstats)
 {
-	int i, moff;
-	ssize_t t, reqsize, reply;
-	unsigned char *request, *p;
+	int i;
+	size_t reqsize;
+	ssize_t t, reply;
+	unsigned char *request;
 	struct nmdb_srv *srv;
 
 	/* This buffer is used for a single reply, must be big enough to
@@ -716,22 +706,7 @@ int nmdb_stats(nmdb_t *db, unsigned char *buf, size_t bsize,
 
 	for (i = 0; i < db->nservers; i++) {
 		srv = db->servers + i;
-
-		moff = srv_get_msg_offset(srv);
-
-		/* Request: 4 bytes ver+id, 4 bytes request code.
-		 * Reply: 4 bytes lenght + variable amount of uint64_t.*/
-
-		/* We need to tailor the request for the different message
-		 * offsets */
-		reqsize = moff + 4 + 4;
-		request = malloc(reqsize);
-		if (request == NULL)
-			return -1;
-
-		p = request + moff;
-		* (uint32_t *) p = htonl( (PROTO_VER << 28) | ID_CODE );
-		* ((uint32_t *) p + 1) = htonl(REQ_STATS);
+		request = new_packet(srv, REQ_STATS, &reqsize, NULL, 0);
 
 		t = srv_send(srv, request, reqsize);
 		free(request);