From 363709b032f3b36b793caa81bdd143060db6cfd2 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Mon, 24 Aug 2026 15:14:42 +0000 Subject: [PATCH] fix(lib): thread from_host through the wire format and the job-submit interning object (bug-1676, gitea #44) - src/schema/controller.capnp: JobSubmitData gains fromHost @10: Text $C.mapname("from_host") -- auto-regenerates controller.capnp.c/h via the existing meson capnpc-c custom_target. - src/include/xce/types.h: job_submit_data_t gains char* from_host. - src/lib/jobj.c: jobsub_init/jobsub_destroy (the hand-written, ref-counted, content-deduped job-submit interning object -- not auto-generated) thread from_host through the deep-copy, the dedup identity comparison, and the destroy path. Closes the wire-format half of the round-trip: from_host now survives from the apiserver's submission all the way through the controller and back on every subsequent job-state push, and rides along for free in the existing WAL_JOB_SUBMIT persistence across a controller restart. Did not need to touch job.c's build_job_submit_payloads() (bare pointer borrow of the already-decoded submit struct) or any WAL apply-path code (capnp_encode_job/decode_Job already generically handle the whole xce_job_t including its full .submit sub-struct). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg --- src/include/xce/types.h | 1 + src/lib/jobj.c | 5 ++- src/lib/testsuite/test_jobj.c | 64 ++++++++++++++++++++++++++++++++--- src/schema/controller.capnp | 1 + 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/include/xce/types.h b/src/include/xce/types.h index 8e81bb34..b8bd359c 100644 --- a/src/include/xce/types.h +++ b/src/include/xce/types.h @@ -333,6 +333,7 @@ typedef struct { char* user_group; char* job_description; char* resreq; + char* from_host; } job_submit_data_t; typedef struct { diff --git a/src/lib/jobj.c b/src/lib/jobj.c index d4a5bd06..dd2c3a3e 100644 --- a/src/lib/jobj.c +++ b/src/lib/jobj.c @@ -148,6 +148,7 @@ static int jobsub_init(meta_obj_t* obj, va_list ap) dst->user_group = makeString(src->user_group); dst->job_description = makeString(src->job_description); dst->resreq = makeString(src->resreq); + dst->from_host = makeString(src->from_host); if (!(EQUAL_STRING(dst->queue, src->queue) && EQUAL_STRING(dst->user, src->user) @@ -155,7 +156,8 @@ static int jobsub_init(meta_obj_t* obj, va_list ap) && 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))) { + && EQUAL_STRING(dst->resreq, src->resreq) + && EQUAL_STRING(dst->from_host, src->from_host))) { jobsub_destroy(obj); return -ENOMEM; } @@ -177,6 +179,7 @@ static void jobsub_destroy(meta_obj_t* obj) dereference(jobsub->user_group); dereference(jobsub->job_description); dereference(jobsub->resreq); + dereference(jobsub->from_host); if (jobsub->start_info != NULL) { dereference(jobsub->start_info); } diff --git a/src/lib/testsuite/test_jobj.c b/src/lib/testsuite/test_jobj.c index 892150fc..641d966a 100644 --- a/src/lib/testsuite/test_jobj.c +++ b/src/lib/testsuite/test_jobj.c @@ -110,7 +110,8 @@ static void test_jobsub_create(void) .project_name = "default", .user_group = NULL, .job_description = "no description", - .resreq = "type == any" }; + .resreq = "type == any", + .from_host = "review-client" }; job_submit_data_t* s2 = NULL; rc = xstring_table_init(32); @@ -137,7 +138,9 @@ static void test_jobsub_create(void) && 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) + && EQUAL_STRING(s2->resreq, "type == any") + && EQUAL_STRING(s2->from_host, "review-client") + && (s2->mintasks == 1) && (s2->maxtasks == 5) && (s2->user_group == NULL)); job_obj_fini(); @@ -165,7 +168,8 @@ static void test_jobsub_share(void) .project_name = "default", .user_group = NULL, .job_description = "no description", - .resreq = "type == any" }; + .resreq = "type == any", + .from_host = "review-client" }; job_submit_data_t* s2 = NULL; job_submit_data_t* s3 = NULL; @@ -193,7 +197,9 @@ static void test_jobsub_share(void) && 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) + && EQUAL_STRING(s2->resreq, "type == any") + && EQUAL_STRING(s2->from_host, "review-client") + && (s2->mintasks == 1) && (s2->maxtasks == 5) && (s2->user_group == NULL)); s3 = makeJobsub(&jobsub1); @@ -204,6 +210,51 @@ static void test_jobsub_share(void) xstring_table_fini(); } +/* bug-1676: from_host must participate in makeJobsub's content-dedup + * identity, not just be silently dropped or ignored -- two submissions + * differing ONLY in from_host must NOT collapse to the same interned + * object (they are genuinely different submissions from different + * clients), while an identical from_host still dedupes like every other + * field (test_jobsub_share above). */ +static void test_jobsub_from_host_distinguishes_identity(void) +{ + int rc; + job_submit_data_t jobsub_a = { .queue = "xce", + .user = "rshen", + .mintasks = 1, + .maxtasks = 5, + .job_name = "J1", + .resreq = "type == any", + .from_host = "client-a" }; + job_submit_data_t jobsub_b = { .queue = "xce", + .user = "rshen", + .mintasks = 1, + .maxtasks = 5, + .job_name = "J1", + .resreq = "type == any", + .from_host = "client-b" }; + job_submit_data_t* sa = NULL; + job_submit_data_t* sb = NULL; + + rc = xstring_table_init(32); + TEST_ASSERT_TRUE(rc >= 0); + + rc = job_obj_init(31, 31); + TEST_ASSERT_TRUE(rc >= 0); + + sa = makeJobsub(&jobsub_a); + sb = makeJobsub(&jobsub_b); + + TEST_ASSERT_TRUE(sa != NULL); + TEST_ASSERT_TRUE(sb != NULL); + TEST_ASSERT_TRUE(sa != sb); + TEST_ASSERT_TRUE(EQUAL_STRING(sa->from_host, "client-a")); + TEST_ASSERT_TRUE(EQUAL_STRING(sb->from_host, "client-b")); + + job_obj_fini(); + xstring_table_fini(); +} + static void test_job_create(void) { int rc; @@ -230,7 +281,8 @@ static void test_job_create(void) .project_name = "default", .user_group = NULL, .job_description = "no description", - .resreq = "type == any" }; + .resreq = "type == any", + .from_host = "review-client" }; xce_job_t job1 = { .submit = &jobsub1 }; job_t* j2 = NULL; time_t now = time(NULL); @@ -278,6 +330,7 @@ static void test_job_create(void) && EQUAL_STRING(j2->job.submit->project_name, "default") && EQUAL_STRING(j2->job.submit->job_description, "no description") && EQUAL_STRING(j2->job.submit->resreq, "type == any") + && EQUAL_STRING(j2->job.submit->from_host, "review-client") && (j2->job.submit->mintasks == 1) && (j2->job.submit->maxtasks == 5) && (j2->job.submit->user_group == NULL)); @@ -295,5 +348,6 @@ void test_jobobj(void) RUN_TEST(test_startinfo_share); RUN_TEST(test_jobsub_create); RUN_TEST(test_jobsub_share); + RUN_TEST(test_jobsub_from_host_distinguishes_identity); RUN_TEST(test_job_create); } diff --git a/src/schema/controller.capnp b/src/schema/controller.capnp index 42df5db3..dd756cd7 100644 --- a/src/schema/controller.capnp +++ b/src/schema/controller.capnp @@ -531,6 +531,7 @@ struct JobSubmitData $C.mapname("job_submit_data_t") { description @7: Text $C.mapname("job_description"); resreq @8: Text; startinfo @9: JobStartInfo $C.mapname("start_info"); + fromHost @10: Text $C.mapname("from_host"); } struct JobSubmit $C.mapname("xce_job_submit_t") {