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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
Rongsong Shen 2026-08-24 15:14:42 +00:00
parent fe8818b19b
commit 363709b032
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
4 changed files with 65 additions and 6 deletions

View file

@ -333,6 +333,7 @@ typedef struct {
char* user_group;
char* job_description;
char* resreq;
char* from_host;
} job_submit_data_t;
typedef struct {

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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") {