feat(job-array-one-based-index): classify every job submission first (task 2.1)

handle_jobsubmit classifies (first_jobid, array_size) before the field
checks, the before-event hook and any registry access: a tagged array
starting at index 0 is answered with the new E_XCE_ARRAY_START0 and an
ERROR log asking for the client to be upgraded (7.1, wins per 7.9);
size 0, tags 2/3, untagged multi-element submissions and arrays whose
last element exceeds 32767 (checked without addition) get -EINVAL.
Nothing is stored for a rejected submission. This also closes a crash:
a size-0 submission used to reach payload building and overflow calloc.
Existing array tests move to tagged block|1 first IDs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-01 09:44:12 +00:00
parent ef728435d4
commit e6c484a0e7
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
11 changed files with 574 additions and 19 deletions

View file

@ -2324,16 +2324,24 @@ static void test_job_array_submit_one_entry_one_continuation_across_sizes(void)
* test_job_array_submit_payload_size_independent_of_array_size above
* compares an arbitrary "large" sample (10000) against a small one. This
* test additionally exercises the REAL structural ceiling design.md relies
* on to satisfy Requirement 7 without a chunking policy: idgen() rejects
* arraySize > MAX_ARRAY_IDX + 1, so MAX_ARRAY_IDX + 1 (32768, config.h) is
* the largest array_size that can ever legally reach this function in
* production. Confirms the encoded payload at that exact ceiling is still
* identical in size to a tiny array's payload AND stays well under a sane
* absolute byte bound -- Requirement 7.1's "no single record exceeds a
* bounded size" is an absolute claim, not only a relative one. */
* on to satisfy Requirement 7 without a chunking policy: since
* job-array-one-based-index task 2.1, handle_jobsubmit's jobsubmit_classify
* admits only tagged arrays numbered from 1 whose last element is at most
* MAX_ARRAY_IDX, so MAX_ARRAY_IDX (32767, config.h) elements starting at a
* tagged block|1 first ID is the largest array that can ever legally reach
* this function in production. Confirms the encoded payload at that exact
* ceiling is still identical in size to a tiny array's payload AND stays
* well under a sane absolute byte bound -- Requirement 7.1's "no single
* record exceeds a bounded size" is an absolute claim, not only a relative
* one. */
static void test_job_array_submit_payload_size_bounded_at_max_array_idx(void)
{
const uint64_t ceiling_array_size = MAX_ARRAY_IDX + 1; /* 32768 */
const uint64_t ceiling_array_size = MAX_ARRAY_IDX; /* 32767 */
/* tagged block|1 first IDs (job-array-one-based-index task 2.1) */
const uint64_t small_first = MAKE_JOBID(
0, 0, 0, TAG_JOB_ARRAY, ((uint64_t)3 << N_ARRAY_IDX_BITS) | 1);
const uint64_t ceiling_first = MAKE_JOBID(
0, 0, 0, TAG_JOB_ARRAY, ((uint64_t)4 << N_ARRAY_IDX_BITS) | 1);
wal_entry_hdr_t hdr_small, hdr_ceiling;
uint64_t out_lsn = 0;
int rc;
@ -2344,7 +2352,7 @@ static void test_job_array_submit_payload_size_bounded_at_max_array_idx(void)
jap_notify_reset();
off_small = (off_t)g_jap.seg_offset;
rc = persist_submit_job_array_async(&g_jap, 40000, 2, &g_jap_spec,
rc = persist_submit_job_array_async(&g_jap, small_first, 2, &g_jap_spec,
&out_lsn, jap_notify_fn, &g_jap_obs);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(0,
@ -2352,17 +2360,18 @@ static void test_job_array_submit_payload_size_bounded_at_max_array_idx(void)
jap_notify_reset();
off_ceiling = (off_t)g_jap.seg_offset;
rc = persist_submit_job_array_async(&g_jap, 50000, ceiling_array_size,
&g_jap_spec, &out_lsn,
jap_notify_fn, &g_jap_obs);
rc = persist_submit_job_array_async(&g_jap, ceiling_first,
ceiling_array_size, &g_jap_spec,
&out_lsn, jap_notify_fn, &g_jap_obs);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(0,
jap_read_wal_hdr_at(&g_jap, off_ceiling, &hdr_ceiling));
TEST_ASSERT_EQUAL_UINT32_MESSAGE(hdr_small.payload_len,
hdr_ceiling.payload_len,
TEST_ASSERT_EQUAL_UINT32_MESSAGE(
hdr_small.payload_len, hdr_ceiling.payload_len,
"the payload size at the actual upstream array_size ceiling "
"(MAX_ARRAY_IDX + 1 = 32768) must be identical to a tiny array's "
"(MAX_ARRAY_IDX = 32767) must be identical to a tiny array's "
"payload size -- proving Requirement 7's bound holds at the real "
"cap, not just at an arbitrary large sample");
TEST_ASSERT_TRUE_MESSAGE(hdr_ceiling.payload_len < 4096,