[PATCH] chunkd: add support for multiple key/value tables

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is fully fleshed out and working, but I have not committed it yet,
in case there is feedback or major objections.

The following patch presents the last major chunkd conceptual change
I felt was needed in the chunkd API:  multiple key/value tables.

Applications and users will often want to be partitioned away from
each other, or simply have a need for something other than simply a
flat namespace.  With this change, chunkd's API is now much like Amazon
S3, which has a shared namespace for buckets, and then each bucket has
its own namespace.

This is made possible with a single API addition, TABLE OPEN.

Here is what a chunkd session now looks like, with this patch:

	LOGIN(user="jgarzik")
	TABLE-OPEN(name="tabled")
	GET...
	GET...
	GET...
	PUT...
	PUT...
	PUT...

The corresponding C API call is stc_table_open().

With this change, some of my upper layer projects (NFS, SQL) become
more manageable.  This change enables me to dedicate several tables
to each application and/or user.


 configure.ac         |    1 
 doc/chcli.cfg        |    3 +
 include/chunk_msg.h  |    4 +
 include/chunkc.h     |    8 ++
 lib/chunkdc.c        |   42 ++++++++++++++
 server/Makefile.am   |    6 +-
 server/be-fs.c       |  152 ++++++++++++++++++++++++++++++++++++++++++++-------
 server/chunkd.h      |   15 +++--
 server/object.c      |    7 +-
 server/server.c      |   64 +++++++++++++++++++--
 test/auth.c          |    6 ++
 test/basic-object.c  |    3 +
 test/it-works.c      |    9 +++
 test/large-object.c  |    3 +
 test/lotsa-objects.c |    3 +
 test/nop.c           |    3 +
 test/test.h          |    2 
 tools/chcli.c        |   38 +++++++++++-
 18 files changed, 332 insertions(+), 37 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8c32383..f54cf27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,6 +79,7 @@ AC_CHECK_LIB(event, event_base_new, EVENT_LIBS=-levent,
 AC_CHECK_LIB(argp, argp_parse, ARGP_LIBS=-largp)
 AC_CHECK_LIB(socket, bind, SOCKET_LIBS=-lsocket)
 PKG_CHECK_MODULES(CLDC, libcldc)
+PKG_CHECK_MODULES(TOKYOCABINET, tokyocabinet)
 
 dnl -----------------------------
 dnl Check for cld program, used
diff --git a/doc/chcli.cfg b/doc/chcli.cfg
index c27b956..63ef148 100644
--- a/doc/chcli.cfg
+++ b/doc/chcli.cfg
@@ -9,6 +9,9 @@
 ## provide the host:port pair of the chunkd service
 # host=127.0.0.1:9191
 
+## provide the initial table to open and communicate with
+# table=my_table_name
+
 ## provide the username and secret key password for authentication.
 ## password is ready from CHCLI_PASSWORD env var, if not supplied here.
 # username=guest
diff --git a/include/chunk_msg.h b/include/chunk_msg.h
index 90272ca..4d3d208 100644
--- a/include/chunk_msg.h
+++ b/include/chunk_msg.h
@@ -21,6 +21,8 @@ enum chunksrv_ops {
 	CHO_DEL			= 4,
 	CHO_LIST		= 5,
 	CHO_LOGIN		= 6,
+	CHO_TABLE_OPEN		= 7,
+	CHO_TABLE_DEL		= 8,
 };
 
 enum chunk_errcode {
@@ -32,10 +34,12 @@ enum chunk_errcode {
 	che_NoSuchKey			= 5,
 	che_SignatureDoesNotMatch	= 6,
 	che_InvalidKey			= 7,
+	che_InvalidTable		= 8,
 };
 
 enum chunk_flags {
 	CHF_SYNC		= (1 << 0),	/* force write to media */
+	CHF_TABLE_NEW		= (1 << 1),	/* create table */
 };
 
 struct chunksrv_req {
diff --git a/include/chunkc.h b/include/chunkc.h
index 768eecd..04cbd87 100644
--- a/include/chunkc.h
+++ b/include/chunkc.h
@@ -44,6 +44,8 @@ extern void stc_init(void);
 extern struct st_client *stc_new(const char *service_host, int port,
 				 const char *user, const char *secret_key,
 				 bool encrypt);
+extern bool stc_table_open(struct st_client *stc, const void *key, size_t key_len,
+		    uint32_t flags);
 
 extern bool stc_get(struct st_client *stc, const void *key, size_t key_len,
 	     size_t (*write_cb)(void *, size_t, size_t, void *),
@@ -103,4 +105,10 @@ static inline bool stc_delz(struct st_client *stc, const char *key)
 	return stc_del(stc, key, strlen(key) + 1);
 }
 
+static inline bool stc_table_openz(struct st_client *stc, const char *key,
+				   uint32_t flags)
+{
+	return stc_table_open(stc, key, strlen(key) + 1, flags);
+}
+
 #endif /* __STC_H__ */
diff --git a/lib/chunkdc.c b/lib/chunkdc.c
index 1597e91..c9606a8 100644
--- a/lib/chunkdc.c
+++ b/lib/chunkdc.c
@@ -453,6 +453,48 @@ size_t stc_get_recv(struct st_client *stc, void *data, size_t data_len)
 	return done_cnt;
 }
 
+bool stc_table_open(struct st_client *stc, const void *key, size_t key_len,
+		    uint32_t flags)
+{
+	struct chunksrv_resp resp;
+	struct chunksrv_req *req = (struct chunksrv_req *) stc->req_buf;
+
+	if (stc->verbose)
+		fprintf(stderr, "libstc: TABLE OPEN(%u, %u)\n",
+			(unsigned int) key_len,
+			flags);
+
+	if (!key_valid(key, key_len))
+		return false;
+
+	/* initialize request */
+	req_init(stc, req);
+	req->op = CHO_TABLE_OPEN;
+	req->flags = (flags & CHF_TABLE_NEW);
+	req_set_key(req, key, key_len);
+
+	/* sign request */
+	chreq_sign(req, stc->key, req->sig);
+
+	/* write request */
+	if (!net_write(stc, req, req_len(req)))
+		return false;
+
+	/* read response header */
+	if (!net_read(stc, &resp, sizeof(resp)))
+		return false;
+
+	/* check response code */
+	if (resp.resp_code != che_Success) {
+		if (stc->verbose)
+			fprintf(stderr, "TABLE OPEN resp code: %d\n",
+				resp.resp_code);
+		return false;
+	}
+
+	return true;
+}
+
 bool stc_put(struct st_client *stc, const void *key, size_t key_len,
 	     size_t (*read_cb)(void *, size_t, size_t, void *),
 	     uint64_t len, void *user_data, uint32_t flags)
diff --git a/server/Makefile.am b/server/Makefile.am
index 70fd066..7589a38 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -1,5 +1,6 @@
 
-INCLUDES	= -I$(top_srcdir)/include @GLIB_CFLAGS@ @CLDC_CFLAGS@
+INCLUDES	= -I$(top_srcdir)/include @GLIB_CFLAGS@ @CLDC_CFLAGS@ \
+		  @TOKYOCABINET_CFLAGS@
 
 sbin_PROGRAMS	= chunkd
 
@@ -8,4 +9,5 @@ chunkd_SOURCES	= chunkd.h		\
 		  be-fs.c object.c server.c config.c cldu.c util.c
 chunkd_LDADD	= \
 		  @CLDC_LIBS@ @GLIB_LIBS@ @CRYPTO_LIBS@ \
-		  @SSL_LIBS@ @EVENT_LIBS@ @ARGP_LIBS@ @SOCKET_LIBS@
+		  @SSL_LIBS@ @EVENT_LIBS@ @ARGP_LIBS@ @SOCKET_LIBS@ \
+		  @TOKYOCABINET_LIBS@
diff --git a/server/be-fs.c b/server/be-fs.c
index fb301b8..48ce698 100644
--- a/server/be-fs.c
+++ b/server/be-fs.c
@@ -16,10 +16,14 @@
 #include <string.h>
 #include <errno.h>
 #include <syslog.h>
+#include <tcutil.h>
+#include <tchdb.h>
 #include "chunkd.h"
 
 #define BE_NAME		"fs"
 
+#define MDB_TABLE_ID	"__chunkd_table_id"
+
 struct fs_obj {
 	struct backend_obj	bo;
 
@@ -37,6 +41,103 @@ struct be_fs_obj_hdr {
 	uint32_t		key_len;
 };
 
+bool fs_table_open(const char *user, const void *kbuf, size_t klen,
+		   bool create_tbl, uint32_t *table_id,
+		   enum chunk_errcode *err_code)
+{
+	TCHDB *hdb;
+	char *db_fn = NULL, *table_path = NULL;
+	int omode, osize = 0, next_num;
+	bool rc = false;
+	uint32_t *val_p, table_id_le;
+
+	*err_code = che_InternalError;
+
+	/* validate table name */
+	if (klen < 1 || klen > CHD_KEY_SZ ||
+	    (klen >= strlen(MDB_TABLE_ID) &&
+	     !memcmp(kbuf, MDB_TABLE_ID, strlen(MDB_TABLE_ID)))) {
+		*err_code = che_InvalidArgument;
+		return false;
+	}
+
+	/*
+	 * open master database
+	 */
+	if (asprintf(&db_fn, "%s/master.tch", chunkd_srv.vol_path) < 0)
+		return false;
+
+	hdb = tchdbnew();
+	if (!hdb)
+		goto out;
+
+	omode = HDBOREADER | HDBONOLCK;
+	if (create_tbl)
+		omode |= HDBOWRITER | HDBOCREAT | HDBOTSYNC;
+	if (!tchdbopen(hdb, db_fn, omode)) {
+		applog(LOG_ERR, "failed to open master table %s", db_fn);
+		goto out_hdb;
+	}
+
+	/*
+	 * lookup table name.  if found, return immediately
+	 */
+	val_p = tchdbget(hdb, kbuf, klen, &osize);
+	if (val_p) {
+		if (create_tbl) {
+			*err_code = che_InvalidArgument;
+			goto out_close;
+		}
+
+		*table_id = GUINT32_FROM_LE(*val_p);
+		goto out_ok;
+	}
+
+	/*
+	 * otherwise, we now begin the process of table creation
+	 */
+
+	if (!create_tbl) {
+		*err_code = che_InvalidArgument;
+		goto out_close;
+	}
+
+	/* allocate unique integer id for table */
+	next_num = tchdbaddint(hdb, MDB_TABLE_ID, strlen(MDB_TABLE_ID)+1, 1);
+	if (next_num == INT_MIN)
+		goto out_close;
+
+	*table_id = next_num;
+	table_id_le = GUINT32_TO_LE(next_num);
+
+	/*
+	 * create table directory, $BASE_PATH/table-id
+	 */
+	if (asprintf(&table_path, "%s/%d", chunkd_srv.vol_path, next_num) < 0)
+		goto out_close;
+
+	if ((mkdir(table_path, 0777) < 0) && (errno != EEXIST)) {
+		applog(LOG_ERR, "mkdir(%s): %s", table_path, strerror(errno));
+		goto out_close;
+	}
+
+	/* finally, store in table_name->table_id map */
+	if (!tchdbput(hdb, kbuf, klen, &table_id_le, sizeof(table_id_le)))
+		goto out_close;
+
+out_ok:
+	*err_code = che_Success;
+	rc = true;
+out_close:
+	tchdbclose(hdb);
+out_hdb:
+	tchdbdel(hdb);
+out:
+	free(db_fn);
+	free(table_path);
+	return rc;
+}
+
 static struct fs_obj *fs_obj_alloc(void)
 {
 	struct fs_obj *obj;
@@ -53,7 +154,7 @@ static struct fs_obj *fs_obj_alloc(void)
 	return obj;
 }
 
-static char *fs_obj_pathname(const void *key, size_t key_len)
+static char *fs_obj_pathname(uint32_t table_id,const void *key, size_t key_len)
 {
 	char *s = NULL;
 	char prefix[5] = "";
@@ -62,19 +163,23 @@ static char *fs_obj_pathname(const void *key, size_t key_len)
 	unsigned char md[SHA256_DIGEST_LENGTH];
 	char mdstr[(SHA256_DIGEST_LENGTH * 2) + 1];
 
+	if (!table_id || !key || !key_len)
+		return NULL;
+
 	SHA256(key, key_len, md);
 	hexstr(md, SHA256_DIGEST_LENGTH, mdstr);
 
 	memcpy(prefix, mdstr, 4);
 
-	slen = strlen(chunkd_srv.vol_path) + 1 + 
-	       strlen(prefix) + 1 +
-	       strlen(mdstr) + 1;
+	slen = strlen(chunkd_srv.vol_path) + 1 +	/* volume */
+	       16 +					/* table id */
+	       strlen(prefix) + 1 +			/* prefix */
+	       strlen(mdstr) + 1;			/* filename */
 	s = malloc(slen);
 	if (!s)
 		return NULL;
 
-	sprintf(s, "%s/%s", chunkd_srv.vol_path, prefix);
+	sprintf(s, "%s/%u/%s", chunkd_srv.vol_path, table_id, prefix);
 
 	/* create subdir on the fly, if not already exists */
 	if (stat(s, &st) < 0) {
@@ -97,7 +202,8 @@ static char *fs_obj_pathname(const void *key, size_t key_len)
 		goto err_out;
 	}
 
-	sprintf(s, "%s/%s/%s", chunkd_srv.vol_path, prefix, mdstr + 4);
+	sprintf(s, "%s/%u/%s/%s", chunkd_srv.vol_path, table_id,
+		prefix, mdstr + 4);
 
 	return s;
 
@@ -114,7 +220,8 @@ static bool key_valid(const void *key, size_t key_len)
 	return true;
 }
 
-struct backend_obj *fs_obj_new(const void *key, size_t key_len,
+struct backend_obj *fs_obj_new(uint32_t table_id,
+			       const void *key, size_t key_len,
 			       enum chunk_errcode *err_code)
 {
 	struct fs_obj *obj;
@@ -136,7 +243,7 @@ struct backend_obj *fs_obj_new(const void *key, size_t key_len,
 	}
 
 	/* build local fs pathname */
-	fn = fs_obj_pathname(key, key_len);
+	fn = fs_obj_pathname(table_id, key, key_len);
 	if (!fn) {
 		applog(LOG_ERR, "OOM in object_put");
 		*err_code = che_InternalError;
@@ -194,8 +301,9 @@ err_out:
 	return NULL;
 }
 
-struct backend_obj *fs_obj_open(const char *user, const void *key,
-				size_t key_len, enum chunk_errcode *err_code)
+struct backend_obj *fs_obj_open(uint32_t table_id, const char *user,
+				const void *key, size_t key_len,
+				enum chunk_errcode *err_code)
 {
 	struct fs_obj *obj;
 	struct stat st;
@@ -214,7 +322,7 @@ struct backend_obj *fs_obj_open(const char *user, const void *key,
 	}
 
 	/* build local fs pathname */
-	obj->in_fn = fs_obj_pathname(key, key_len);
+	obj->in_fn = fs_obj_pathname(table_id, key, key_len);
 	if (!obj->in_fn) {
 		*err_code = che_InternalError;
 		goto err_out;
@@ -457,7 +565,8 @@ bool fs_obj_write_commit(struct backend_obj *bo, const char *user,
 	return true;
 }
 
-bool fs_obj_delete(const char *user, const void *key, size_t key_len,
+bool fs_obj_delete(uint32_t table_id, const char *user,
+		   const void *key, size_t key_len,
 		   enum chunk_errcode *err_code)
 {
 	char *fn = NULL;
@@ -473,7 +582,7 @@ bool fs_obj_delete(const char *user, const void *key, size_t key_len,
 	}
 
 	/* build local fs pathname */
-	fn = fs_obj_pathname(key, key_len);
+	fn = fs_obj_pathname(table_id, key, key_len);
 	if (!fn)
 		goto err_out;
 
@@ -532,18 +641,22 @@ err_out:
 	return false;
 }
 
-GList *fs_list_objs(const char *user)
+GList *fs_list_objs(uint32_t table_id, const char *user)
 {
 	GList *res = NULL;
 	struct dirent *de, *root_de;
 	DIR *d, *root;
-	char *sub;
+	char *sub, *table_path = NULL;
+
+	sub = alloca(strlen(chunkd_srv.vol_path) + 1 + 16 + 4 + 1);
 
-	sub = alloca(strlen(chunkd_srv.vol_path) + 1 + 4 + 1);
+	if (asprintf(&table_path, "%s/%u", chunkd_srv.vol_path, table_id) < 0)
+		return NULL;
 
-	root = opendir(chunkd_srv.vol_path);
+	root = opendir(table_path);
 	if (!root) {
-		syslogerr(chunkd_srv.vol_path);
+		syslogerr(table_path);
+		free(table_path);
 		return NULL;
 	}
 
@@ -555,7 +668,7 @@ GList *fs_list_objs(const char *user)
 		if (strlen(root_de->d_name) != 4)
 			continue;
 
-		sprintf(sub, "%s/%s", chunkd_srv.vol_path, root_de->d_name);
+		sprintf(sub, "%s/%s", table_path, root_de->d_name);
 		d = opendir(sub);
 		if (!d) {
 			syslogerr(sub);
@@ -688,6 +801,7 @@ GList *fs_list_objs(const char *user)
 
 	closedir(root);
 
+	free(table_path);
 	return res;
 }
 
diff --git a/server/chunkd.h b/server/chunkd.h
index d6b37c6..2058144 100644
--- a/server/chunkd.h
+++ b/server/chunkd.h
@@ -78,6 +78,9 @@ struct client {
 
 	char			user[CHD_USER_SZ + 1];
 
+	size_t			table_len;
+	uint32_t		table_id;
+
 	SSL			*ssl;
 	bool			read_want_write;
 	bool			write_want_read;
@@ -107,6 +110,7 @@ struct client {
 	char			netbuf[CLI_DATA_BUF_SZ];
 	char			netbuf_out[CLI_DATA_BUF_SZ];
 	char			key[CHD_KEY_SZ];
+	char			table[CHD_KEY_SZ];
 };
 
 struct backend_obj {
@@ -192,9 +196,9 @@ struct server {
 };
 
 /* be-fs.c */
-extern struct backend_obj *fs_obj_new(const void *kbuf, size_t klen,
+extern struct backend_obj *fs_obj_new(uint32_t table_id, const void *kbuf, size_t klen,
 				      enum chunk_errcode *err_code);
-extern struct backend_obj *fs_obj_open(const char *user,
+extern struct backend_obj *fs_obj_open(uint32_t table_id, const char *user,
 				       const void *kbuf, size_t klen,
 				       enum chunk_errcode *err_code);
 extern ssize_t fs_obj_write(struct backend_obj *bo, const void *ptr, size_t len);
@@ -202,11 +206,14 @@ extern ssize_t fs_obj_read(struct backend_obj *bo, void *ptr, size_t len);
 extern void fs_obj_free(struct backend_obj *bo);
 extern bool fs_obj_write_commit(struct backend_obj *bo, const char *user,
 				const char *hashstr, bool sync_data);
-extern bool fs_obj_delete(const char *user,
+extern bool fs_obj_delete(uint32_t table_id, const char *user,
 		          const void *kbuf, size_t klen,
 			  enum chunk_errcode *err_code);
-extern GList *fs_list_objs(const char *user);
 extern ssize_t fs_obj_sendfile(struct backend_obj *bo, int out_fd, size_t len);
+extern GList *fs_list_objs(uint32_t table_id, const char *user);
+extern bool fs_table_open(const char *user, const void *kbuf, size_t klen,
+			  bool create_tbl, uint32_t *table_id,
+			  enum chunk_errcode *err_code);
 
 /* object.c */
 extern bool object_del(struct client *cli);
diff --git a/server/object.c b/server/object.c
index 23b0aa9..027ce2b 100644
--- a/server/object.c
+++ b/server/object.c
@@ -30,7 +30,8 @@ bool object_del(struct client *cli)
 
 	resp_init_req(resp, &cli->creq);
 
-	rcb = fs_obj_delete(cli->user, cli->key, cli->key_len, &err);
+	rcb = fs_obj_delete(cli->table_id, cli->user,
+			    cli->key, cli->key_len, &err);
 	if (!rcb)
 		return cli_err(cli, err, true);
 
@@ -196,7 +197,7 @@ bool object_put(struct client *cli)
 	if (!user)
 		return cli_err(cli, che_AccessDenied, true);
 
-	cli->out_bo = fs_obj_new(cli->key, cli->key_len, &err);
+	cli->out_bo = fs_obj_new(cli->table_id, cli->key, cli->key_len, &err);
 	if (!cli->out_bo)
 		return cli_err(cli, err, true);
 
@@ -286,7 +287,7 @@ bool object_get(struct client *cli, bool want_body)
 
 	resp_init_req(&get_resp->resp, &cli->creq);
 
-	cli->in_obj = obj = fs_obj_open(cli->user, cli->key,
+	cli->in_obj = obj = fs_obj_open(cli->table_id, cli->user, cli->key,
 					cli->key_len, &err);
 	if (!obj) {
 		free(get_resp);
diff --git a/server/server.c b/server/server.c
index 2d9095f..a145706 100644
--- a/server/server.c
+++ b/server/server.c
@@ -117,6 +117,10 @@ static struct {
 	[che_InvalidKey] =
 	{ "che_InvalidKey", 400,
 	  "Invalid key presented" },
+
+	[che_InvalidTable] =
+	{ "che_InvalidTable", 400,
+	  "Invalid table requested, or table not open" },
 };
 
 void applog(int prio, const char *fmt, ...)
@@ -728,7 +732,7 @@ static bool volume_list(struct client *cli)
 	bool rcb;
 	GList *res = NULL;
 
-	res = fs_list_objs(cli->user);
+	res = fs_list_objs(cli->table_id, cli->user);
 
 	s = g_markup_printf_escaped(
 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
@@ -784,6 +788,23 @@ static bool volume_list(struct client *cli)
 	return rcb;
 }
 
+static bool volume_open(struct client *cli)
+{
+	enum chunk_errcode err = che_Success;
+
+	if (!fs_table_open(cli->user, cli->key, cli->key_len,
+			   (cli->creq.flags & CHF_TABLE_NEW),
+			   &cli->table_id, &err))
+		goto out;
+
+	memset(cli->table, 0, sizeof(cli->table));
+	memcpy(cli->table, cli->key, cli->key_len);
+	cli->table_len = cli->key_len;
+
+out:
+	return cli_err(cli, err, true);
+}
+
 static bool authcheck(const struct chunksrv_req *req, const void *key,
 		      size_t key_len, const char *secret_key)
 {
@@ -854,6 +875,8 @@ static const char *op2str(enum chunksrv_ops op)
 	case CHO_DEL:		return "CHO_DEL";
 	case CHO_LIST:		return "CHO_LIST";
 	case CHO_LOGIN:		return "CHO_LOGIN";
+	case CHO_TABLE_OPEN:	return "CHO_TABLE_OPEN";
+	case CHO_TABLE_DEL:	return "CHO_TABLE_DEL";
 
 	default:
 		return "BUG/UNKNOWN!";
@@ -867,14 +890,13 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events)
 {
 	struct chunksrv_req *req = &cli->creq;
 	bool rcb;
-	enum chunk_errcode err;
+	enum chunk_errcode err = che_InvalidArgument;
 	bool logged_in = (cli->user[0] != 0);
+	bool have_table = (cli->table_len > 0);
 
 	/* validate request header */
-	if (!valid_req_hdr(req)) {
-		err = che_InvalidArgument;
+	if (!valid_req_hdr(req))
 		goto err_out;
-	}
 
 	if (debugging)
 		applog(LOG_DEBUG, "REQ(op %s, key %s (%u), user %s) "
@@ -905,10 +927,31 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events)
 	}
 
 	/*
+	 * verify open-table requirement, for the operations that need it
+	 */
+	switch (req->op) {
+	case CHO_GET:
+	case CHO_GET_META:
+	case CHO_PUT:
+	case CHO_DEL:
+	case CHO_LIST:
+		if (!have_table) {
+			err = che_InvalidTable;
+			goto err_out;
+		}
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	/*
 	 * operations on objects
 	 */
 	switch (req->op) {
 	case CHO_LOGIN:
+		if (logged_in)
+			goto err_out;
 		rcb = login_user(cli);
 		break;
 	case CHO_NOP:
@@ -929,6 +972,17 @@ static bool cli_evt_exec_req(struct client *cli, unsigned int events)
 	case CHO_LIST:
 		rcb = volume_list(cli);
 		break;
+	case CHO_TABLE_OPEN:
+		rcb = volume_open(cli);
+		break;
+	case CHO_TABLE_DEL:
+#if 0
+		/* not implemented yet */
+		rcv = volume_del(cli);
+#else
+		rcb = cli_err(cli, che_InternalError, true);
+#endif
+		break;
 	default:
 		rcb = cli_err(cli, che_InvalidURI, true);
 		break;
diff --git a/test/auth.c b/test/auth.c
index 232efa7..ae28620 100644
--- a/test/auth.c
+++ b/test/auth.c
@@ -29,9 +29,15 @@ static void test(bool encrypt)
 	stc1 = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, encrypt);
 	OK(stc1);
 
+	rcb = stc_table_openz(stc1, TEST_TABLE, 0);
+	OK(rcb);
+
 	stc2 = stc_new(TEST_HOST, port, TEST_USER2, TEST_USER2_KEY, encrypt);
 	OK(stc2);
 
+	rcb = stc_table_openz(stc2, TEST_TABLE, 0);
+	OK(rcb);
+
 	/* store object 1 */
 	rcb = stc_put_inlinez(stc1, key1, val1, strlen(val1), 0);
 	OK(rcb);
diff --git a/test/basic-object.c b/test/basic-object.c
index 8f4c040..05b8630 100644
--- a/test/basic-object.c
+++ b/test/basic-object.c
@@ -27,6 +27,9 @@ static void test(bool encrypt)
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, encrypt);
 	OK(stc);
 
+	rcb = stc_table_openz(stc, TEST_TABLE, 0);
+	OK(rcb);
+
 	/* store object */
 	rcb = stc_put_inlinez(stc, key, val, strlen(val), 0);
 	OK(rcb);
diff --git a/test/it-works.c b/test/it-works.c
index ef923d8..87233bc 100644
--- a/test/it-works.c
+++ b/test/it-works.c
@@ -21,6 +21,15 @@ static void test(bool ssl)
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, ssl);
 	OK(stc);
 
+	/*
+	 * we must supply CHF_TABLE_NEW on the first iteration of
+	 * this test, because we are the first test in the testsuite,
+	 * and must create the database to be used by all other tests.
+	 */
+	rcb = stc_table_openz(stc, TEST_TABLE,
+			      ssl ? 0 : CHF_TABLE_NEW);
+	OK(rcb);
+
 	rcb = stc_ping(stc);
 	OK(rcb);
 
diff --git a/test/large-object.c b/test/large-object.c
index f49ca64..f0884b8 100644
--- a/test/large-object.c
+++ b/test/large-object.c
@@ -93,6 +93,9 @@ static void test(bool encrypt)
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, encrypt);
 	OK(stc);
 
+	rcb = stc_table_openz(stc, TEST_TABLE, 0);
+	OK(rcb);
+
 	sync();
 
 	gettimeofday(&ta, NULL);
diff --git a/test/lotsa-objects.c b/test/lotsa-objects.c
index bf6b96d..fbf5f81 100644
--- a/test/lotsa-objects.c
+++ b/test/lotsa-objects.c
@@ -33,6 +33,9 @@ static void test(int n_objects, bool encrypt)
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, encrypt);
 	OK(stc);
 
+	rcb = stc_table_openz(stc, TEST_TABLE, 0);
+	OK(rcb);
+
 	fprintf(stderr, "      lotsa-objects syncing...\n");
 	sync();
 
diff --git a/test/nop.c b/test/nop.c
index c683dc4..5771a2c 100644
--- a/test/nop.c
+++ b/test/nop.c
@@ -28,6 +28,9 @@ static void test(int n_nops, bool encrypt)
 	stc = stc_new(TEST_HOST, port, TEST_USER, TEST_USER_KEY, encrypt);
 	OK(stc);
 
+	rcb = stc_table_openz(stc, TEST_TABLE, 0);
+	OK(rcb);
+
 	gettimeofday(&ta, NULL);
 
 	/* send NOP messages */
diff --git a/test/test.h b/test/test.h
index dd99843..3321587 100644
--- a/test/test.h
+++ b/test/test.h
@@ -8,6 +8,8 @@
 
 #define TEST_HOST "localhost"
 
+#define TEST_TABLE "test"
+
 #define TEST_USER "testuser"
 #define TEST_USER_KEY "testuser"
 
diff --git a/tools/chcli.c b/tools/chcli.c
index bc8fad5..0d995a9 100644
--- a/tools/chcli.c
+++ b/tools/chcli.c
@@ -36,6 +36,8 @@ static struct argp_option options[] = {
 	  "Send GET output to FILE, rather than stdout" },
 	{ "ssl", 'S', NULL, 0,
 	  "Enable SSL channel security" },
+	{ "table", 't', "TABLE", 0,
+	  "Set table for storage and retrieval" },
 	{ "user", 'u', "USER", 0,
 	  "Set username to USER" },
 	{ "verbose", 'v', NULL, 0,
@@ -43,6 +45,8 @@ static struct argp_option options[] = {
 
 	{ "list-cmds", 1001, NULL, 0,
 	  "List supported commands" },
+	{ "create", 1002, NULL, 0,
+	  "Create new table (required, if table does not exist)" },
 
 	{ }
 };
@@ -78,6 +82,9 @@ static char *password;
 static char *output_fn;
 static char *key_data;
 static gsize key_data_len;
+static char *table_name;
+static size_t table_name_len;
+static bool table_create;
 static char *password_env = "CHCLI_PASSWORD";
 static bool chcli_verbose;
 static bool use_ssl;
@@ -197,6 +204,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 			free(s);
 		}
 
+		table_name = g_key_file_get_string(config, "global", "table",
+						   NULL);
+		if (table_name)
+			table_name_len = strlen(table_name) + 1;
 		password = g_key_file_get_string(config, "global", "password",
 						 NULL);
 
@@ -245,16 +256,23 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 	case 'o':
 		output_fn = arg;
 		break;
-	case 'v':
-		chcli_verbose = true;
-		break;
 	case 'S':
 		use_ssl = true;
 		break;
+	case 't':
+		table_name = arg;
+		table_name_len = strlen(arg) + 1;
+		break;
+	case 'v':
+		chcli_verbose = true;
+		break;
 
 	case 1001:			/* --list-cmds */
 		show_cmds();
 		break;
+	case 1002:			/* --create */
+		table_create = true;
+		break;
 
 	case ARGP_KEY_ARG:
 		if (cmd_mode != CHC_NONE)
@@ -298,6 +316,15 @@ static struct st_client *chcli_stc_new(void)
 
 	stc->verbose = chcli_verbose;
 
+	if (!stc_table_open(stc, table_name, table_name_len,
+			    table_create ? CHF_TABLE_NEW : 0)) {
+		fprintf(stderr, "%s:%u: failed to open table\n",
+			host->name,
+			host->port);
+		stc_free(stc);
+		return NULL;
+	}
+
 	return stc;
 }
 
@@ -527,7 +554,10 @@ int main (int argc, char *argv[])
 		fprintf(stderr, "no host specified\n");
 		return 1;
 	}
-
+	if (!table_name || !table_name_len) {
+		fprintf(stderr, "no table name specified\n");
+		return 1;
+	}
 	if (strlen(username) == 0) {
 		fprintf(stderr, "no username specified\n");
 		return 1;
--
To unsubscribe from this list: send the line "unsubscribe hail-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Fedora Clound]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux