Skip to content

Commit

Permalink
Merge pull request #3941 from chu11/issue3811_kvsnsroot
Browse files Browse the repository at this point in the history
kvs: optionally initialize namespace to a root reference
  • Loading branch information
mergify[bot] authored Nov 5, 2021
2 parents 5da24e7 + 21acfef commit 017ac29
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 33 deletions.
8 changes: 5 additions & 3 deletions doc/man1/flux-kvs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ arguments are described below.
COMMANDS
========

**namespace create** [-o owner] *name* [*name* ...]
**namespace create** [-o owner] [-r rootref] *name* [*name* ...]
Create a new kvs namespace. User may specify an alternate userid of a
user that owns the namespace via *-o*. Specifying an alternate owner
would allow a non-instance owner to read/write to a namespace.
User may specify an initial root reference for the namespace via
*-r*.

**namespace remove** *name* [*name...*]
Remove a kvs namespace.
Expand Down Expand Up @@ -171,11 +173,11 @@ COMMANDS
reads version, sends version to node B. Node B waits for version, gets
value.

**getroot** [-N ns] [-s \| -o]
**getroot** [-N ns] [-s \| -o \| -b]
Retrieve the current KVS root, displaying it as an RFC 11 dirref object.
Specify an alternate namespace to retrieve from via *-N*. If *-o* is
specified, display the namespace owner. If *-s* is specified, display
the root sequence number.
the root sequence number. If *-b* is specified, display the root blobref.

**eventlog get** [-N ns] [-W] [-w] [-c count] [-u] *key*
Display the contents of an RFC 18 KVS eventlog referred to by *key*.
Expand Down
13 changes: 13 additions & 0 deletions doc/man3/flux_kvs_namespace_create.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ SYNOPSIS
uint32_t owner,
int flags);

::

flux_future_t *flux_kvs_namespace_create_with (flux_t *h,
const char *namespace,
const char *rootref,
uint32_t owner,
int flags);

::

flux_future_t *flux_kvs_namespace_remove (flux_t *h,
Expand All @@ -32,6 +40,11 @@ other KVS namespaces. An owner of the namespace other than the
instance owner can be chosen by setting *owner*. Otherwise, *owner*
can be set to FLUX_USERID_UNKNOWN.

``flux_kvs_namespace_create_with()`` is identical to
``flux_kvs_namespace_create()`` but will initialize the namespace to
the specified *rootref*. This may be useful in several circumstances,
such as initializing a namespace to an earlier checkpoint.

``flux_kvs_namespace_remove()`` removes a KVS namespace.


Expand Down
26 changes: 23 additions & 3 deletions src/cmd/flux-kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ static struct optparse_option getroot_opts[] = {
{ .name = "owner", .key = 'o', .has_arg = 0,
.usage = "Show owner",
},
{ .name = "blobref", .key = 'b', .has_arg = 0,
.usage = "Show blobref",
},
OPTPARSE_TABLE_END
};

Expand Down Expand Up @@ -355,7 +358,7 @@ static struct optparse_subcommand subcommands[] = {
namespace_opt
},
{ "getroot",
"[-N ns] [-s|-o]",
"[-N ns] [-s|-o|-b]",
"Get KVS root treeobj",
cmd_getroot,
0,
Expand Down Expand Up @@ -436,6 +439,7 @@ int cmd_namespace_create (optparse_t *p, int argc, char **argv)
int optindex, i;
uint32_t owner = FLUX_USERID_UNKNOWN;
const char *str;
const char *rootref;

optindex = optparse_option_index (p);
if ((optindex - argc) == 0) {
Expand All @@ -450,13 +454,19 @@ int cmd_namespace_create (optparse_t *p, int argc, char **argv)
log_msg_exit ("--owner requires an unsigned integer argument");
}

rootref = optparse_get_str (p, "rootref", NULL);

if (!(h = flux_open (NULL, 0)))
log_err_exit ("flux_open");

for (i = optindex; i < argc; i++) {
const char *name = argv[i];
int flags = 0;
if (!(f = flux_kvs_namespace_create (h, name, owner, flags)))
if (rootref)
f = flux_kvs_namespace_create_with (h, name, rootref, owner, flags);
else
f = flux_kvs_namespace_create (h, name, owner, flags);
if (!f)
log_err_exit ("%s", name);
if (flux_future_get (f, NULL) < 0)
log_msg_exit ("%s: %s", name, future_strerror (f, errno));
Expand Down Expand Up @@ -545,12 +555,15 @@ static struct optparse_option namespace_create_opts[] = {
{ .name = "owner", .key = 'o', .has_arg = 1,
.usage = "Specify alternate namespace owner via userid",
},
{ .name = "rootref", .key = 'r', .has_arg = 1,
.usage = "Initialize namespace with specific root reference",
},
OPTPARSE_TABLE_END
};

static struct optparse_subcommand namespace_subcommands[] = {
{ "create",
"name [name...]",
"[-o owner] [-r rootref] name [name...]",
"Create a KVS namespace",
cmd_namespace_create,
0,
Expand Down Expand Up @@ -1741,6 +1754,13 @@ void getroot_continuation (flux_future_t *f, void *arg)
log_err_exit ("flux_kvs_getroot_get_sequence");
printf ("%d\n", sequence);
}
else if (optparse_hasopt (p, "blobref")) {
const char *blobref;

if (flux_kvs_getroot_get_blobref (f, &blobref) < 0)
log_err_exit ("flux_kvs_getroot_get_blobref");
printf ("%s\n", blobref);
}
else {
const char *treeobj;

Expand Down
51 changes: 50 additions & 1 deletion src/common/libkvs/kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,69 @@
#include <jansson.h>
#include <flux/core.h>

#include "src/common/libutil/blobref.h"

#include "treeobj.h"
#include "kvs_util_private.h"

flux_future_t *flux_kvs_namespace_create (flux_t *h, const char *ns,
uint32_t owner, int flags)
{
flux_future_t *rv = NULL;
const char *hash_name;
json_t *rootdir = NULL;
char rootref[BLOBREF_MAX_STRING_SIZE];
void *data = NULL;
int len;

if (!ns || flags) {
errno = EINVAL;
return NULL;
}

if (!(hash_name = flux_attr_get (h, "content.hash")))
goto cleanup;

if (!(rootdir = treeobj_create_dir ()))
goto cleanup;

if (!(data = treeobj_encode (rootdir)))
goto cleanup;
len = strlen (data);

/* N.B. blobref of empty treeobj dir guaranteed to be in content store
* b/c that is how the primary KVS is initialized.
*/
if (blobref_hash (hash_name, data, len, rootref, sizeof (rootref)) < 0)
goto cleanup;

/* N.B. owner cast to int */
rv = flux_rpc_pack (h, "kvs.namespace-create", 0, 0,
"{ s:s s:s s:i s:i }",
"namespace", ns,
"rootref", rootref,
"owner", owner,
"flags", flags);
cleanup:
json_decref (rootdir);
free (data);
return rv;
}

flux_future_t *flux_kvs_namespace_create_with (flux_t *h, const char *ns,
const char *rootref,
uint32_t owner, int flags)
{
if (!ns || !rootref || flags) {
errno = EINVAL;
return NULL;
}

/* N.B. owner cast to int */
return flux_rpc_pack (h, "kvs.namespace-create", 0, 0,
"{ s:s s:i s:i }",
"{ s:s s:s s:i s:i }",
"namespace", ns,
"rootref", rootref,
"owner", owner,
"flags", flags);
}
Expand Down
3 changes: 3 additions & 0 deletions src/common/libkvs/kvs.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ enum kvs_op {
*/
flux_future_t *flux_kvs_namespace_create (flux_t *h, const char *ns,
uint32_t owner, int flags);
flux_future_t *flux_kvs_namespace_create_with (flux_t *h, const char *ns,
const char *rootref,
uint32_t owner, int flags);
flux_future_t *flux_kvs_namespace_remove (flux_t *h, const char *ns);

/* Synchronization:
Expand Down
5 changes: 5 additions & 0 deletions src/common/libkvs/test/kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ void errors (void)
ok (flux_kvs_namespace_create (NULL, NULL, 0, 5) == NULL && errno == EINVAL,
"flux_kvs_namespace_create fails on bad input");

errno = 0;
ok (flux_kvs_namespace_create_with (NULL, NULL, NULL, 0, 5) == NULL
&& errno == EINVAL,
"flux_kvs_namespace_create_with fails on bad input");

errno = 0;
ok (flux_kvs_namespace_remove (NULL, NULL) == NULL && errno == EINVAL,
"flux_kvs_namespace_remove fails on bad input");
Expand Down
33 changes: 7 additions & 26 deletions src/modules/kvs/kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2230,15 +2230,12 @@ static void stats_clear_request_cb (flux_t *h, flux_msg_handler_t *mh,
}

static int namespace_create (struct kvs_ctx *ctx, const char *ns,
uint32_t owner, int flags, const char **errmsg)
const char *rootref, uint32_t owner,
int flags, const char **errmsg)
{
struct kvsroot *root;
json_t *rootdir = NULL;
char ref[BLOBREF_MAX_STRING_SIZE];
void *data = NULL;
flux_msg_t *msg = NULL;
char *topic = NULL;
int len;
int rv = -1;

/* If namespace already exists, return EEXIST. Doesn't matter if
Expand All @@ -2262,23 +2259,7 @@ static int namespace_create (struct kvs_ctx *ctx, const char *ns,
return -1;
}

if (!(rootdir = treeobj_create_dir ())) {
flux_log_error (ctx->h, "%s: treeobj_create_dir", __FUNCTION__);
goto cleanup;
}

if (!(data = treeobj_encode (rootdir))) {
flux_log_error (ctx->h, "%s: treeobj_encode", __FUNCTION__);
goto cleanup;
}
len = strlen (data);

if (blobref_hash (ctx->hash_name, data, len, ref, sizeof (ref)) < 0) {
flux_log_error (ctx->h, "%s: blobref_hash", __FUNCTION__);
goto cleanup;
}

setroot (ctx, root, ref, 0);
setroot (ctx, root, rootref, 0);

if (event_subscribe (ctx, ns) < 0) {
flux_log_error (ctx->h, "%s: event_subscribe", __FUNCTION__);
Expand Down Expand Up @@ -2312,8 +2293,6 @@ static int namespace_create (struct kvs_ctx *ctx, const char *ns,
cleanup:
if (rv < 0)
kvsroot_mgr_remove_root (ctx->krm, ns);
free (data);
json_decref (rootdir);
free (topic);
flux_msg_destroy (msg);
return rv;
Expand All @@ -2325,14 +2304,16 @@ static void namespace_create_request_cb (flux_t *h, flux_msg_handler_t *mh,
struct kvs_ctx *ctx = arg;
const char *errmsg = NULL;
const char *ns;
const char *rootref;
uint32_t owner;
int flags;

assert (ctx->rank == 0);

/* N.B. owner read into uint32_t */
if (flux_request_unpack (msg, NULL, "{ s:s s:i s:i }",
if (flux_request_unpack (msg, NULL, "{ s:s s:s s:i s:i }",
"namespace", &ns,
"rootref", &rootref,
"owner", &owner,
"flags", &flags) < 0) {
flux_log_error (h, "%s: flux_request_unpack", __FUNCTION__);
Expand All @@ -2342,7 +2323,7 @@ static void namespace_create_request_cb (flux_t *h, flux_msg_handler_t *mh,
if (owner == FLUX_USERID_UNKNOWN)
owner = getuid ();

if (namespace_create (ctx, ns, owner, flags, &errmsg) < 0)
if (namespace_create (ctx, ns, rootref, owner, flags, &errmsg) < 0)
goto error;

if (flux_respond (h, msg, NULL) < 0)
Expand Down
7 changes: 7 additions & 0 deletions t/t1000-kvs.t
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,13 @@ test_expect_success 'flux kvs getroot --owner returns instance owner' '
test $OWNER -eq $(id -u)
'

test_expect_success 'flux kvs getroot --blobref returns changing blobrefs' '
BLOBREF1=$(flux kvs getroot --blobref) &&
flux kvs put test.c=barf &&
BLOBREF2=$(flux kvs getroot --blobref) &&
test $BLOBREF1 != $BLOBREF2
'

test_expect_success 'flux kvs getroot works on alt namespace' '
flux kvs namespace create testns1 &&
SEQ=$(flux kvs getroot --namespace=testns1 --sequence) &&
Expand Down
34 changes: 34 additions & 0 deletions t/t1004-kvs-namespace.t
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ NAMESPACETEST=namespacetest
NAMESPACETMP=namespacetmp
NAMESPACERANK1=namespacerank1
NAMESPACEORDER=namespaceorder
NAMESPACEROOTREF=namespacerootref

namespace_create_loop() {
i=0
Expand Down Expand Up @@ -339,6 +340,39 @@ test_expect_success 'kvs: put - namespace specified in command line overrides en
test_kvs_key_namespace $NAMESPACEORDER-2 $DIR.puttest 5
'
#
# Namespace rootref initialization
#
test_expect_success HAVE_JQ 'kvs: namespace rootref setup' '
flux kvs namespace create $NAMESPACEROOTREF-1 &&
flux kvs put --namespace=$NAMESPACEROOTREF-1 $DIR.rootreftest=foobar &&
test_kvs_key_namespace $NAMESPACEROOTREF-1 $DIR.rootreftest foobar &&
flux kvs getroot --blobref --namespace=$NAMESPACEROOTREF-1 > rootref1
'
test_expect_success HAVE_JQ 'kvs: namespace create with init rootref' '
flux kvs namespace create --rootref=$(cat rootref1) $NAMESPACEROOTREF-2 &&
test_kvs_key_namespace $NAMESPACEROOTREF-1 $DIR.rootreftest foobar
'
test_expect_success HAVE_JQ 'kvs: namespaces dont clobber each other' '
flux kvs put --namespace=$NAMESPACEROOTREF-1 $DIR.val=42 &&
flux kvs put --namespace=$NAMESPACEROOTREF-2 $DIR.val=43 &&
test_kvs_key_namespace $NAMESPACEROOTREF-1 $DIR.val 42 &&
test_kvs_key_namespace $NAMESPACEROOTREF-2 $DIR.val 43
'
BADROOTREF="sha1-0123456789abcdef0123456789abcdef01234567"
test_expect_success HAVE_JQ 'kvs: namespace create can take bad blobref' '
flux kvs namespace create --rootref=$BADROOTREF $NAMESPACEROOTREF-3 &&
flux kvs get --namespace=$NAMESPACEROOTREF-3 --treeobj .
'
test_expect_success HAVE_JQ 'kvs: namespace with bad rootref fails otherwise' '
test_must_fail flux kvs ls --namespace=$NAMESPACEROOTREF-3 .
'
#
# Namespace corner case tests
#
Expand Down

0 comments on commit 017ac29

Please sign in to comment.