Make xray object table credis-managed and hence flushable. (#2338)

* monitor.py: issue flushes to data shard

* ResultTableAdd & ObjectTableAdd: add credis-managed versions

* Fix return codes

* Credis-manage xray object table & associated ray.table_append cmd

* Fix incorrect return code from TableAppend_DoWrite()

* Revert "ResultTableAdd & ObjectTableAdd: add credis-managed versions"

This reverts commit 628c2ea190df4c861dda0c284fab7ca6faa1ea24.

* Address comments

* Lint: fix indent

* Address comment
This commit is contained in:
Zongheng Yang
2018-07-03 17:32:44 -07:00
committed by Philipp Moritz
parent f21d783e6d
commit ba28dddf6f
6 changed files with 158 additions and 76 deletions
+5
View File
@@ -50,6 +50,11 @@ class RedisChainModule {
// Runs "node_func" on every node in the chain; after the tail node has run it
// too, finalizes the mutation by running "tail_func".
//
// If node_func() returns non-zero, it is treated as an error and the entire
// update will terminate early, without running subsequent node_func() and the
// final tail_func().
//
// TODO(zongheng): currently only supports 1-node chain.
int ChainReplicate(RedisModuleCtx *ctx,
RedisModuleString **argv,
+90 -53
View File
@@ -654,6 +654,75 @@ int ChainTableAdd_RedisCommand(RedisModuleCtx *ctx,
}
#endif
int TableAppend_DoWrite(RedisModuleCtx *ctx,
RedisModuleString **argv,
int argc,
RedisModuleString **mutated_key_str) {
if (argc < 5 || argc > 6) {
return RedisModule_WrongArity(ctx);
}
RedisModuleString *prefix_str = argv[1];
RedisModuleString *id = argv[3];
RedisModuleString *data = argv[4];
RedisModuleString *index_str = nullptr;
if (argc == 6) {
index_str = argv[5];
}
// Set the keys in the table.
RedisModuleKey *key =
OpenPrefixedKey(ctx, prefix_str, id, REDISMODULE_READ | REDISMODULE_WRITE,
mutated_key_str);
// Determine the index at which the data should be appended. If no index is
// requested, then is the current length of the log.
size_t index = RedisModule_ValueLength(key);
if (index_str != nullptr) {
// Parse the requested index.
long long requested_index;
RAY_CHECK(RedisModule_StringToLongLong(index_str, &requested_index) ==
REDISMODULE_OK);
RAY_CHECK(requested_index >= 0);
index = static_cast<size_t>(requested_index);
}
// Only perform the append if the requested index matches the current length
// of the log, or if no index was requested.
if (index == RedisModule_ValueLength(key)) {
// The requested index matches the current length of the log or no index
// was requested. Perform the append.
int flags = REDISMODULE_ZADD_NX;
RedisModule_ZsetAdd(key, index, data, &flags);
// Check that we actually add a new entry during the append. This is only
// necessary since we implement the log with a sorted set, so all entries
// must be unique, or else we will have gaps in the log.
RAY_CHECK(flags == REDISMODULE_ZADD_ADDED) << "Appended a duplicate entry";
return REDISMODULE_OK;
} else {
// The requested index did not match the current length of the log. Return
// an error message as a string.
static const char *reply = "ERR entry exists";
RedisModule_ReplyWithStringBuffer(ctx, reply, strlen(reply));
return REDISMODULE_ERR;
}
}
int TableAppend_DoPublish(RedisModuleCtx *ctx,
RedisModuleString **argv,
int /*argc*/) {
RedisModuleString *pubsub_channel_str = argv[2];
RedisModuleString *id = argv[3];
RedisModuleString *data = argv[4];
// Publish a message on the requested pubsub channel if necessary.
TablePubsub pubsub_channel = ParseTablePubsub(pubsub_channel_str);
if (pubsub_channel != TablePubsub::NO_PUBLISH) {
// All other pubsub channels write the data back directly onto the
// channel.
return PublishTableAdd(ctx, pubsub_channel_str, id, data);
} else {
return RedisModule_ReplyWithSimpleString(ctx, "OK");
}
}
/// Append an entry to the log stored at a key. Publishes a notification about
/// the update to all subscribers, if a pubsub channel is provided.
///
@@ -678,62 +747,25 @@ int TableAppend_RedisCommand(RedisModuleCtx *ctx,
RedisModuleString **argv,
int argc) {
RedisModule_AutoMemory(ctx);
if (argc < 5 || argc > 6) {
return RedisModule_WrongArity(ctx);
}
RedisModuleString *prefix_str = argv[1];
RedisModuleString *pubsub_channel_str = argv[2];
RedisModuleString *id = argv[3];
RedisModuleString *data = argv[4];
RedisModuleString *index_str = nullptr;
if (argc == 6) {
index_str = argv[5];
}
// Set the keys in the table.
RedisModuleKey *key = OpenPrefixedKey(ctx, prefix_str, id,
REDISMODULE_READ | REDISMODULE_WRITE);
// Determine the index at which the data should be appended. If no index is
// requested, then is the current length of the log.
size_t index = RedisModule_ValueLength(key);
if (index_str != nullptr) {
// Parse the requested index.
long long requested_index;
RAY_CHECK(RedisModule_StringToLongLong(index_str, &requested_index) ==
REDISMODULE_OK);
RAY_CHECK(requested_index >= 0);
index = static_cast<size_t>(requested_index);
}
// Only perform the append if the requested index matches the current length
// of the log, or if no index was requested.
if (index == RedisModule_ValueLength(key)) {
// The requested index matches the current length of the log or no index
// was requested. Perform the append.
int flags = REDISMODULE_ZADD_NX;
RedisModule_ZsetAdd(key, index, data, &flags);
// Check that we actually add a new entry during the append. This is only
// necessary since we implement the log with a sorted set, so all entries
// must be unique, or else we will have gaps in the log.
RAY_CHECK(flags == REDISMODULE_ZADD_ADDED) << "Appended a duplicate entry";
// Publish a message on the requested pubsub channel if necessary.
TablePubsub pubsub_channel = ParseTablePubsub(pubsub_channel_str);
if (pubsub_channel != TablePubsub::NO_PUBLISH) {
// All other pubsub channels write the data back directly onto the
// channel.
return PublishTableAdd(ctx, pubsub_channel_str, id, data);
} else {
return RedisModule_ReplyWithSimpleString(ctx, "OK");
}
} else {
// The requested index did not match the current length of the log. Return
// an error message as a string.
const char *reply = "ERR entry exists";
return RedisModule_ReplyWithStringBuffer(ctx, reply, strlen(reply));
const int status = TableAppend_DoWrite(ctx, argv, argc,
/*mutated_key_str=*/nullptr);
if (status) {
return status;
}
return TableAppend_DoPublish(ctx, argv, argc);
}
#if RAY_USE_NEW_GCS
int ChainTableAppend_RedisCommand(RedisModuleCtx *ctx,
RedisModuleString **argv,
int argc) {
RedisModule_AutoMemory(ctx);
return module.ChainReplicate(ctx, argv, argc,
/*node_func=*/TableAppend_DoWrite,
/*tail_func=*/TableAppend_DoPublish);
}
#endif
/// A helper function to create and finish a GcsTableEntry, based on the
/// current value or values at the given key.
void TableEntryToFlatbuf(RedisModuleKey *table_key,
@@ -1833,6 +1865,11 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx,
0, 0) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
if (RedisModule_CreateCommand(ctx, "ray.chain.table_append",
ChainTableAppend_RedisCommand, "write pubsub",
0, 0, 0) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
#endif
return REDISMODULE_OK;