myxce/src/lib/request.c
2025-11-03 18:19:59 +08:00

931 lines
22 KiB
C

#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "mylock.h"
#include "netio.h"
#include "request.h"
#include "typemap.h"
#include "utils.h"
#include "xce/types.h"
ioctx_t* ioctx_alloc(endpoint_t* ep,
xce_peerinfo_t* peer)
{
ioctx_t* ctx;
ctx = (ioctx_t*)calloc(1, sizeof(*ctx));
if (ctx == NULL) {
errno = -ENOMEM;
return NULL;
}
ctx->ep = endpoint_ref(ep);
ctx->from = peer;
ctx->nrefs++;
return ctx;
}
int ioctx_ref(ioctx_t* ctx)
{
int old = ctx->nrefs;
ctx->nrefs++;
return old;
}
static void ioctx_kill(ioctx_t* ctx,
int free_ctx)
{
if (ctx == NULL) {
return;
}
endpoint_deref(ctx->ep);
free_packet(&(ctx->pkt));
capn_free(&(ctx->c));
if (free_ctx) {
free(ctx);
}
}
void ioctx_deref(ioctx_t* ctx,
int free_ctx)
{
if (ctx == NULL) {
return;
}
if (ctx->nrefs == 0) {
WARN("Something wrong. Have you forgotten to call ioctx_ref()?");
return;
}
ctx->nrefs--;
if (ctx->nrefs == 0) {
ioctx_kill(ctx, free_ctx);
}
}
int ioctx_encode(ioctx_t* ctx,
xce_request_t* req)
{
struct capn_segment* cs;
Request_ptr rp;
int rc;
capn_init_malloc(&(ctx->c));
cs = capn_root(&(ctx->c)).seg;
encode_Request(cs, &(ctx->rq), req);
cs = capn_root(&(ctx->c)).seg;
rp = new_Request(cs);
write_Request(&(ctx->rq), rp);
capn_setp(capn_root(&(ctx->c)), 0, rp.p);
ctx->pkt.sz = capn_size(&(ctx->c));
rc = alloc_packet(&(ctx->pkt));
if (rc < 0) {
return rc;
}
capn_write_mem(&(ctx->c),
(uint8_t*)ctx->pkt.data,
ctx->pkt.sz, 0);
return 0;
}
int ioctx_decode(ioctx_t* ctx,
xce_request_t* req)
{
Request_ptr rp;
capn_init_mem(&(ctx->c), (const uint8_t*)ctx->pkt.data,
ctx->pkt.sz, 0);
rp.p = capn_getp(capn_root(&(ctx->c)), 0, 1);
read_Request(&(ctx->rq), rp);
decode_Request(req, &(ctx->rq));
return 0;
}
int ioctx_flush(ioctx_t* ctx, int fd)
{
int rc;
rc = write_packet(fd, &(ctx->pkt));
return rc;
}
void init_reply_by_req(xce_reply_t* reply,
xce_request_t* req)
{
reply->seq = req->seq;
reply->opcode = req->opcode;
}
int xce_request(ioctx_t* ctx,
xce_request_t* req)
{
int rc;
req->seq = endpoint_getseq(ctx->ep);
req->from = ctx->from;
rc = ioctx_encode(ctx, req);
if (rc < 0) {
return rc;
}
endpoint_enq(ctx->ep, &(ctx->link));
return 0;
}
int xce_reply_with_ctx(ioctx_t* ctx,
xce_peerinfo_t* from,
xce_reply_t* reply)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_reply,
.body_which = Request_body_replymsg,
};
/* clang-format on */
int rc;
TRACE("%s seq %lu opcode %d status %d data which %d",
__func__, reply->seq, reply->opcode,
reply->status, reply->data_which);
request.from = from;
request.body.replymsg = reply;
request.seq = endpoint_getseq(ctx->ep);
rc = ioctx_encode(ctx, &request);
if (rc < 0) {
return rc;
}
endpoint_enq(ctx->ep, &(ctx->link));
return 0;
}
int xce_reply(endpoint_t* ep,
xce_peerinfo_t* from,
xce_reply_t* reply)
{
ioctx_t* ctx;
ctx = ioctx_alloc(ep, from);
if (ctx == NULL) {
return -ENOMEM;
}
return xce_reply_with_ctx(ctx, from, reply);
}
int xce_nop_req(ioctx_t* ctx)
{
xce_request_t request = {
.opcode = OPCode_nop,
.body_which = Request_body_nomsg
};
if (ctx == NULL) {
return -EINVAL;
}
return xce_request(ctx, &request);
}
int xce_hello_req(ioctx_t* ctx,
char* msg)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_hello,
.body_which = Request_body_hellomsg,
.body = {
.hellomsg = msg
}
};
/* clang-format on */
if ((ctx == NULL) || (msg == NULL)) {
return -EINVAL;
}
return xce_request(ctx, &request);
}
int xce_join_req(ioctx_t* ctx,
int role,
hostattrs_t* attrs)
{
/* clang-format off */
xce_joindata_t joinmsg = {
.role = role
};
xce_request_t request = {
.opcode = OPCode_join,
.body_which = Request_body_joinmsg,
.body = {
.joinmsg = &joinmsg
}
};
if ((role != HostRole_client) &&
(role != HostRole_worker) &&
(role != HostRole_scheduler)) {
return -EINVAL;
}
/* clang-format on */
if (role == HostRole_worker) {
if (attrs == NULL) {
return -EINVAL;
}
joinmsg.data_which = JoinData_data_attrs;
joinmsg.data.attrs = attrs;
}
return xce_request(ctx, &request);
}
int xce_shutdown_req(ioctx_t* ctx)
{
int rc;
dataq_t* outq;
xce_request_t request = {
.opcode = OPCode_shutdown,
.body_which = Request_body_nomsg
};
if (ctx == NULL) {
return -EINVAL;
}
rc = xce_request(ctx, &request);
if (rc < 0) {
return rc;
}
outq = &(ctx->ep->outq);
while (!DATAQ_EMPTY(outq)) {
sleep(1);
}
return 0;
}
int xce_pushconfig_req(endpoint_t* ep,
xce_peerinfo_t* from,
xce_configdata_t* config)
{
int rc = 0;
xce_request_t request = {
.opcode = OPCode_push,
.body_which = Request_body_configpushmsg
};
ioctx_t* ctx = NULL;
if ((ep == NULL) || (config == NULL)) {
return -EINVAL;
}
ctx = ioctx_alloc(ep, from);
if (ctx == NULL) {
return -ENOMEM;
}
request.body.configpushmsg = config;
rc = xce_request(ctx, &request);
return rc;
}
static int xce_push_req(endpoint_t* ep,
xce_peerinfo_t* from,
xce_data_t* data)
{
int rc = 0;
ioctx_t* ctx = NULL;
xce_request_t request = {
.opcode = OPCode_push,
.body_which = Request_body_pushmsg
};
if ((ep == NULL) || (from == NULL) || (data == NULL)) {
return -EINVAL;
}
ctx = ioctx_alloc(ep, from);
if (ctx == NULL) {
return -ENOMEM;
}
request.body.pushmsg = data;
rc = xce_request(ctx, &request);
return rc;
}
int xce_push_data_req(endpoint_t* ep,
xce_peerinfo_t* from,
xce_data_t* data,
xce_check_fn_t checkf,
void* checkarg,
int pktlimit)
{
int nrows = 0;
int pos = 0;
int rc = 0;
xce_data_t data1;
int checkstatus = 0;
if ((ep == NULL) || (from == NULL) || (data == NULL)) {
return -EINVAL;
}
data1.table = data->table;
switch (data->table) {
case Data_data_schedjobs:
nrows = data->data.jobs->n_total;
data1.data.jobs = (xce_jobs_data_t*)calloc(1, sizeof(xce_jobs_data_t));
if (data1.data.jobs == NULL) {
rc = -ENOMEM;
}
break;
case Data_data_schedworkers:
nrows = data->data.workers->n_total;
data1.data.workers = (xce_workers_data_t*)calloc(1, sizeof(xce_workers_data_t));
if (data1.data.workers == NULL) {
rc = -ENOMEM;
}
break;
default:
rc = -EINVAL;
break;
}
if (rc < 0) {
return rc;
}
if (pktlimit <= 0) {
pktlimit = nrows;
}
do {
int nc = nrows - pos;
if (nc > pktlimit) {
nc = pktlimit;
}
if (checkf != NULL) {
checkstatus = (*checkf)(checkarg);
if (checkstatus < 0) {
nc = 0;
}
}
switch (data->table) {
case Data_data_schedjobs:
data1.data.jobs->n_total = data->data.jobs->n_total;
data1.data.jobs->pos = pos;
data1.data.jobs->count = nc;
if (nc == 0) {
data1.data.jobs->jobs = NULL;
} else {
data1.data.jobs->jobs = &(data->data.jobs->jobs[pos]);
}
break;
case Data_data_schedworkers:
data1.data.workers->n_total = data->data.workers->n_total;
data1.data.workers->pos = pos;
data1.data.workers->count = nc;
if (nc == 0) {
data1.data.workers->workers = NULL;
} else {
data1.data.workers->workers = &(data->data.workers->workers[pos]);
}
break;
default:
break;
}
rc = xce_push_req(ep, from, &data1);
if (rc < 0) {
break;
}
pos += nc;
} while ((pos < nrows) && (checkstatus >= 0));
switch (data->table) {
case Data_data_schedjobs:
FREEUP(data1.data.jobs);
break;
case Data_data_schedworkers:
FREEUP(data1.data.workers);
break;
default:
break;
}
return rc;
}
int xce_get_req(ioctx_t* ctx,
xce_get_t* get)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_get,
.body_which = Request_body_getmsg,
.body = {
.getmsg = get
}
};
/* clang-format on */
return xce_request(ctx, &request);
}
int xce_reply_get(endpoint_t* ep,
xce_peerinfo_t* from,
xce_reply_t* reply,
xce_check_fn_t checkf,
void* checkarg,
int pktlimit)
{
int rc = 0;
int nrows = 0;
int pos = 0;
/* clang-format off */
xce_data_t getdata = {
.table = reply->data.getdata->table
};
xce_reply_t reply1 = {
.seq = reply->seq,
.opcode = reply->opcode,
.status = reply->status,
.data_which = reply->data_which,
.data = {
.getdata = &getdata
}
};
/* clang-format on */
int checkstatus = 0;
xce_data_t* data = reply->data.getdata;
if ((ep == NULL) || (from == NULL) || (reply == NULL)) {
return -EINVAL;
}
switch (getdata.table) {
case Data_data_schedjobs:
case Data_data_jobs:
nrows = data->data.jobs->n_total;
getdata.data.jobs = (xce_jobs_data_t*)calloc(1, sizeof(xce_jobs_data_t));
break;
case Data_data_schedworkers:
case Data_data_workers:
nrows = data->data.workers->n_total;
getdata.data.workers = (xce_workers_data_t*)calloc(1, sizeof(xce_workers_data_t));
break;
case Data_data_resources:
nrows = data->data.resources->n_total;
getdata.data.resources = (xce_resource_data_t*)calloc(1, sizeof(xce_resource_data_t));
break;
case Data_data_resvals:
nrows = data->data.resvals->n_total;
getdata.data.resvals = (xce_resval_data_t*)calloc(1, sizeof(xce_resval_data_t));
break;
default:
rc = -EINVAL;
break;
}
if (rc < 0) {
/* FIXME we need to reply no data */
return rc;
}
if (pktlimit <= 0) {
pktlimit = nrows;
}
do {
int nc = nrows - pos;
if (nc > pktlimit) {
nc = pktlimit;
}
if (checkf != NULL) {
checkstatus = (*checkf)(checkarg);
if (checkstatus < 0) {
nc = 0;
}
}
switch (getdata.table) {
case Data_data_schedjobs:
case Data_data_jobs:
getdata.data.jobs->n_total = data->data.jobs->n_total;
getdata.data.jobs->pos = pos;
getdata.data.jobs->count = nc;
if (nc == 0) {
getdata.data.jobs->jobs = NULL;
} else {
getdata.data.jobs->jobs = &(data->data.jobs->jobs[pos]);
}
break;
case Data_data_schedworkers:
case Data_data_workers:
getdata.data.workers->n_total = data->data.workers->n_total;
getdata.data.workers->pos = pos;
getdata.data.workers->count = nc;
if (nc == 0) {
getdata.data.workers->workers = NULL;
} else {
getdata.data.workers->workers = &(data->data.workers->workers[pos]);
}
break;
case Data_data_resources:
getdata.data.resources->n_total = data->data.resources->n_total;
getdata.data.resources->pos = pos;
getdata.data.workers->count = nc;
if (nc == 0) {
getdata.data.resources->resources = NULL;
} else {
getdata.data.resources->resources = &(data->data.resources->resources[pos]);
}
break;
case Data_data_resvals:
getdata.data.resvals->n_total = data->data.resvals->n_total;
getdata.data.resvals->pos = pos;
getdata.data.resvals->count = nc;
if (nc == 0) {
getdata.data.resvals->vals = NULL;
} else {
getdata.data.resvals->vals = &(data->data.resvals->vals[pos]);
}
break;
default:
/* should never goes here */
break;
}
rc = xce_reply(ep, from, &reply1);
if (rc < 0) {
break;
}
pos += nc;
} while ((pos < nrows) && (checkstatus >= 0));
switch (getdata.table) {
case Data_data_schedjobs:
case Data_data_jobs:
FREEUP(getdata.data.jobs);
break;
case Data_data_schedworkers:
case Data_data_workers:
FREEUP(getdata.data.workers);
break;
case Data_data_resources:
FREEUP(getdata.data.resources);
break;
case Data_data_resvals:
FREEUP(getdata.data.resvals);
break;
default:
break;
}
return rc;
}
int extract_data(dataset_t* dataset,
xce_data_t* getdata)
{
int ntotal;
int rc = 0;
int pos = 0;
int count = 0;
TRACE("%s ...", __func__);
switch (getdata->table) {
case Data_data_schedjobs:
case Data_data_jobs:
if (getdata->data.jobs->count <= 0) {
return 1;
}
ntotal = getdata->data.jobs->n_total;
pos = getdata->data.jobs->pos;
count = getdata->data.jobs->count;
if (dataset->rows == NULL) {
dataset->rows = (xce_job_t**)calloc(ntotal, sizeof(xce_job_t*));
dataset->nrows = 0;
}
memcpy((void*)(((char*)dataset->rows) + sizeof(xce_job_t*) * pos),
getdata->data.jobs->jobs, count * sizeof(xce_job_t*));
memset(getdata->data.jobs->jobs, 0x0, count * sizeof(xce_job_t*));
break;
case Data_data_schedworkers:
case Data_data_workers:
if (getdata->data.workers->count <= 0) {
return 1;
}
ntotal = getdata->data.workers->n_total;
if (dataset->rows == NULL) {
dataset->rows = (xce_worker_t**)calloc(ntotal, sizeof(xce_worker_t*));
dataset->nrows = 0;
}
pos = getdata->data.workers->pos;
count = getdata->data.workers->count;
memcpy((void*)(((char*)dataset->rows) + sizeof(xce_worker_t*) * pos),
getdata->data.workers->workers, count * sizeof(xce_worker_t*));
memset(getdata->data.workers->workers, 0x0, count * sizeof(xce_worker_t*));
break;
case Data_data_resources:
if (getdata->data.resources->count <= 0) {
return 1;
}
ntotal = getdata->data.resources->n_total;
if (dataset->rows == NULL) {
dataset->rows = (xce_resource_t**)calloc(ntotal, sizeof(xce_resource_t*));
dataset->nrows = 0;
}
pos = getdata->data.resources->pos;
count = getdata->data.resources->count;
memcpy((void*)(((char*)dataset->rows) + sizeof(xce_resource_t*) * pos),
getdata->data.resources->resources, count * sizeof(xce_resource_t*));
memset(getdata->data.resources->resources, 0x0, count * sizeof(xce_resource_t*));
break;
case Data_data_resvals:
if (getdata->data.resvals->count <= 0) {
return 1;
}
ntotal = getdata->data.resvals->n_total;
if (dataset->rows == NULL) {
dataset->rows = (xce_resval_t**)calloc(ntotal, sizeof(xce_resval_t*));
dataset->nrows = 0;
}
pos = getdata->data.resvals->pos;
count = getdata->data.resvals->count;
memcpy((void*)(((char*)dataset->rows) + sizeof(xce_resval_t*) * pos),
getdata->data.resvals->vals, count * sizeof(xce_resval_t*));
memset(getdata->data.resvals->vals, 0x0, count * sizeof(xce_resval_t*));
break;
default:
rc = -EINVAL;
break;
}
if (rc < 0) {
return rc;
}
dataset->nrows += count;
if (dataset->nrows < ntotal) {
return 0;
}
return 1;
}
int xce_jobdispatch_req(ioctx_t* ctx,
xce_job_dispatch_t* info)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_jobdispatch,
.body_which = Request_body_dispatchmsg,
.body = {
.dispatchmsg = info
}
};
/* clang-format on */
/* clang-format off */
if ((ctx == NULL) ||
(info == NULL)) {
return -EINVAL;
}
/* clang-format on */
return xce_request(ctx, &request);
}
int xce_notify_req(ioctx_t* ctx,
xce_notify_data_t* data)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_notify,
.body_which = Request_body_notifymsg,
.body = {
.notifymsg = data
}
};
/* clang-forn on */
if ((ctx == NULL) || (data == NULL)) {
return -EINVAL;
}
return xce_request(ctx, &request);
}
int xce_jobsubmit_req(ioctx_t* ctx,
xce_job_submit_t* submit)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_jobsub,
.body_which = Request_body_jobsubmsg,
.body = {
.jobsubmsg = submit
}
};
/*clang-format on*/
/* clang-format off */
if ((ctx == NULL) ||
(submit == NULL)) {
return -EINVAL;
}
/* clang-format on */
return xce_request(ctx, &request);
}
int xce_startjob_req(ioctx_t* ctx,
xce_job_exec_t* execinfo)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_startjob,
.body_which = Request_body_jobstartmsg,
.body = {
.jobstartmsg = execinfo
}
};
/* clang-format on */
return xce_request(ctx, &request);
}
int xce_clusterconf_req(ioctx_t* ctx)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_clusterconf,
.body_which = Request_body_nomsg
};
/* clang-format on */
return xce_request(ctx, &request);
}
int xce_update_req(ioctx_t* ctx,
xce_update_data_t* data)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_update,
.body_which = Request_body_updatemsg,
.body = {
.updatemsg = data
}
};
/* clang-format on */
if ((ctx == NULL) || (data == NULL)) {
return -EINVAL;
}
return xce_request(ctx, &request);
}
int xce_jobctrl_req(ioctx_t* ctx,
xce_jobctrl_t* ctrinfo)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_jobcontrol,
.body_which = Request_body_jobctrlmsg,
.body = {
.jobctrlmsg = ctrinfo
}
};
/* clang-format on */
if ((ctx == NULL) || (ctrinfo == NULL)) {
return -EINVAL;
}
if (ctrinfo->jobid == 0) {
return -EINVAL;
}
switch (ctrinfo->action) {
case JobControl_u_siginfo:
break;
case JobControl_u_ckptoption:
if (ctrinfo->u.ckptoption->method == NULL) {
ctrinfo->u.ckptoption->method = "default";
}
break;
default:
return -EINVAL;
break;
}
return xce_request(ctx, &request);
}
int xce_queuectrl_req(ioctx_t* ctx,
xce_queuectrl_t* ctrlinfo)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_queuecontrol,
.body_which = Request_body_queuectrlmsg,
.body = {
.queuectrlmsg = ctrlinfo
}
};
/* clang-format on */
if ((ctx == NULL) || (ctrlinfo == NULL)) {
return -EINVAL;
}
if ((ctrlinfo->queue == NULL) || (strlen(ctrlinfo->queue) == 0)) {
return -EINVAL;
}
if (ctrlinfo->action == QUEUE_DO_NONE) {
return 0;
}
if ((ctrlinfo->action < 0) || (ctrlinfo->action > QUEUE_ACTIVE)) {
return -EINVAL;
}
return xce_request(ctx, &request);
}
int xce_runtask_req(ioctx_t* ctx,
xce_taskrun_t* runinfo)
{
/* clang-format off */
xce_request_t request = {
.opcode = OPCode_runtasks,
.body_which = Request_body_runtaskmsg,
.body = {
.runtaskmsg = runinfo
}
};
/* clang-format on */
if ((ctx == NULL) || (runinfo == NULL)) {
return -EINVAL;
}
if (runinfo->nhosts <= 0) {
return -EINVAL;
}
return xce_request(ctx, &request);
}