diff --git a/src/controller/xceobjs.c b/src/controller/xceobjs.c index 5a35c494..dedb3c46 100644 --- a/src/controller/xceobjs.c +++ b/src/controller/xceobjs.c @@ -1008,3 +1008,4 @@ static void* xgroup_create(objmgr_t* mgr, objtype_t* typeval, va_list ap) } static void xgroup_fini(void* g) { return; } static void xgroup_type_fini(objtype_t* typeval) { return; } + diff --git a/src/flake.lock b/src/flake.lock index 48a2e0b8..e0ed8bcf 100644 --- a/src/flake.lock +++ b/src/flake.lock @@ -117,11 +117,11 @@ "xbuild": "xbuild" }, "locked": { - "lastModified": 1771555882, - "narHash": "sha256-kNX3V49Gq1b+QUqh0/dgW74qeRg3nE7DC6sWaSCJKsQ=", + "lastModified": 1771560785, + "narHash": "sha256-0iyZt6UrIyYS3gCGNuUma2l7O92LS48XAm9HPd4bEN0=", "ref": "master", - "rev": "3da443cbadd0c15e4708f53d9f5abe2d3a40c2d2", - "revCount": 16, + "rev": "724c740909879b6b5d8851809f2aead7362bc78f", + "revCount": 17, "type": "git", "url": "ssh://forgejo@gitea.shenrs.eu/rshen/librtti" }, diff --git a/src/include/jobj.h b/src/include/jobj.h new file mode 100644 index 00000000..f4280c47 --- /dev/null +++ b/src/include/jobj.h @@ -0,0 +1,13 @@ +#if !defined(_JOBJ_H_) + +#define _JOBJ_H_ 1 + +#include "xce/types.h" + +extern job_submit_data_t* makeJobsub(job_submit_data_t*); +extern job_startinfo_t* makeJobstartinfo(job_startinfo_t*); +extern xce_job_t* makeJob(xce_job_t*); +extern int job_obj_init(int, int); +extern void job_obj_fini(); + +#endif diff --git a/src/include/kv.h b/src/include/kv.h index ee4f4104..07c76cf3 100644 --- a/src/include/kv.h +++ b/src/include/kv.h @@ -3,10 +3,12 @@ #define _KV_H_ 1 #include - -typedef void (*kv_value_kill_fn_t)(void*); +#include +#include extern typeinfo_t kvtab_int64_type; extern typeinfo_t kvtab_string_type; +extern typeinfo_t kvtab_generic_type; +extern int key_cmp_default(void*, void*, size_t); #endif diff --git a/src/include/utils.h b/src/include/utils.h index 39bb2c5b..938d9b3c 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -67,6 +67,10 @@ } #endif +#define EQUAL_STRING(s1, s2) \ + (((s1) == (s2)) \ + || (((s1) != NULL) && ((s2) != NULL) && (strcmp((s1), (s2)) == 0))) + #define N_EL_ARRAY(arr) (sizeof(arr) / sizeof(arr[0])) #define PTR_STEP(p, delta) ((void*)(((char*)p) + (delta))) diff --git a/src/lib/jobj.c b/src/lib/jobj.c new file mode 100644 index 00000000..53ab8d8f --- /dev/null +++ b/src/lib/jobj.c @@ -0,0 +1,612 @@ +#include +#include +#include +#include +#include + +#include "jobj.h" +#include "kv.h" +#include "mylock.h" +#include "utils.h" +#include "xce/types.h" +#include "xstring.h" + +static struct { + mylock_t lock; + var sub_table; +} jobsub_table; + +static struct { + mylock_t lock; + var startinfo_table; +} startinfo_table; + +static typeinfo_t job_submit_type; + +static void jobsub_destroy(meta_obj_t*); + +static void jobsub_killer(var s) +{ + if (s == NULL) { + return; + } + + destroy_(s, (obj_destroy_fn_t)jobsub_destroy); +} + +static int jobsub_table_init(int nslots) +{ + if (nslots <= 1) { + return -EINVAL; + } + + mylock_init(&(jobsub_table.lock)); + jobsub_table.sub_table + = makeInstance(&kvtab_generic_type, nslots, jobsub_killer, + sizeof(job_submit_data_t), key_cmp_default); + if (jobsub_table.sub_table == NULL) { + return -errno; + } + + return 1; +} + +static void jobsub_table_fini() +{ + destroy(jobsub_table.sub_table); + mylock_fini(&(jobsub_table.lock)); +} + +typedef struct { + mylock_t lock; + uint64_t refcount; +} job_submit_private_t; + +static size_t jobsub_datasize(va_list ap) +{ + size_t sz = sizeof(job_submit_data_t); + + return sz; +} + +static int jobsub_init(meta_obj_t* obj, va_list ap) +{ + job_submit_data_t* src = va_arg(ap, job_submit_data_t*); + job_submit_data_t* dst = RTTI_OBJ_TO_DATA(job_submit_data_t, obj); + job_submit_private_t* priv = (job_submit_private_t*)RTTI_OBJ_TO_PRIV(obj); + + if (src == NULL) { + return -EINVAL; + } + + dst->queue = makeString(src->queue); + dst->user = makeString(src->user); + dst->mintasks = src->mintasks; + dst->maxtasks = src->maxtasks; + if (src->start_info != NULL) { + dst->start_info = makeJobstartinfo(src->start_info); + if (dst->start_info == NULL) { + jobsub_destroy(obj); + return -ENOMEM; + } + } else { + dst->start_info = NULL; + } + dst->job_name = makeString(src->job_name); + dst->project_name = makeString(src->project_name); + dst->user_group = makeString(src->user_group); + dst->job_description = makeString(src->job_description); + dst->resreq = makeString(src->resreq); + + if (!(EQUAL_STRING(dst->queue, src->queue) + && EQUAL_STRING(dst->user, src->user) + && EQUAL_STRING(dst->job_name, src->job_name) + && EQUAL_STRING(dst->project_name, src->project_name) + && EQUAL_STRING(dst->user_group, src->user_group) + && EQUAL_STRING(dst->job_description, src->job_description) + && EQUAL_STRING(dst->resreq, src->resreq))) { + jobsub_destroy(obj); + return -ENOMEM; + } + + mylock_init(&(priv->lock)); + priv->refcount = 1; + + return 1; +} + +static void jobsub_destroy(meta_obj_t* obj) +{ + job_submit_data_t* jobsub = RTTI_OBJ_TO_DATA(job_submit_data_t, obj); + job_submit_private_t* priv = (job_submit_private_t*)RTTI_OBJ_TO_PRIV(obj); + + dereference(jobsub->queue); + dereference(jobsub->user); + dereference(jobsub->job_name); + dereference(jobsub->project_name); + dereference(jobsub->user_group); + dereference(jobsub->job_description); + dereference(jobsub->resreq); + if (jobsub->start_info != NULL) { + dereference(jobsub->start_info); + } + + mylock_fini(&(priv->lock)); + memset(priv, 0x0, sizeof(*priv)); +} + +static int jobsub_reference(meta_obj_t* obj) +{ + job_submit_private_t* priv = (job_submit_private_t*)RTTI_OBJ_TO_PRIV(obj); + + mylock_lock(&(priv->lock)); + priv->refcount++; + mylock_unlock(&(priv->lock)); + + return 1; +} + +static void jobsub_dereference(meta_obj_t* obj) +{ + job_submit_private_t* priv = (job_submit_private_t*)RTTI_OBJ_TO_PRIV(obj); + job_submit_data_t* data = RTTI_OBJ_TO_DATA(job_submit_data_t, obj); + uint64_t count; + + mylock_lock(&(priv->lock)); + priv->refcount--; + count = priv->refcount; + mylock_unlock(&(priv->lock)); + + if (count == 0) { + mylock_lock(&(jobsub_table.lock)); + key_del(jobsub_table.sub_table, data); + mylock_unlock(&(jobsub_table.lock)); + } + + return; +} + +static typeinfo_t job_submit_type + = { .name = "job submit", + .privateSize = sizeof(job_submit_private_t), + .dataSize = (datasize_fn_t)jobsub_datasize, + .init = (obj_init_fn_t)jobsub_init, + .destroy = (obj_destroy_fn_t)NULL, /* disable destroy() */ + .interfaces + = { .reference = &(intf_reference_t) { + .reference = (reference_fn_t)jobsub_reference, + .dereference = (dereference_fn_t)jobsub_dereference } } }; + +job_submit_data_t* makeJobsub(job_submit_data_t* subdata) +{ + var jobsub = NULL; + var jobsub1 = NULL; + int rc = 0; + + if (subdata == NULL) { + errno = EINVAL; + + return NULL; + } + + jobsub = makeInstance(&job_submit_type, subdata); + if (jobsub == NULL) { + return NULL; + } + + mylock_lock(&(jobsub_table.lock)); + rc = key_find(jobsub_table.sub_table, (void*)jobsub, (void**)&jobsub1); + if (rc > 0) { + reference(jobsub1); + } + mylock_unlock(&(jobsub_table.lock)); + + if (rc > 0) { + destroy_(jobsub, (obj_destroy_fn_t)jobsub_destroy); + return (job_submit_data_t*)jobsub1; + } + + mylock_lock(&(jobsub_table.lock)); + rc = key_add(jobsub_table.sub_table, (void*)jobsub, jobsub); + mylock_unlock(&(jobsub_table.lock)); + + if (rc < 0) { + destroy_(jobsub, (obj_destroy_fn_t)jobsub_destroy); + jobsub = NULL; + + errno = -rc; + } else { + errno = 0; + } + + return jobsub; +} + +typedef struct { + mylock_t lock; + uint64_t refcount; +} startinfo_private_t; + +static void startinfo_destroy(meta_obj_t* obj) +{ + job_startinfo_t* startinfo = RTTI_OBJ_TO_DATA(job_startinfo_t, obj); + startinfo_private_t* priv = (startinfo_private_t*)RTTI_OBJ_TO_PRIV(obj); + + dereference(startinfo->exechome); + dereference(startinfo->execcwd); + dereference(startinfo->execuser); + dereference(startinfo->cmdline); + if (startinfo->exdata != NULL) { + dereference(startinfo->exdata); + } + + if (startinfo->launch_type != NULL) { + dereference(startinfo->launch_type); + } + + if (startinfo->q_pre_exec != NULL) { + dereference(startinfo->q_pre_exec); + } + + if (startinfo->q_post_exec != NULL) { + dereference(startinfo->q_post_exec); + } + + if (startinfo->job_pre_exec != NULL) { + dereference(startinfo->job_pre_exec); + } + + if (startinfo->job_post_exec != NULL) { + dereference(startinfo->job_post_exec); + } + + mylock_fini(&(priv->lock)); + memset(priv, 0x0, sizeof(*priv)); + return; +} + +static size_t startinfo_datasize(va_list ap) +{ + size_t sz = sizeof(job_startinfo_t); + + return sz; +} + +static int startinfo_init(meta_obj_t* obj, va_list ap) +{ + job_startinfo_t* src = va_arg(ap, job_startinfo_t*); + job_startinfo_t* dst = RTTI_OBJ_TO_DATA(job_startinfo_t, obj); + startinfo_private_t* priv = RTTI_OBJ_TO_PRIV(obj); + + if (src == NULL) { + return -EINVAL; + } + + mylock_init(&(priv->lock)); + priv->refcount = 1; + + dst->exechome = makeString(src->exechome); + dst->execcwd = makeString(src->execcwd); + dst->execuser = makeString(src->execuser); + dst->cmdline = makeString(src->cmdline); + dst->exdata = NULL; + if (src->exdata != NULL) { + dst->exdata = makeString(src->exdata); + } + + dst->launch_type = NULL; + if (src->launch_type != NULL) { + dst->launch_type = makeString(src->launch_type); + } + + dst->q_pre_exec = NULL; + if (src->q_pre_exec != NULL) { + dst->q_pre_exec = makeString(src->q_pre_exec); + } + + dst->q_post_exec = NULL; + if (src->q_post_exec != NULL) { + dst->q_post_exec = makeString(src->q_post_exec); + } + + dst->job_pre_exec = NULL; + if (src->job_pre_exec != NULL) { + dst->job_pre_exec = makeString(src->job_pre_exec); + } + + dst->job_post_exec = NULL; + if (src->job_post_exec != NULL) { + dst->job_post_exec = makeString(src->job_post_exec); + } + + return 1; +} + +static int startinfo_reference(meta_obj_t* obj) +{ + startinfo_private_t* priv = (startinfo_private_t*)RTTI_OBJ_TO_PRIV(obj); + + mylock_lock(&(priv->lock)); + priv->refcount++; + mylock_unlock(&(priv->lock)); + + return 1; +} + +static void startinfo_dereference(meta_obj_t* obj) +{ + job_startinfo_t* startinfo = RTTI_OBJ_TO_DATA(job_startinfo_t, obj); + startinfo_private_t* priv = (startinfo_private_t*)RTTI_OBJ_TO_PRIV(obj); + uint64_t count; + + mylock_lock(&(priv->lock)); + priv->refcount--; + count = priv->refcount; + mylock_unlock(&(priv->lock)); + + if (count == 0) { + mylock_lock(&(startinfo_table.lock)); + key_del(startinfo_table.startinfo_table, startinfo); + mylock_unlock(&(startinfo_table.lock)); + } + return; +} + +static typeinfo_t job_startinfo_type + = { .name = "job start info", + .privateSize = sizeof(startinfo_private_t), + .dataSize = (datasize_fn_t)startinfo_datasize, + .init = (obj_init_fn_t)startinfo_init, + .destroy = NULL, + .interfaces + = { .reference = &(intf_reference_t) { + .reference = (reference_fn_t)startinfo_reference, + .dereference = (dereference_fn_t)startinfo_dereference } } }; + +job_startinfo_t* makeJobstartinfo(job_startinfo_t* startinfo) +{ + var startinfo1 = NULL; + var startinfo2 = NULL; + int rc = 0; + + if (startinfo == NULL) { + errno = EINVAL; + + return NULL; + } + + startinfo1 = makeInstance(&(job_startinfo_type), startinfo); + if (startinfo1 == NULL) { + return NULL; + } + + mylock_lock(&(startinfo_table.lock)); + rc = key_find(startinfo_table.startinfo_table, (void*)startinfo1, + (void**)&startinfo2); + if (rc > 0) { + reference(startinfo2); + } + mylock_unlock(&(startinfo_table.lock)); + + if (rc > 0) { + destroy_(startinfo1, (obj_destroy_fn_t)startinfo_destroy); + return (job_startinfo_t*)startinfo2; + } + + mylock_lock(&(startinfo_table.lock)); + rc = key_add(startinfo_table.startinfo_table, (void*)startinfo1, + startinfo1); + mylock_unlock(&(startinfo_table.lock)); + + if (rc < 0) { + destroy_(startinfo1, (obj_destroy_fn_t)startinfo_destroy); + startinfo1 = NULL; + errno = -rc; + } else { + errno = 0; + } + return startinfo1; +} + +static void startinfo_killer(var s) +{ + if (s == NULL) { + return; + } + + destroy_(s, (obj_destroy_fn_t)startinfo_destroy); +} + +static int startinfo_table_init(int nslots) +{ + if (nslots <= 1) { + return -EINVAL; + } + + mylock_init(&(startinfo_table.lock)); + startinfo_table.startinfo_table + = makeInstance(&kvtab_generic_type, nslots, startinfo_killer, + sizeof(job_startinfo_t), key_cmp_default); + if (startinfo_table.startinfo_table == NULL) { + return -errno; + } + + return 0; +} + +static void startinfo_table_fini() +{ + destroy(startinfo_table.startinfo_table); + mylock_fini(&(startinfo_table.lock)); + + return; +} + +typedef struct { + my_rwlock_t lock; + uint64_t refcount; +} job_private_t; + +static size_t job_datasize(va_list ap) +{ + size_t sz = sizeof(xce_job_t); + + return sz; +} + +static int job_init(meta_obj_t* obj, va_list ap) +{ + xce_job_t* dst = RTTI_OBJ_TO_DATA(xce_job_t, obj); + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + xce_job_t* src = va_arg(ap, xce_job_t*); + + if (src->submit == NULL) { + return -EINVAL; + } + + dst->jobid = src->jobid; + dst->submit = makeJobsub(src->submit); + dst->sub_time = src->sub_time; + dst->queue_time = src->queue_time; + dst->start_time = src->start_time; + dst->finish_time = src->finish_time; + MOVE_PTR(dst->pidinfo, src->pidinfo); + dst->state = src->state; + MOVE_PTR(dst->allocs, src->allocs); + MOVE_PTR(dst->accounts, src->accounts); + dst->run_time = src->run_time; + MOVE_PTR(dst->run_usage, src->run_usage); + MOVE_PTR(dst->exit_info, src->exit_info); + dst->ckptinfo = makeString(src->ckptinfo); + dst->pending_ctrl = src->pending_ctrl; + MOVE_PTR(dst->pend_reasons, src->pend_reasons); + + my_rwlock_init(&(priv->lock)); + priv->refcount = 1; + + return 1; +} + +static void job_destroy(meta_obj_t* obj) +{ + xce_job_t* j = RTTI_OBJ_TO_DATA(xce_job_t, obj); + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + + dereference(j->submit); + dereference(j->ckptinfo); + + /* FIXME: */ + if (j->pidinfo != NULL) { } + + if (j->allocs != NULL) { } + + if (j->accounts != NULL) { } + + if (j->run_usage != NULL) { } + + if (j->exit_info != NULL) { } + + if (j->pend_reasons != NULL) { } + + my_rwlock_fini(&(priv->lock)); + memset(priv, 0x0, sizeof(*priv)); + + return; +} + +static int job_reference(meta_obj_t* obj) +{ + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + + my_rwlock_wlock(&(priv->lock)); + priv->refcount++; + my_rwlock_unlock(&(priv->lock)); + + return 1; +} + +static void job_dereference(meta_obj_t* obj) +{ + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + xce_job_t* j = RTTI_OBJ_TO_DATA(xce_job_t, obj); + uint64_t count; + + my_rwlock_wlock(&(priv->lock)); + priv->refcount--; + count = priv->refcount; + my_rwlock_unlock(&(priv->lock)); + + if (count == 0) { + destroy_(j, (obj_destroy_fn_t)job_destroy); + } + + return; +} + +static int job_lock(meta_obj_t* obj, uint64_t option) +{ + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + int rc = -EINVAL; + + switch (option) { + case RTTI_LOCK_READ: + rc = my_rwlock_rlock(&(priv->lock)); + break; + case RTTI_LOCK_WRITE: + rc = my_rwlock_wlock(&(priv->lock)); + break; + default: + break; + } + + return rc; +} + +static void job_unlock(meta_obj_t* obj) +{ + job_private_t* priv = (job_private_t*)RTTI_OBJ_TO_PRIV(obj); + + my_rwlock_unlock(&(priv->lock)); + + return; +} + +static typeinfo_t job_type = { + .name = "xce job", + .privateSize = sizeof(job_private_t), + .dataSize = (datasize_fn_t)job_datasize, + .init = (obj_init_fn_t)job_init, + .destroy = NULL, + .interfaces + = { .reference + = &(intf_reference_t) { .reference = (reference_fn_t)job_reference, + .dereference + = (dereference_fn_t)job_dereference }, + .lock = &(intf_lock_t) { .lock = (lock_fn_t)job_lock, + .unlock = (unlock_fn_t)job_unlock } } +}; + +xce_job_t* makeJob(xce_job_t* j) +{ + xce_job_t* job = makeInstance(&job_type, j); + return job; +} + +int job_obj_init(int n_sub_table_slots, int n_startinfo_table_slots) +{ + int rc = 0; + + rc = jobsub_table_init(n_sub_table_slots); + if (rc < 0) { + return rc; + } + + rc = startinfo_table_init(n_startinfo_table_slots); + return rc; +} + +void job_obj_fini(void) +{ + jobsub_table_fini(); + startinfo_table_fini(); +} diff --git a/src/lib/kv.c b/src/lib/kv.c index 0a2e5cb5..e4acd3fa 100644 --- a/src/lib/kv.c +++ b/src/lib/kv.c @@ -15,9 +15,9 @@ struct kvent_ { }; typedef struct { - uint32_t nslots; - kv_value_kill_fn_t val_killer; - kvent_t** slots; + uint32_t nslots; + destroy_fn_t val_killer; + kvent_t** slots; } kvtab_t; static size_t kvtab_datasize(va_list ap) @@ -28,9 +28,9 @@ static size_t kvtab_datasize(va_list ap) static int kvtab_init(meta_obj_t* obj, va_list ap) { - kvtab_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_t, obj); - uint32_t nslots = va_arg(ap, uint32_t); - kv_value_kill_fn_t killer = va_arg(ap, kv_value_kill_fn_t); + kvtab_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_t, obj); + uint32_t nslots = va_arg(ap, uint32_t); + destroy_fn_t killer = va_arg(ap, destroy_fn_t); if (nslots <= 1) { return -EINVAL; @@ -310,3 +310,183 @@ typeinfo_t kvtab_string_type .add_key = (key_add_fn_t)kvtab_string_add, .del_key = (key_del_fn_t)kvtab_string_del, .find_key = (key_find_fn_t)kvtab_string_find } } }; + +typedef struct { + uint32_t nslots; + size_t keylen; + destroy_fn_t val_killer; + comp_fn_t cmp; + kvent_t** slots; +} kvtab_generic_t; + +static size_t kvtab_generic_datasize(va_list ap) +{ + size_t sz = sizeof(kvtab_generic_t); + + return sz; +} + +static int kvtab_generic_init(meta_obj_t* obj, va_list ap) +{ + uint32_t nslots = va_arg(ap, uint32_t); + destroy_fn_t killer = va_arg(ap, destroy_fn_t); + size_t keylen = va_arg(ap, size_t); + comp_fn_t cmp = va_arg(ap, comp_fn_t); + kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); + + if (nslots <= 1) { + return -EINVAL; + } + + kvtab->slots = (kvent_t**)calloc(nslots, sizeof(*(kvtab->slots))); + if (kvtab->slots == NULL) { + return -EINVAL; + } + + kvtab->nslots = nslots; + kvtab->val_killer = killer; + kvtab->cmp = cmp; + kvtab->keylen = keylen; + + return 1; +} + +static void kvtab_generic_destroy(meta_obj_t* obj) +{ + kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); + int i; + + for (i = 0; i < kvtab->nslots; i++) { + kvent_t* e = NULL; + while ((e = kvtab->slots[i]) != NULL) { + kvtab->slots[i] = e->next; + e->next = NULL; + FREEUP(e->key); + if (kvtab->val_killer != NULL) { + kvtab->val_killer(e->value); + } + + FREEUP(e); + } + } + + FREEUP(kvtab->slots); + + return; +} + +static kvent_t* kvtab_generic_get(kvtab_generic_t* kvtab, void* key) +{ + uint32_t hc; + kvent_t* e = NULL; + + hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; + e = kvtab->slots[hc]; + + while (e != NULL) { + if (kvtab->cmp(e->key, key, kvtab->keylen) == 0) { + break; + } + + e = e->next; + } + + return e; +} + +static int kvtab_generic_add(meta_obj_t* obj, void* key, void* value) +{ + kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); + kvent_t* e = NULL; + uint32_t hc; + + e = kvtab_generic_get(kvtab, key); + if (e != NULL) { + return -EEXIST; + } + + e = (kvent_t*)calloc(1, sizeof(*e)); + if (e == NULL) { + return -ENOMEM; + } + + e->key = (void*)calloc(1, kvtab->keylen); + if (e->key == NULL) { + FREEUP(e); + return -ENOMEM; + } + + memcpy(e->key, key, kvtab->keylen); + e->value = value; + + hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; + e->next = kvtab->slots[hc]; + kvtab->slots[hc] = e; + + return 1; +} + +static int kvtab_generic_del(meta_obj_t* obj, void* key) +{ + kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); + kvent_t** e = NULL; + uint32_t hc; + + hc = hash_block((char*)key, kvtab->keylen) % kvtab->nslots; + e = &(kvtab->slots[hc]); + + while ((*e) != NULL) { + if (kvtab->cmp((*e)->key, key, kvtab->keylen) == 0) { + kvent_t* e1 = *e; + + *e = e1->next; + FREEUP(e1->key); + if (kvtab->val_killer != NULL) { + kvtab->val_killer(e1->value); + } + + FREEUP(e1); + + return 1; + } + + e = &((*e)->next); + } + + return 0; +} + +static int kvtab_generic_find(meta_obj_t* obj, void* key, void** value) +{ + kvtab_generic_t* kvtab = RTTI_OBJ_TO_DATA(kvtab_generic_t, obj); + kvent_t* e = NULL; + + if (value == NULL) { + return -EINVAL; + } + + e = kvtab_generic_get(kvtab, key); + if (e == NULL) { + return -ENOENT; + } + + *value = e->value; + + return 1; +} + +typeinfo_t kvtab_generic_type + = { .name = "kvtab_generic", + .privateSize = 0, + .dataSize = (datasize_fn_t)kvtab_generic_datasize, + .init = (obj_init_fn_t)kvtab_generic_init, + .destroy = (obj_destroy_fn_t)kvtab_generic_destroy, + .interfaces = { .kv = &(intf_kv_t) { + .add_key = (key_add_fn_t)kvtab_generic_add, + .del_key = (key_del_fn_t)kvtab_generic_del, + .find_key = (key_find_fn_t)kvtab_generic_find } } }; + +int key_cmp_default(void* k1, void* k2, size_t len) +{ + return memcmp(k1, k2, len); +} diff --git a/src/lib/meson.build b/src/lib/meson.build index e9c79b8e..dcaf6ac8 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -84,6 +84,10 @@ libxce_src = [ gen_srcs[0], 'resreq.c', 'bitset.c', 'kv.c', + 'jobj.c', + 'qobj.c', + 'resobj.c', + 'wobj.c', ] incdir = include_directories('../include') @@ -137,6 +141,7 @@ libxce_test_src = ['testsuite/test.c', 'testsuite/test_resreq.c', 'testsuite/test_bitset.c', 'testsuite/test_kv.c', + 'testsuite/test_jobj.c', ] libxce_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep] diff --git a/src/lib/qobj.c b/src/lib/qobj.c new file mode 100644 index 00000000..60f96d8e --- /dev/null +++ b/src/lib/qobj.c @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include diff --git a/src/lib/resobj.c b/src/lib/resobj.c new file mode 100644 index 00000000..60f96d8e --- /dev/null +++ b/src/lib/resobj.c @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include diff --git a/src/lib/testsuite/test.c b/src/lib/testsuite/test.c index ef3ee050..0b71b60c 100644 --- a/src/lib/testsuite/test.c +++ b/src/lib/testsuite/test.c @@ -24,6 +24,7 @@ extern void test_xvec(void); extern void test_resreq(void); extern void test_bitset(void); extern void test_kv(void); +extern void test_jobobj(void); void setUp(void) { return; } @@ -117,6 +118,7 @@ int main(int argc, char* argv[]) TEST(test_resreq); TEST(test_bitset); TEST(test_kv); + TEST(test_jobobj); return UNITY_END(); } diff --git a/src/lib/testsuite/test_jobj.c b/src/lib/testsuite/test_jobj.c new file mode 100644 index 00000000..659aadd6 --- /dev/null +++ b/src/lib/testsuite/test_jobj.c @@ -0,0 +1,290 @@ +#include +#include +#include +#include + +#include + +#include "jobj.h" +#include "utils.h" +#include "xstring.h" + +static void test_startinfo_create() +{ + int rc; + job_startinfo_t s1 = { .exechome = "/homes/rshen", + .execcwd = "/tmp", + .execuser = "rshen", + .cmdline = "sleep 3000", + .exdata = "Hello", + .q_pre_exec = "sleep 1", + .q_post_exec = "sleep 10", + .job_pre_exec = "pwd", + .job_post_exec = "hello" }; + job_startinfo_t* s2 = NULL; + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + s2 = makeJobstartinfo(&s1); + + TEST_ASSERT_TRUE(s2 != NULL); + + TEST_ASSERT_TRUE(EQUAL_STRING(s1.exechome, s2->exechome) + && EQUAL_STRING(s1.execcwd, s2->execcwd) + && EQUAL_STRING(s1.execuser, s2->execuser) + && EQUAL_STRING(s1.cmdline, s2->cmdline) + && EQUAL_STRING(s1.exdata, s2->exdata) + && EQUAL_STRING(s1.q_pre_exec, s2->q_pre_exec) + && EQUAL_STRING(s1.q_post_exec, s2->q_post_exec) + && EQUAL_STRING(s1.job_pre_exec, s2->job_pre_exec) + && EQUAL_STRING(s1.job_post_exec, s2->job_post_exec)); + job_obj_fini(); + xstring_table_fini(); +} + +static void test_startinfo_share() +{ + int rc; + job_startinfo_t s1 = { .exechome = "/homes/rshen", + .execcwd = "/tmp", + .execuser = "rshen", + .cmdline = "sleep 3000", + .exdata = "Hello", + .q_pre_exec = "sleep 1", + .q_post_exec = "sleep 10", + .job_pre_exec = "pwd", + .job_post_exec = "hello" }; + job_startinfo_t* s2 = NULL; + job_startinfo_t* s3 = NULL; + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + s2 = makeJobstartinfo(&s1); + + TEST_ASSERT_TRUE(s2 != NULL); + + TEST_ASSERT_TRUE(EQUAL_STRING(s1.exechome, s2->exechome) + && EQUAL_STRING(s1.execcwd, s2->execcwd) + && EQUAL_STRING(s1.execuser, s2->execuser) + && EQUAL_STRING(s1.cmdline, s2->cmdline) + && EQUAL_STRING(s1.exdata, s2->exdata) + && EQUAL_STRING(s1.q_pre_exec, s2->q_pre_exec) + && EQUAL_STRING(s1.q_post_exec, s2->q_post_exec) + && EQUAL_STRING(s1.job_pre_exec, s2->job_pre_exec) + && EQUAL_STRING(s1.job_post_exec, s2->job_post_exec)); + + s3 = makeJobstartinfo(&s1); + TEST_ASSERT_TRUE(s2 == s3); + + job_obj_fini(); + xstring_table_fini(); +} + +static void test_jobsub_create(void) +{ + int rc; + job_startinfo_t s1 = { .exechome = "/homes/rshen", + .execcwd = "/tmp", + .execuser = "rshen", + .cmdline = "sleep 3000", + .exdata = "Hello", + .q_pre_exec = "sleep 1", + .q_post_exec = "sleep 10", + .job_pre_exec = "pwd", + .job_post_exec = "hello" }; + job_submit_data_t jobsub1 = { .queue = "xce", + .user = "rshen", + .mintasks = 1, + .maxtasks = 5, + .start_info = &s1, + .job_name = "J1", + .project_name = "default", + .user_group = NULL, + .job_description = "no description", + .resreq = "type == any" }; + job_submit_data_t* s2 = NULL; + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + s2 = makeJobsub(&jobsub1); + + TEST_ASSERT_TRUE(s2 != NULL); + + TEST_ASSERT_TRUE( + EQUAL_STRING(s1.exechome, s2->start_info->exechome) + && EQUAL_STRING(s1.execcwd, s2->start_info->execcwd) + && EQUAL_STRING(s1.execuser, s2->start_info->execuser) + && EQUAL_STRING(s1.cmdline, s2->start_info->cmdline) + && EQUAL_STRING(s1.exdata, s2->start_info->exdata) + && EQUAL_STRING(s1.q_pre_exec, s2->start_info->q_pre_exec) + && EQUAL_STRING(s1.q_post_exec, s2->start_info->q_post_exec) + && EQUAL_STRING(s1.job_pre_exec, s2->start_info->job_pre_exec) + && EQUAL_STRING(s1.job_post_exec, s2->start_info->job_post_exec) + && EQUAL_STRING(s2->queue, "xce") && EQUAL_STRING(s2->user, "rshen") + && EQUAL_STRING(s2->job_name, "J1") + && EQUAL_STRING(s2->project_name, "default") + && EQUAL_STRING(s2->job_description, "no description") + && EQUAL_STRING(s2->resreq, "type == any") && (s2->mintasks == 1) + && (s2->maxtasks == 5) && (s2->user_group == NULL)); + + job_obj_fini(); + xstring_table_fini(); +} + +static void test_jobsub_share(void) +{ + int rc; + job_startinfo_t s1 = { .exechome = "/homes/rshen", + .execcwd = "/tmp", + .execuser = "rshen", + .cmdline = "sleep 3000", + .exdata = "Hello", + .q_pre_exec = "sleep 1", + .q_post_exec = "sleep 10", + .job_pre_exec = "pwd", + .job_post_exec = "hello" }; + job_submit_data_t jobsub1 = { .queue = "xce", + .user = "rshen", + .mintasks = 1, + .maxtasks = 5, + .start_info = &s1, + .job_name = "J1", + .project_name = "default", + .user_group = NULL, + .job_description = "no description", + .resreq = "type == any" }; + job_submit_data_t* s2 = NULL; + job_submit_data_t* s3 = NULL; + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + s2 = makeJobsub(&jobsub1); + + TEST_ASSERT_TRUE(s2 != NULL); + + TEST_ASSERT_TRUE( + EQUAL_STRING(s1.exechome, s2->start_info->exechome) + && EQUAL_STRING(s1.execcwd, s2->start_info->execcwd) + && EQUAL_STRING(s1.execuser, s2->start_info->execuser) + && EQUAL_STRING(s1.cmdline, s2->start_info->cmdline) + && EQUAL_STRING(s1.exdata, s2->start_info->exdata) + && EQUAL_STRING(s1.q_pre_exec, s2->start_info->q_pre_exec) + && EQUAL_STRING(s1.q_post_exec, s2->start_info->q_post_exec) + && EQUAL_STRING(s1.job_pre_exec, s2->start_info->job_pre_exec) + && EQUAL_STRING(s1.job_post_exec, s2->start_info->job_post_exec) + && EQUAL_STRING(s2->queue, "xce") && EQUAL_STRING(s2->user, "rshen") + && EQUAL_STRING(s2->job_name, "J1") + && EQUAL_STRING(s2->project_name, "default") + && EQUAL_STRING(s2->job_description, "no description") + && EQUAL_STRING(s2->resreq, "type == any") && (s2->mintasks == 1) + && (s2->maxtasks == 5) && (s2->user_group == NULL)); + + s3 = makeJobsub(&jobsub1); + + TEST_ASSERT_TRUE(s2 == s3); + + job_obj_fini(); + xstring_table_fini(); +} + +static void test_job_create(void) +{ + int rc; + job_startinfo_t s1 = { .exechome = "/homes/rshen", + .execcwd = "/tmp", + .execuser = "rshen", + .cmdline = "sleep 3000", + .exdata = "Hello", + .q_pre_exec = "sleep 1", + .q_post_exec = "sleep 10", + .job_pre_exec = "pwd", + .job_post_exec = "hello" }; + job_submit_data_t jobsub1 = { .queue = "xce", + .user = "rshen", + .mintasks = 1, + .maxtasks = 5, + .start_info = &s1, + .job_name = "J1", + .project_name = "default", + .user_group = NULL, + .job_description = "no description", + .resreq = "type == any" }; + xce_job_t job1 = { .submit = &jobsub1 }; + xce_job_t* j2 = NULL; + time_t now = time(NULL); + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + job1.sub_time = now; + job1.queue_time = now; + job1.start_time = 0; + job1.finish_time = 0; + job1.pidinfo = NULL; + job1.state = JOB_STAT_PEND; + job1.allocs = NULL; + job1.run_time = 0; + job1.run_usage = NULL; + job1.exit_info = NULL; + job1.ckptinfo = NULL; + job1.pending_ctrl = 0; + job1.jobid = 100; + + j2 = makeJob(&job1); + + TEST_ASSERT_TRUE(j2 != NULL); + + TEST_ASSERT_TRUE( + EQUAL_STRING(s1.exechome, j2->submit->start_info->exechome) + && EQUAL_STRING(s1.execcwd, j2->submit->start_info->execcwd) + && EQUAL_STRING(s1.execuser, j2->submit->start_info->execuser) + && EQUAL_STRING(s1.cmdline, j2->submit->start_info->cmdline) + && EQUAL_STRING(s1.exdata, j2->submit->start_info->exdata) + && EQUAL_STRING(s1.q_pre_exec, j2->submit->start_info->q_pre_exec) + && EQUAL_STRING(s1.q_post_exec, j2->submit->start_info->q_post_exec) + && EQUAL_STRING(s1.job_pre_exec, j2->submit->start_info->job_pre_exec) + && EQUAL_STRING(s1.job_post_exec, j2->submit->start_info->job_post_exec) + && EQUAL_STRING(j2->submit->queue, "xce") + && EQUAL_STRING(j2->submit->user, "rshen") + && EQUAL_STRING(j2->submit->job_name, "J1") + && EQUAL_STRING(j2->submit->project_name, "default") + && EQUAL_STRING(j2->submit->job_description, "no description") + && EQUAL_STRING(j2->submit->resreq, "type == any") + && (j2->submit->mintasks == 1) && (j2->submit->maxtasks == 5) + && (j2->submit->user_group == NULL)); + + destroy(j2); + + job_obj_fini(); + xstring_table_fini(); +} + +void test_jobobj(void) +{ + printf("\n>> job obj test\n\n"); + + RUN_TEST(test_startinfo_create); + RUN_TEST(test_startinfo_share); + RUN_TEST(test_jobsub_create); + RUN_TEST(test_jobsub_share); + RUN_TEST(test_job_create); +} diff --git a/src/lib/wobj.c b/src/lib/wobj.c new file mode 100644 index 00000000..60f96d8e --- /dev/null +++ b/src/lib/wobj.c @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include