mirror of
https://github.com/wassname/ray.git
synced 2026-08-14 12:40:23 +08:00
Merge task table and task log into a single table (#30)
* Merge task table and task log * Fix test in db tests * Address Robert's comments and some better error checking * Add a LOG_FATAL that exits the program
This commit is contained in:
committed by
Philipp Moritz
parent
194bdb1d96
commit
9d1e750e8f
@@ -36,3 +36,24 @@ void object_table_subscribe(
|
||||
init_table_callback(db_handle, object_id, sub_data, retry, done_callback,
|
||||
redis_object_table_subscribe, user_context);
|
||||
}
|
||||
|
||||
void result_table_add(db_handle *db_handle,
|
||||
object_id object_id,
|
||||
task_id task_id_arg,
|
||||
retry_info *retry,
|
||||
result_table_done_callback done_callback,
|
||||
void *user_context) {
|
||||
task_id *task_id_copy = malloc(sizeof(task_id));
|
||||
memcpy(task_id_copy, task_id_arg.id, sizeof(task_id));
|
||||
init_table_callback(db_handle, object_id, task_id_copy, retry, done_callback,
|
||||
redis_result_table_add, user_context);
|
||||
}
|
||||
|
||||
void result_table_lookup(db_handle *db_handle,
|
||||
object_id object_id,
|
||||
retry_info *retry,
|
||||
result_table_lookup_callback done_callback,
|
||||
void *user_context) {
|
||||
init_table_callback(db_handle, object_id, NULL, retry, done_callback,
|
||||
redis_result_table_lookup, user_context);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "common.h"
|
||||
#include "table.h"
|
||||
#include "db.h"
|
||||
#include "task.h"
|
||||
|
||||
/*
|
||||
* ==== Lookup call and callback ====
|
||||
@@ -123,4 +124,55 @@ typedef struct {
|
||||
void *subscribe_context;
|
||||
} object_table_subscribe_data;
|
||||
|
||||
/*
|
||||
* ==== Result table ====
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback called when the add/remove operation for a result table entry
|
||||
* completes. */
|
||||
typedef void (*result_table_done_callback)(object_id object_id,
|
||||
void *user_context);
|
||||
|
||||
/**
|
||||
* Add information about a new object to the object table. This
|
||||
* is immutable information like the ID of the task that
|
||||
* created the object.
|
||||
*
|
||||
* @param db_handle Handle to object_table database.
|
||||
* @param object_id ID of the object to add.
|
||||
* @param task_id ID of the task that creates this object.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Context passed by the caller.
|
||||
* @return Void.
|
||||
*/
|
||||
void result_table_add(db_handle *db_handle,
|
||||
object_id object_id,
|
||||
task_id task_id,
|
||||
retry_info *retry,
|
||||
result_table_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/** Callback called when the result table lookup completes. */
|
||||
typedef void (*result_table_lookup_callback)(object_id object_id,
|
||||
task *task,
|
||||
void *user_context);
|
||||
|
||||
/**
|
||||
* Lookup the task that created an object in the result table.
|
||||
*
|
||||
* @param db_handle Handle to object_table database.
|
||||
* @param object_id ID of the object to lookup.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Context passed by the caller.
|
||||
* @return Void.
|
||||
*/
|
||||
void result_table_lookup(db_handle *db_handle,
|
||||
object_id object_id,
|
||||
retry_info *retry,
|
||||
result_table_lookup_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
#endif /* OBJECT_TABLE_H */
|
||||
|
||||
+296
-84
@@ -11,21 +11,19 @@
|
||||
#include "db.h"
|
||||
#include "object_table.h"
|
||||
#include "task.h"
|
||||
#include "task_log.h"
|
||||
#include "task_table.h"
|
||||
#include "event_loop.h"
|
||||
#include "redis.h"
|
||||
#include "io.h"
|
||||
|
||||
#define LOG_REDIS_ERR(context, M, ...) \
|
||||
fprintf(stderr, "[ERROR] (%s:%d: message: %s) " M "\n", __FILE__, __LINE__, \
|
||||
context->errstr, ##__VA_ARGS__)
|
||||
#define LOG_REDIS_ERR(context, M, ...) \
|
||||
LOG_INFO("Redis error %d %s; %s", context->err, context->errstr, M)
|
||||
|
||||
#define CHECK_REDIS_CONNECT(CONTEXT_TYPE, context, M, ...) \
|
||||
do { \
|
||||
CONTEXT_TYPE *_context = (context); \
|
||||
if (!_context) { \
|
||||
LOG_ERR("could not allocate redis context"); \
|
||||
exit(-1); \
|
||||
LOG_FATAL("could not allocate redis context"); \
|
||||
} \
|
||||
if (_context->err) { \
|
||||
LOG_REDIS_ERR(_context, M, ##__VA_ARGS__); \
|
||||
@@ -123,6 +121,62 @@ void db_attach(db_handle *db, event_loop *loop) {
|
||||
redisAeAttach(loop, db->sub_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal function to allocate a task object and parse a hashmap reply
|
||||
* from Redis into the task object. If the Redis reply is malformed, an empty
|
||||
* task with the given task ID is returned.
|
||||
*
|
||||
* @param id The ID of the task we're looking up. If the reply from Redis is
|
||||
* well-formed, the reply's ID should match this ID. Else, the returned
|
||||
* task will have its ID set to this ID.
|
||||
* @param num_redis_replies The number of keys and values in the Redis hashmap.
|
||||
* @param redis_replies A pointer to the Redis hashmap keys and values.
|
||||
* @return A pointer to the parsed task.
|
||||
*/
|
||||
task *parse_redis_task_table_entry(task_id id,
|
||||
int num_redis_replies,
|
||||
redisReply **redis_replies) {
|
||||
task *task_result;
|
||||
if (num_redis_replies == 0) {
|
||||
/* There was no information about this task. */
|
||||
return NULL;
|
||||
}
|
||||
/* Exit immediately if there weren't 6 fields, one for each key-value pair.
|
||||
* The keys are "node", "state", and "task_spec". */
|
||||
DCHECK(num_redis_replies == 6);
|
||||
/* Parse the task struct's fields. */
|
||||
scheduling_state state = 0;
|
||||
node_id node = NIL_ID;
|
||||
task_spec *spec = NULL;
|
||||
for (int i = 0; i < num_redis_replies; i = i + 2) {
|
||||
char *key = redis_replies[i]->str;
|
||||
redisReply *value = redis_replies[i + 1];
|
||||
if (strcmp(key, "node") == 0) {
|
||||
memcpy(&node, value->str, value->len);
|
||||
} else if (strcmp(key, "state") == 0) {
|
||||
int scanned = sscanf(value->str, "%d", (int *) &state);
|
||||
if (scanned != 1) {
|
||||
LOG_FATAL("Scheduling state for task is malformed");
|
||||
state = 0;
|
||||
}
|
||||
} else if (strcmp(key, "task_spec") == 0) {
|
||||
spec = malloc(value->len);
|
||||
memcpy(spec, value->str, value->len);
|
||||
} else {
|
||||
LOG_FATAL("Found unexpected %s field in task log", key);
|
||||
}
|
||||
}
|
||||
/* Exit immediately if we couldn't parse the task spec. */
|
||||
if (spec == NULL) {
|
||||
LOG_FATAL("Could not parse task spec from task log");
|
||||
}
|
||||
/* Build and return the task. */
|
||||
DCHECK(task_ids_equal(task_spec_id(spec), id));
|
||||
task_result = alloc_task(spec, state, node);
|
||||
free_task_spec(spec);
|
||||
return task_result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ==== object_table callbacks ====
|
||||
*/
|
||||
@@ -133,7 +187,7 @@ void redis_object_table_add_callback(redisAsyncContext *c,
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
|
||||
if (callback_data->done_callback) {
|
||||
task_log_done_callback done_callback = callback_data->done_callback;
|
||||
task_table_done_callback done_callback = callback_data->done_callback;
|
||||
done_callback(callback_data->id, callback_data->user_context);
|
||||
}
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
@@ -142,10 +196,12 @@ void redis_object_table_add_callback(redisAsyncContext *c,
|
||||
void redis_object_table_add(table_callback_data *callback_data) {
|
||||
CHECK(callback_data);
|
||||
db_handle *db = callback_data->db_handle;
|
||||
redisAsyncCommand(db->context, redis_object_table_add_callback,
|
||||
(void *) callback_data->timer_id, "SADD obj:%b %d",
|
||||
&callback_data->id.id[0], UNIQUE_ID_SIZE, db->client_id);
|
||||
if (db->context->err) {
|
||||
object_id id = callback_data->id;
|
||||
int status =
|
||||
redisAsyncCommand(db->context, redis_object_table_add_callback,
|
||||
(void *) callback_data->timer_id, "SADD obj:%b %d",
|
||||
id.id, sizeof(object_id), db->client_id);
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "could not add object_table entry");
|
||||
}
|
||||
}
|
||||
@@ -155,14 +211,117 @@ void redis_object_table_lookup(table_callback_data *callback_data) {
|
||||
db_handle *db = callback_data->db_handle;
|
||||
|
||||
/* Call redis asynchronously */
|
||||
redisAsyncCommand(db->context, redis_object_table_get_entry,
|
||||
(void *) callback_data->timer_id, "SMEMBERS obj:%b",
|
||||
&callback_data->id.id[0], UNIQUE_ID_SIZE);
|
||||
if (db->context->err) {
|
||||
object_id id = callback_data->id;
|
||||
int status = redisAsyncCommand(db->context, redis_object_table_get_entry,
|
||||
(void *) callback_data->timer_id,
|
||||
"SMEMBERS obj:%b", id.id, sizeof(object_id));
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "error in object_table lookup");
|
||||
}
|
||||
}
|
||||
|
||||
void redis_result_table_add_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
redisReply *reply = r;
|
||||
CHECK(reply->type == REDIS_REPLY_STATUS ||
|
||||
reply->type == REDIS_REPLY_INTEGER);
|
||||
if (callback_data->done_callback) {
|
||||
result_table_done_callback done_callback = callback_data->done_callback;
|
||||
done_callback(callback_data->id, callback_data->user_context);
|
||||
}
|
||||
task_id *task_id = callback_data->data;
|
||||
free(task_id);
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
}
|
||||
|
||||
void redis_result_table_add(table_callback_data *callback_data) {
|
||||
CHECK(callback_data);
|
||||
db_handle *db = callback_data->db_handle;
|
||||
object_id id = callback_data->id;
|
||||
task_id *result_task_id = (task_id *) callback_data->data;
|
||||
/* Add the result entry to the result table. */
|
||||
int status = redisAsyncCommand(db->context, redis_result_table_add_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"SET result:%b %b", id.id, sizeof(object_id),
|
||||
(*result_task_id).id, sizeof(task_id));
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "Error in result table add");
|
||||
}
|
||||
}
|
||||
|
||||
void redis_result_table_lookup_task_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
redisReply *reply = r;
|
||||
/* Check that we received a Redis hashmap. */
|
||||
if (reply->type != REDIS_REPLY_ARRAY) {
|
||||
LOG_FATAL("Expected Redis array, received type %d %s", reply->type,
|
||||
reply->str);
|
||||
}
|
||||
/* If the user registered a success callback, construct the task object from
|
||||
* the Redis reply and call the callback. */
|
||||
result_table_lookup_callback done_callback = callback_data->done_callback;
|
||||
task_id *result_task_id = callback_data->data;
|
||||
if (done_callback) {
|
||||
task *task_reply = parse_redis_task_table_entry(
|
||||
*result_task_id, reply->elements, reply->element);
|
||||
done_callback(callback_data->id, task_reply, callback_data->user_context);
|
||||
free_task(task_reply);
|
||||
}
|
||||
free(result_task_id);
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
}
|
||||
|
||||
void redis_result_table_lookup_object_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
redisReply *reply = r;
|
||||
|
||||
if (reply->type == REDIS_REPLY_STRING) {
|
||||
/* If we found the object, get the spec of the task that created it. */
|
||||
DCHECK(reply->len == sizeof(task_id));
|
||||
task_id *result_task_id = malloc(sizeof(task_id));
|
||||
memcpy(result_task_id, reply->str, reply->len);
|
||||
callback_data->data = (void *) result_task_id;
|
||||
int status =
|
||||
redisAsyncCommand(db->context, redis_result_table_lookup_task_callback,
|
||||
(void *) callback_data->timer_id, "HGETALL task:%b",
|
||||
(*result_task_id).id, sizeof(task_id));
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "Could not look up result table entry");
|
||||
}
|
||||
} else if (reply->type == REDIS_REPLY_NIL) {
|
||||
/* The object with the requested ID was not in the table. */
|
||||
LOG_ERR("Object's result not in table.");
|
||||
result_table_lookup_callback done_callback = callback_data->done_callback;
|
||||
if (done_callback) {
|
||||
done_callback(callback_data->id, NULL, callback_data->user_context);
|
||||
}
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
return;
|
||||
} else {
|
||||
LOG_FATAL("expected string or nil, received type %d", reply->type);
|
||||
}
|
||||
}
|
||||
|
||||
void redis_result_table_lookup(table_callback_data *callback_data) {
|
||||
CHECK(callback_data);
|
||||
db_handle *db = callback_data->db_handle;
|
||||
/* First, lookup the ID of the task that created this object. */
|
||||
object_id id = callback_data->id;
|
||||
int status =
|
||||
redisAsyncCommand(db->context, redis_result_table_lookup_object_callback,
|
||||
(void *) callback_data->timer_id, "GET result:%b",
|
||||
id.id, sizeof(object_id));
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "Error in result table lookup");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry from the plasma manager table in redis.
|
||||
*
|
||||
@@ -213,8 +372,7 @@ void redis_object_table_get_entry(redisAsyncContext *c,
|
||||
destroy_timer_callback(callback_data->db_handle->loop, callback_data);
|
||||
free(managers);
|
||||
} else {
|
||||
LOG_ERR("expected integer or string, received type %d", reply->type);
|
||||
exit(-1);
|
||||
LOG_FATAL("expected integer or string, received type %d", reply->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,28 +407,64 @@ void redis_object_table_subscribe(table_callback_data *callback_data) {
|
||||
db_handle *db = callback_data->db_handle;
|
||||
|
||||
/* subscribe to key notification associated to object id */
|
||||
|
||||
redisAsyncCommand(db->sub_context, object_table_redis_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"SUBSCRIBE __keyspace@0__:%b add",
|
||||
(char *) &callback_data->id.id[0], UNIQUE_ID_SIZE);
|
||||
|
||||
if (db->sub_context->err) {
|
||||
object_id id = callback_data->id;
|
||||
int status = redisAsyncCommand(db->sub_context, object_table_redis_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"SUBSCRIBE __keyspace@0__:%b add", id.id,
|
||||
sizeof(object_id));
|
||||
if ((status == REDIS_ERR) || db->sub_context->err) {
|
||||
LOG_REDIS_ERR(db->sub_context,
|
||||
"error in redis_object_table_subscribe_callback");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ==== task_log callbacks ====
|
||||
* ==== task_table callbacks ====
|
||||
*/
|
||||
|
||||
void redis_task_log_publish(table_callback_data *callback_data) {
|
||||
void redis_task_table_get_task_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
redisReply *reply = r;
|
||||
/* Check that we received a Redis hashmap. */
|
||||
if (reply->type != REDIS_REPLY_ARRAY) {
|
||||
LOG_FATAL("Expected Redis array, received type %d %s", reply->type,
|
||||
reply->str);
|
||||
}
|
||||
/* If the user registered a success callback, construct the task object from
|
||||
* the Redis reply and call the callback. */
|
||||
if (callback_data->done_callback) {
|
||||
task_table_get_callback done_callback = callback_data->done_callback;
|
||||
task *task_reply = parse_redis_task_table_entry(
|
||||
callback_data->id, reply->elements, reply->element);
|
||||
done_callback(task_reply, callback_data->user_context);
|
||||
free_task(task_reply);
|
||||
}
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
}
|
||||
|
||||
void redis_task_table_get_task(table_callback_data *callback_data) {
|
||||
CHECK(callback_data);
|
||||
db_handle *db = callback_data->db_handle;
|
||||
task_instance *task_instance = callback_data->data;
|
||||
task_iid task_iid = *task_instance_id(task_instance);
|
||||
node_id node = *task_instance_node(task_instance);
|
||||
int32_t state = *task_instance_state(task_instance);
|
||||
task_id id = callback_data->id;
|
||||
int status =
|
||||
redisAsyncCommand(db->context, redis_task_table_get_task_callback,
|
||||
(void *) callback_data->timer_id, "HGETALL task:%b",
|
||||
id.id, sizeof(task_id));
|
||||
if ((status == REDIS_ERR) || db->sub_context->err) {
|
||||
LOG_REDIS_ERR(db->sub_context, "Could not get task from task table");
|
||||
}
|
||||
}
|
||||
|
||||
void redis_task_table_publish(table_callback_data *callback_data,
|
||||
bool task_added) {
|
||||
db_handle *db = callback_data->db_handle;
|
||||
task *task = callback_data->data;
|
||||
task_id id = task_task_id(task);
|
||||
node_id node = task_node(task);
|
||||
scheduling_state state = task_state(task);
|
||||
task_spec *spec = task_task_spec(task);
|
||||
|
||||
LOG_DEBUG("Called log_publish callback");
|
||||
|
||||
@@ -294,84 +488,98 @@ void redis_task_log_publish(table_callback_data *callback_data) {
|
||||
}
|
||||
|
||||
if (((bool *) callback_data->requests_info)[PUSH_INDEX] == false) {
|
||||
if (*task_instance_state(task_instance) == TASK_STATUS_WAITING) {
|
||||
redisAsyncCommand(db->context, redis_task_log_publish_push_callback,
|
||||
(void *) callback_data->timer_id, "RPUSH tasklog:%b %b",
|
||||
(char *) &task_iid.id[0], UNIQUE_ID_SIZE,
|
||||
(char *) task_instance,
|
||||
task_instance_size(task_instance));
|
||||
/* If the task has already been added to the task table, only update the
|
||||
* scheduling information fields. */
|
||||
int status = REDIS_OK;
|
||||
if (task_added) {
|
||||
status = redisAsyncCommand(
|
||||
db->context, redis_task_table_publish_push_callback,
|
||||
(void *) callback_data->timer_id, "HMSET task:%b state %d node %b",
|
||||
(char *) id.id, sizeof(task_id), state, (char *) node.id,
|
||||
sizeof(node_id));
|
||||
} else {
|
||||
task_update update = {.state = state, .node = node};
|
||||
redisAsyncCommand(db->context, redis_task_log_publish_push_callback,
|
||||
(void *) callback_data->timer_id, "RPUSH tasklog:%b %b",
|
||||
(char *) &task_iid.id[0], UNIQUE_ID_SIZE,
|
||||
(char *) &update, sizeof(update));
|
||||
status = redisAsyncCommand(
|
||||
db->context, redis_task_table_publish_push_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"HMSET task:%b state %d node %b task_spec %b", (char *) id.id,
|
||||
sizeof(task_id), state, (char *) node.id, sizeof(node_id),
|
||||
(char *) spec, task_spec_size(spec));
|
||||
}
|
||||
|
||||
if (db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "error setting task in task_log_add_task");
|
||||
if ((status = REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "error setting task in task_table_add_task");
|
||||
}
|
||||
}
|
||||
|
||||
if (((bool *) callback_data->requests_info)[PUBLISH_INDEX] == false) {
|
||||
redisAsyncCommand(db->context, redis_task_log_publish_publish_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"PUBLISH task_log:%b:%d %b", (char *) &node.id[0],
|
||||
UNIQUE_ID_SIZE, state, (char *) task_instance,
|
||||
task_instance_size(task_instance));
|
||||
int status = redisAsyncCommand(
|
||||
db->context, redis_task_table_publish_publish_callback,
|
||||
(void *) callback_data->timer_id, "PUBLISH task:%b:%d %b",
|
||||
(char *) node.id, sizeof(node_id), state, (char *) task,
|
||||
task_size(task));
|
||||
|
||||
if (db->context->err) {
|
||||
LOG_REDIS_ERR(db->context, "error publishing task in task_log_add_task");
|
||||
if ((status == REDIS_ERR) || db->context->err) {
|
||||
LOG_REDIS_ERR(db->context,
|
||||
"error publishing task in task_table_add_task");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void redis_task_log_publish_push_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
void redis_task_table_add_task(table_callback_data *callback_data) {
|
||||
redis_task_table_publish(callback_data, false);
|
||||
}
|
||||
|
||||
void redis_task_table_update(table_callback_data *callback_data) {
|
||||
redis_task_table_publish(callback_data, true);
|
||||
}
|
||||
|
||||
void redis_task_table_publish_push_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
CHECK(callback_data->requests_info != NULL);
|
||||
((bool *) callback_data->requests_info)[PUSH_INDEX] = true;
|
||||
|
||||
if (((bool *) callback_data->requests_info)[PUBLISH_INDEX] == true) {
|
||||
if (callback_data->done_callback) {
|
||||
task_log_done_callback done_callback = callback_data->done_callback;
|
||||
task_table_done_callback done_callback = callback_data->done_callback;
|
||||
done_callback(callback_data->id, callback_data->user_context);
|
||||
}
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
void redis_task_log_publish_publish_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
void redis_task_table_publish_publish_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
|
||||
CHECK(callback_data->requests_info != NULL);
|
||||
((bool *) callback_data->requests_info)[PUBLISH_INDEX] = true;
|
||||
|
||||
if (((bool *) callback_data->requests_info)[PUSH_INDEX] == true) {
|
||||
if (callback_data->done_callback) {
|
||||
task_log_done_callback done_callback = callback_data->done_callback;
|
||||
task_table_done_callback done_callback = callback_data->done_callback;
|
||||
done_callback(callback_data->id, callback_data->user_context);
|
||||
}
|
||||
destroy_timer_callback(db->loop, callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
void task_log_redis_callback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
void redis_task_table_subscribe_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata) {
|
||||
REDIS_CALLBACK_HEADER(db, callback_data, r)
|
||||
redisReply *reply = r;
|
||||
|
||||
CHECK(reply->type == REDIS_REPLY_ARRAY);
|
||||
/* First entry is message type, second is topic, third is payload. */
|
||||
CHECK(reply->elements > 2);
|
||||
/* If this condition is true, we got the initial message that acknowledged the
|
||||
* subscription. */
|
||||
if (reply->element[2]->str == NULL) {
|
||||
CHECK(reply->elements > 2);
|
||||
/* First entry is message type, then possibly the regex we psubscribed to,
|
||||
* then topic, then payload. */
|
||||
redisReply *payload = reply->element[reply->elements - 1];
|
||||
if (payload->str == NULL) {
|
||||
if (callback_data->done_callback) {
|
||||
task_log_done_callback done_callback = callback_data->done_callback;
|
||||
task_table_done_callback done_callback = callback_data->done_callback;
|
||||
done_callback(callback_data->id, callback_data->user_context);
|
||||
}
|
||||
/* Note that we do not destroy the callback data yet because the
|
||||
@@ -380,32 +588,36 @@ void task_log_redis_callback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
return;
|
||||
}
|
||||
/* Otherwise, parse the task and call the callback. */
|
||||
task_log_subscribe_data *data = callback_data->data;
|
||||
task_table_subscribe_data *data = callback_data->data;
|
||||
|
||||
task_instance *instance = malloc(reply->element[2]->len);
|
||||
memcpy(instance, reply->element[2]->str, reply->element[2]->len);
|
||||
task *task = malloc(payload->len);
|
||||
memcpy(task, payload->str, payload->len);
|
||||
if (data->subscribe_callback) {
|
||||
data->subscribe_callback(instance, data->subscribe_context);
|
||||
data->subscribe_callback(task, data->subscribe_context);
|
||||
}
|
||||
task_instance_free(instance);
|
||||
free_task(task);
|
||||
}
|
||||
|
||||
void redis_task_log_subscribe(table_callback_data *callback_data) {
|
||||
void redis_task_table_subscribe(table_callback_data *callback_data) {
|
||||
db_handle *db = callback_data->db_handle;
|
||||
task_log_subscribe_data *data = callback_data->data;
|
||||
|
||||
if (memcmp(&data->node.id[0], &NIL_ID.id[0], UNIQUE_ID_SIZE) == 0) {
|
||||
redisAsyncCommand(db->sub_context, task_log_redis_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"PSUBSCRIBE task_log:*:%d", data->state_filter);
|
||||
task_table_subscribe_data *data = callback_data->data;
|
||||
int status = REDIS_OK;
|
||||
if (IS_NIL_ID(data->node)) {
|
||||
/* TODO(swang): Implement the state_filter by translating the bitmask into
|
||||
* a Redis key-matching pattern. */
|
||||
status =
|
||||
redisAsyncCommand(db->sub_context, redis_task_table_subscribe_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"PSUBSCRIBE task:*:%d", data->state_filter);
|
||||
} else {
|
||||
redisAsyncCommand(db->sub_context, task_log_redis_callback,
|
||||
(void *) callback_data->timer_id,
|
||||
"SUBSCRIBE task_log:%b:%d", (char *) &data->node.id[0],
|
||||
UNIQUE_ID_SIZE, data->state_filter);
|
||||
node_id node = data->node;
|
||||
status = redisAsyncCommand(
|
||||
db->sub_context, redis_task_table_subscribe_callback,
|
||||
(void *) callback_data->timer_id, "SUBSCRIBE task:%b:%d",
|
||||
(char *) node.id, sizeof(node_id), data->state_filter);
|
||||
}
|
||||
if (db->sub_context->err) {
|
||||
LOG_REDIS_ERR(db->sub_context, "error in task_log_register_callback");
|
||||
if ((status == REDIS_ERR) || db->sub_context->err) {
|
||||
LOG_REDIS_ERR(db->sub_context, "error in task_table_register_callback");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+54
-14
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "db.h"
|
||||
#include "object_table.h"
|
||||
#include "task_log.h"
|
||||
#include "task_table.h"
|
||||
|
||||
#include "hiredis/hiredis.h"
|
||||
#include "hiredis/async.h"
|
||||
@@ -65,7 +65,7 @@ void object_table_lookup_callback(redisAsyncContext *c,
|
||||
void redis_object_table_lookup(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Add an entry to the object table in redis.
|
||||
* Add a location entry to the object table in redis.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
@@ -82,50 +82,90 @@ void redis_object_table_add(table_callback_data *callback_data);
|
||||
*/
|
||||
void redis_object_table_subscribe(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Add a new object to the object table in redis.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_result_table_add(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Lookup the object in the object table in redis. The entry in
|
||||
* the object table contains metadata about the object.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_result_table_lookup(table_callback_data *callback_data);
|
||||
|
||||
/*
|
||||
* ==== Redis task table function =====
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add or update task log entry with new scheduling information.
|
||||
* Get a task table entry, including the task spec and the task's scheduling
|
||||
* information.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_log_publish(table_callback_data *callback_data);
|
||||
void redis_task_table_get_task(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Callback invoked when the replya from the task push command is received.
|
||||
* Add a task table entry with a new task spec and the task's scheduling
|
||||
* information.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_table_add_task(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Update a task table entry with the task's scheduling information.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_table_update(table_callback_data *callback_data);
|
||||
|
||||
/**
|
||||
* Callback invoked when the reply from the task push command is received.
|
||||
*
|
||||
* @param c Redis context.
|
||||
* @param r Reply (not used).
|
||||
* @param privdata Data associated to the callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_log_publish_push_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata);
|
||||
|
||||
void redis_task_table_publish_push_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata);
|
||||
|
||||
/**
|
||||
* Callback invoked when the replya from the task publish command is received.
|
||||
* Callback invoked when the reply from the task publish command is received.
|
||||
*
|
||||
* @param c Redis context.
|
||||
* @param r Reply (not used).
|
||||
* @param privdata Data associated to the callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_log_publish_publish_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata);
|
||||
void redis_task_table_publish_publish_callback(redisAsyncContext *c,
|
||||
void *r,
|
||||
void *privdata);
|
||||
|
||||
/**
|
||||
* Subscribe to updates of the task log.
|
||||
* Subscribe to updates of the task table.
|
||||
*
|
||||
* @param callback_data Data structure containing redis connection and timeout
|
||||
* information.
|
||||
* @return Void.
|
||||
*/
|
||||
void redis_task_log_subscribe(table_callback_data *callback_data);
|
||||
void redis_task_table_subscribe(table_callback_data *callback_data);
|
||||
|
||||
#endif /* REDIS_H */
|
||||
|
||||
@@ -67,9 +67,10 @@ int64_t table_timeout_handler(event_loop *loop,
|
||||
if (callback_data->retry.num_retries == 0) {
|
||||
/* We didn't get a response from the database after exhausting all retries;
|
||||
* let user know, cleanup the state, and remove the timer. */
|
||||
LOG_ERR("Table command with timer ID %ld failed", timer_id);
|
||||
if (callback_data->retry.fail_callback) {
|
||||
callback_data->retry.fail_callback(callback_data->id,
|
||||
callback_data->user_context);
|
||||
callback_data->retry.fail_callback(
|
||||
callback_data->id, callback_data->user_context, callback_data->data);
|
||||
}
|
||||
destroy_table_callback(callback_data);
|
||||
return EVENT_LOOP_TIMER_DONE;
|
||||
|
||||
@@ -12,8 +12,19 @@ typedef struct table_callback_data table_callback_data;
|
||||
typedef void *table_done_callback;
|
||||
|
||||
/* The callback called when the database operation hasn't completed after
|
||||
* the number of retries specified for the operation. */
|
||||
typedef void (*table_fail_callback)(unique_id id, void *user_context);
|
||||
* the number of retries specified for the operation.
|
||||
*
|
||||
* @param id The unique ID that identifies this callback. Examples include an
|
||||
* object ID or task ID.
|
||||
* @param user_context The state context for the callback. This is equivalent
|
||||
* to the user_context field in table_callback_data.
|
||||
* @param user_data A data argument for the callback. This is equivalent to the
|
||||
* data field in table_callback_data. The user is responsible for
|
||||
* freeing user_data.
|
||||
*/
|
||||
typedef void (*table_fail_callback)(unique_id id,
|
||||
void *user_context,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*table_retry_callback)(table_callback_data *callback_data);
|
||||
|
||||
@@ -41,7 +52,9 @@ struct table_callback_data {
|
||||
* before the next retry, and a pointer to the failure callback.
|
||||
*/
|
||||
retry_info retry;
|
||||
/** Pointer to the data that is entered into the table. */
|
||||
/** Pointer to the data that is entered into the table. This can be used to
|
||||
* pass the result of the call to the callback. The user is responsible for
|
||||
* freeing data in both the fail_callback and done_callback. */
|
||||
void *data;
|
||||
/** Pointer to the data used internally to handle multiple database requests.
|
||||
*/
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "task_log.h"
|
||||
#include "redis.h"
|
||||
|
||||
#define NUM_DB_REQUESTS 2
|
||||
|
||||
void task_log_publish(db_handle *db_handle,
|
||||
task_instance *task_instance,
|
||||
retry_info *retry,
|
||||
task_log_done_callback done_callback,
|
||||
void *user_context) {
|
||||
init_table_callback(db_handle, *task_instance_id(task_instance),
|
||||
task_instance, retry, done_callback,
|
||||
redis_task_log_publish, user_context);
|
||||
}
|
||||
|
||||
/* TODO(swang): A corresponding task_log_unsubscribe. */
|
||||
void task_log_subscribe(db_handle *db_handle,
|
||||
node_id node,
|
||||
int32_t state_filter,
|
||||
task_log_subscribe_callback subscribe_callback,
|
||||
void *subscribe_context,
|
||||
retry_info *retry,
|
||||
task_log_done_callback done_callback,
|
||||
void *user_context) {
|
||||
task_log_subscribe_data *sub_data = malloc(sizeof(task_log_subscribe_data));
|
||||
utarray_push_back(db_handle->callback_freelist, &sub_data);
|
||||
sub_data->node = node;
|
||||
sub_data->state_filter = state_filter;
|
||||
sub_data->subscribe_callback = subscribe_callback;
|
||||
sub_data->subscribe_context = subscribe_context;
|
||||
|
||||
init_table_callback(db_handle, node, sub_data, retry, done_callback,
|
||||
redis_task_log_subscribe, user_context);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
#ifndef TASK_LOG_H
|
||||
#define TASK_LOG_H
|
||||
|
||||
#include "db.h"
|
||||
#include "table.h"
|
||||
#include "task.h"
|
||||
|
||||
/**
|
||||
* The task log is a message bus that is used for all communication between
|
||||
* local and global schedulers (and also persisted to the state database).
|
||||
* Here are examples of events that are recorded by the task log:
|
||||
*
|
||||
* 1) local scheduler writes it when submits a task to the global scheduler;
|
||||
* 2) global scheduler reads it to get the task submitted by local schedulers;
|
||||
* 3) global scheduler writes it when assigning the task to a local scheduler;
|
||||
* 4) local scheduler reads it to get its tasks assigned by global scheduler;
|
||||
* 5) local scheduler writes it when a task finishes execution;
|
||||
* 6) global scheduler reads it to get the tasks that have finished; */
|
||||
|
||||
/* Callback called when the task log operation completes. */
|
||||
typedef void (*task_log_done_callback)(task_iid task_iid, void *user_context);
|
||||
|
||||
/*
|
||||
* ==== Publish the task log ====
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add or update a task instance to the task log.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_log_publish(db_handle *db_handle,
|
||||
task_instance *task_instance,
|
||||
retry_info *retry,
|
||||
task_log_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/*
|
||||
* ==== Subscribing to the task log ====
|
||||
*/
|
||||
|
||||
/* Callback for subscribing to the task log. */
|
||||
typedef void (*task_log_subscribe_callback)(task_instance *task_instance,
|
||||
void *user_context);
|
||||
|
||||
/**
|
||||
* Register callback for a certain event.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param subscribe_callback Callback that will be called when the task log is
|
||||
* updated.
|
||||
* @param subscribe_context Context that will be passed into the
|
||||
* subscribe_callback.
|
||||
* @param node Node whose events we want to listen to. If you want to register
|
||||
* to updates from all nodes, set node = NIL_ID.
|
||||
* @param state_filter Flags for events we want to listen to. If you want
|
||||
* to listen to all events, use state_filter = TASK_WAITING |
|
||||
* TASK_SCHEDULED | TASK_RUNNING | TASK_DONE.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_log_subscribe(db_handle *db_handle,
|
||||
node_id node,
|
||||
int32_t state_filter,
|
||||
task_log_subscribe_callback subscribe_callback,
|
||||
void *subscribe_context,
|
||||
retry_info *retry,
|
||||
task_log_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/* Data that is needed to register task log subscribe callbacks with the state
|
||||
* database. */
|
||||
typedef struct {
|
||||
node_id node;
|
||||
int32_t state_filter;
|
||||
task_log_subscribe_callback subscribe_callback;
|
||||
void *subscribe_context;
|
||||
} task_log_subscribe_data;
|
||||
|
||||
#endif /* TASK_LOG_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "task_table.h"
|
||||
#include "redis.h"
|
||||
|
||||
#define NUM_DB_REQUESTS 2
|
||||
|
||||
void task_table_get_task(db_handle *db_handle,
|
||||
task_id task_id,
|
||||
retry_info *retry,
|
||||
task_table_get_callback done_callback,
|
||||
void *user_context) {
|
||||
init_table_callback(db_handle, task_id, NULL, retry, done_callback,
|
||||
redis_task_table_get_task, user_context);
|
||||
}
|
||||
|
||||
void task_table_add_task(db_handle *db_handle,
|
||||
task *task,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context) {
|
||||
init_table_callback(db_handle, task_task_id(task), task, retry, done_callback,
|
||||
redis_task_table_add_task, user_context);
|
||||
}
|
||||
|
||||
void task_table_update(db_handle *db_handle,
|
||||
task *task,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context) {
|
||||
init_table_callback(db_handle, task_task_id(task), task, retry, done_callback,
|
||||
redis_task_table_update, user_context);
|
||||
}
|
||||
|
||||
/* TODO(swang): A corresponding task_table_unsubscribe. */
|
||||
void task_table_subscribe(db_handle *db_handle,
|
||||
node_id node,
|
||||
scheduling_state state_filter,
|
||||
task_table_subscribe_callback subscribe_callback,
|
||||
void *subscribe_context,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context) {
|
||||
task_table_subscribe_data *sub_data =
|
||||
malloc(sizeof(task_table_subscribe_data));
|
||||
utarray_push_back(db_handle->callback_freelist, &sub_data);
|
||||
sub_data->node = node;
|
||||
sub_data->state_filter = state_filter;
|
||||
sub_data->subscribe_callback = subscribe_callback;
|
||||
sub_data->subscribe_context = subscribe_context;
|
||||
|
||||
init_table_callback(db_handle, node, sub_data, retry, done_callback,
|
||||
redis_task_table_subscribe, user_context);
|
||||
}
|
||||
+125
-13
@@ -1,20 +1,132 @@
|
||||
#ifndef TASK_TABLE_H
|
||||
#define TASK_TABLE_H
|
||||
#ifndef task_table_H
|
||||
#define task_table_H
|
||||
|
||||
#include "db.h"
|
||||
#include "table.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Add task to the task table, handle errors here. */
|
||||
status task_table_add_task(db_handle *db, task_spec *task);
|
||||
/**
|
||||
* The task table is a message bus that is used for all communication between
|
||||
* local and global schedulers (and also persisted to the state database).
|
||||
* Here are examples of events that are recorded by the task table:
|
||||
*
|
||||
* 1) local scheduler writes when it submits a task to the global scheduler;
|
||||
* 2) global scheduler reads it to get the task submitted by local schedulers;
|
||||
* 3) global scheduler writes it when assigning the task to a local scheduler;
|
||||
* 4) local scheduler reads it to get its tasks assigned by global scheduler;
|
||||
* 5) local scheduler writes it when a task finishes execution;
|
||||
* 6) global scheduler reads it to get the tasks that have finished; */
|
||||
|
||||
/* Callback for getting an entry from the task table. Task spec will be freed
|
||||
* by the system after the callback */
|
||||
typedef void (*task_table_callback)(task_spec *task, void *context);
|
||||
/* Callback called when a task table write operation completes. */
|
||||
typedef void (*task_table_done_callback)(task_id task_id, void *user_context);
|
||||
|
||||
/* Get specific task from the task table. */
|
||||
status task_table_get_task(db_handle *db,
|
||||
task_id task_id,
|
||||
task_table_callback callback,
|
||||
void *context);
|
||||
/* Callback called when a task table read operation completes. */
|
||||
typedef void (*task_table_get_callback)(task *task, void *user_context);
|
||||
|
||||
#endif /* TASK_TABLE_H */
|
||||
/**
|
||||
* Get a task's entry from the task table.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param task_id The ID of the task we want to look up.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_table_get_task(db_handle *db,
|
||||
task_id task_id,
|
||||
retry_info *retry,
|
||||
task_table_get_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/**
|
||||
* Add a task entry, including task spec and scheduling information, to the
|
||||
* task table. This will overwrite any task already in the task table with the
|
||||
* same task ID.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param task The task entry to add to the table.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_table_add_task(db_handle *db_handle,
|
||||
task *task,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/*
|
||||
* ==== Publish the task table ====
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update a task's scheduling information in the task table. This assumes that
|
||||
* the task spec already exists in the task table entry.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param task The task entry to add to the table. The task spec in the entry is
|
||||
* ignored.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_table_update(db_handle *db_handle,
|
||||
task *task,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/*
|
||||
* ==== Subscribing to the task table ====
|
||||
*/
|
||||
|
||||
/* Callback for subscribing to the task table. */
|
||||
typedef void (*task_table_subscribe_callback)(task *task, void *user_context);
|
||||
|
||||
/**
|
||||
* Register a callback for a task event. An event is any update of a task in
|
||||
* the task table, produced by task_table_add_task or task_table_add_task.
|
||||
* Events include changes to the task's scheduling state or changes to the
|
||||
* task's node location.
|
||||
*
|
||||
* @param db_handle Database handle.
|
||||
* @param subscribe_callback Callback that will be called when the task table is
|
||||
* updated.
|
||||
* @param subscribe_context Context that will be passed into the
|
||||
* subscribe_callback.
|
||||
* @param node Node whose events we want to listen to. If you want to register
|
||||
* to updates from all nodes, set node = NIL_ID.
|
||||
* @param state_filter Flags for events we want to listen to. If you want
|
||||
* to listen to all events, use state_filter = TASK_WAITING |
|
||||
* TASK_SCHEDULED | TASK_RUNNING | TASK_DONE.
|
||||
* @param retry Information about retrying the request to the database.
|
||||
* @param done_callback Function to be called when database returns result.
|
||||
* @param user_context Data that will be passed to done_callback and
|
||||
* fail_callback.
|
||||
* @return Void.
|
||||
*/
|
||||
void task_table_subscribe(db_handle *db_handle,
|
||||
node_id node,
|
||||
scheduling_state state_filter,
|
||||
task_table_subscribe_callback subscribe_callback,
|
||||
void *subscribe_context,
|
||||
retry_info *retry,
|
||||
task_table_done_callback done_callback,
|
||||
void *user_context);
|
||||
|
||||
/* Data that is needed to register task table subscribe callbacks with the state
|
||||
* database. */
|
||||
typedef struct {
|
||||
node_id node;
|
||||
scheduling_state state_filter;
|
||||
task_table_subscribe_callback subscribe_callback;
|
||||
void *subscribe_context;
|
||||
} task_table_subscribe_data;
|
||||
|
||||
#endif /* task_table_H */
|
||||
|
||||
Reference in New Issue
Block a user