Skip to content

Commit 0d712e9

Browse files
committed
Implement scale-safe lookup calls
Add transparent Level 2 lookup split/stitch behavior across C, Go, and Rust. Cover lookup scale, malformed responses, interop, coverage, and benchmark validation.
1 parent d7cccb2 commit 0d712e9

160 files changed

Lines changed: 32744 additions & 5976 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/sow/current/SOW-0021-20260613-netipc-at-scale.md‎

Lines changed: 1155 additions & 0 deletions
Large diffs are not rendered by default.

.agents/sow/pending/SOW-0007-20260528-transparent-lookup-batch-splitting.md renamed to .agents/sow/done/SOW-0007-20260528-transparent-lookup-batch-splitting.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Status
44

5-
Status: open
5+
Status: closed
66

7-
Sub-state: follow-up tracked from SOW-0006; not yet scheduled.
7+
Sub-state: superseded before implementation by `SOW-0021 - NetIPC At Scale`.
88

99
## Requirements
1010

@@ -152,21 +152,28 @@ Pending.
152152

153153
- Created as the tracked follow-up for SOW-0006's explicitly scoped-out transparent split/stitch work.
154154

155+
### 2026-06-13
156+
157+
- Closed before implementation because `SOW-0021 - NetIPC At Scale` supersedes this narrower request-splitting SOW.
158+
- The old all-or-error oversized single-item assumption is explicitly replaced by SOW-0021's item-level outcome contract.
159+
- The old staged C/Rust/Go parity option is explicitly replaced by SOW-0021's all-language completion requirement.
160+
155161
## Validation
156162

157-
Pending.
163+
- Not executed in this SOW because the implementation and validation scope moved to SOW-0021 before this SOW started.
164+
- SOW-0021 owns the full C/Rust/Go, POSIX/Windows, interop, coverage, benchmark, and downstream vendoring validation.
158165

159166
## Outcome
160167

161-
Pending.
168+
Closed as superseded by `SOW-0021 - NetIPC At Scale`.
162169

163170
## Lessons Extracted
164171

165172
Pending.
166173

167174
## Followup
168175

169-
None yet.
176+
The active implementation and validation follow-up is SOW-0021.
170177

171178
## Regression Log
172179

‎CMakeLists.txt‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ if(NOT NETIPC_WINDOWS_RUNTIME AND NOT APPLE)
311311
target_link_libraries(test_service_extra PRIVATE
312312
netipc_service netipc_shm netipc_uds netipc_protocol Threads::Threads
313313
)
314+
target_include_directories(test_service_extra PRIVATE
315+
src/libnetdata/netipc/src/service
316+
)
314317
target_compile_definitions(test_service_extra PRIVATE NIPC_INTERNAL_TESTING=1)
315318
add_test(NAME test_service_extra COMMAND test_service_extra)
316319
set_tests_properties(test_service_extra PROPERTIES TIMEOUT 120)
@@ -568,6 +571,15 @@ if(NOT NETIPC_WINDOWS_RUNTIME AND NOT APPLE AND CARGO_EXECUTABLE)
568571
TIMEOUT 120
569572
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_c>;INTEROP_SVC_RS=${INTEROP_SVC_RS};INTEROP_SVC_GO=${INTEROP_SVC_GO}"
570573
)
574+
575+
add_test(NAME test_lookup_scale_interop
576+
COMMAND bash "${CMAKE_SOURCE_DIR}/tests/test_lookup_scale_interop.sh"
577+
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
578+
)
579+
set_tests_properties(test_lookup_scale_interop PROPERTIES
580+
TIMEOUT 180
581+
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_c>;INTEROP_SVC_RS=${INTEROP_SVC_RS};INTEROP_SVC_GO=${INTEROP_SVC_GO};NIPC_LOOKUP_SCALE_ITEMS=8192"
582+
)
571583
endif()
572584

573585
# --- L3 cache tests (Linux only) -------------------------------------------
@@ -663,6 +675,15 @@ if(NOT NETIPC_WINDOWS_RUNTIME AND NOT APPLE AND CARGO_EXECUTABLE)
663675
TIMEOUT 120
664676
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_c>;INTEROP_SVC_RS=${INTEROP_SVC_RS};INTEROP_SVC_GO=${INTEROP_SVC_GO}"
665677
)
678+
679+
add_test(NAME test_lookup_scale_shm_interop
680+
COMMAND bash "${CMAKE_SOURCE_DIR}/tests/test_lookup_scale_interop.sh"
681+
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
682+
)
683+
set_tests_properties(test_lookup_scale_shm_interop PROPERTIES
684+
TIMEOUT 180
685+
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_c>;INTEROP_SVC_RS=${INTEROP_SVC_RS};INTEROP_SVC_GO=${INTEROP_SVC_GO};NIPC_LOOKUP_SCALE_ITEMS=8192;NIPC_PROFILE=shm"
686+
)
666687
endif()
667688

668689
# --- Cross-language L3 cache interop tests (Linux only) ---------------------
@@ -964,6 +985,26 @@ if(NETIPC_WINDOWS_RUNTIME AND CARGO_EXECUTABLE)
964985
RESOURCE_LOCK win_service_interop_tests
965986
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_win_c>;INTEROP_SVC_RS=${INTEROP_SVC_WIN_RS};INTEROP_SVC_GO=${INTEROP_SVC_WIN_GO}"
966987
)
988+
989+
add_test(NAME test_lookup_scale_win_interop
990+
COMMAND bash "${CMAKE_SOURCE_DIR}/tests/test_lookup_scale_win_interop.sh"
991+
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
992+
)
993+
set_tests_properties(test_lookup_scale_win_interop PROPERTIES
994+
TIMEOUT 300
995+
RESOURCE_LOCK win_service_interop_tests
996+
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_win_c>;INTEROP_SVC_RS=${INTEROP_SVC_WIN_RS};INTEROP_SVC_GO=${INTEROP_SVC_WIN_GO};NIPC_LOOKUP_SCALE_ITEMS=8192"
997+
)
998+
999+
add_test(NAME test_lookup_scale_win_shm_interop
1000+
COMMAND bash "${CMAKE_SOURCE_DIR}/tests/test_lookup_scale_win_shm_interop.sh"
1001+
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1002+
)
1003+
set_tests_properties(test_lookup_scale_win_shm_interop PROPERTIES
1004+
TIMEOUT 300
1005+
RESOURCE_LOCK win_service_interop_tests
1006+
ENVIRONMENT "INTEROP_SVC_C=$<TARGET_FILE:interop_service_win_c>;INTEROP_SVC_RS=${INTEROP_SVC_WIN_RS};INTEROP_SVC_GO=${INTEROP_SVC_WIN_GO};NIPC_LOOKUP_SCALE_ITEMS=8192"
1007+
)
9671008
endif()
9681009

9691010
# --- Cross-language Windows L3 cache interop tests --------------------------

‎README.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ same wire contracts and typed APIs. The goal is simple:
1414
This README is a summary of the current verified state of the repository.
1515
The authoritative specifications live under [docs/](docs/README.md).
1616

17+
## Non-Negotiable Contract
18+
19+
- These rules apply to every implementation language and every service unless
20+
a future spec explicitly changes the global contract.
21+
- C, Rust, and Go must implement the same wire contract and typed behavior.
22+
- NetIPC does not do backward-compatible, forward-compatible, or best-effort
23+
decoding across method, layout, status, echoed-key, or generation drift.
24+
- Netdata plugins and NetIPC providers/clients must match the documented
25+
contract exactly. Any mismatch is rejected.
26+
- Mixed-generation stitched lookup responses are not supported.
27+
- Level 2 lookup callers pass typed semantic keys; they do not split requests
28+
around transport payload budgets and do not stitch responses manually.
29+
- Lookup `PAYLOAD_EXCEEDED` is an internal Level 2 retry signal. The client
30+
retries only the affected suffix and returns one logical response.
31+
- Lookup `OVERSIZED_ITEM` is a final per-item outcome. One oversized valid item
32+
must not invalidate the rest of the logical lookup batch.
33+
- Payload budgets and logical lookup ceilings are initialization policy.
34+
Zero-valued fields use documented defaults; consumers can override them for
35+
small IoT systems or large-memory HPC deployments.
36+
- Named defaults are defaults, not protocol hard limits. Explicit client/server
37+
initialization config is the deployment authority.
38+
1739
## Service Model
1840

1941
The public contract is service-oriented, not plugin-oriented:

‎bench/drivers/c/bench_posix.c‎

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
#define RESPONSE_BUF_SIZE 65536
4949
#define MAX_LATENCY_SAMPLES (10 * 1000 * 1000) /* 10M samples max */
5050
#define DEFAULT_DURATION 30 /* seconds */
51+
#define LOOKUP_METHOD_MAX_ITEMS 32768u
52+
#define LOOKUP_METHOD_PATH_BYTES 64u
53+
#define LOOKUP_METHOD_BUF_BYTES_PER_ITEM 256u
5154

5255
/* Profiles for SHM vs baseline */
5356
#define BENCH_PROFILE_UDS NIPC_PROFILE_BASELINE
@@ -1216,19 +1219,31 @@ static int parse_lookup_method_scenario(const char *scenario,
12161219
else
12171220
return 0;
12181221

1219-
size_t scenario_len = strlen(scenario);
1220-
if (scenario_len >= 4 && strcmp(scenario + scenario_len - 4, "-256") == 0)
1221-
*item_count = 256;
1222-
else if (scenario_len >= 3 && strcmp(scenario + scenario_len - 3, "-16") == 0)
1223-
*item_count = 16;
1224-
else if (scenario_len >= 2 && strcmp(scenario + scenario_len - 2, "-1") == 0)
1225-
*item_count = 1;
1226-
else
1222+
const char *dash = strrchr(scenario, '-');
1223+
if (!dash || dash[1] == '\0')
1224+
return 0;
1225+
1226+
char *end = NULL;
1227+
errno = 0;
1228+
unsigned long parsed = strtoul(dash + 1, &end, 10);
1229+
if (errno != 0 || !end || *end != '\0' || parsed == 0 ||
1230+
parsed > LOOKUP_METHOD_MAX_ITEMS)
12271231
return 0;
12281232

1233+
if (parsed != 1 && parsed != 16 && parsed != 256 &&
1234+
parsed != 8192 && parsed != 32768)
1235+
return 0;
1236+
1237+
*item_count = (uint32_t)parsed;
12291238
return 1;
12301239
}
12311240

1241+
static size_t lookup_method_buffer_size(uint32_t item_count)
1242+
{
1243+
size_t scaled = (size_t)item_count * LOOKUP_METHOD_BUF_BYTES_PER_ITEM + 4096u;
1244+
return scaled > RESPONSE_BUF_SIZE ? scaled : RESPONSE_BUF_SIZE;
1245+
}
1246+
12321247
static int run_lookup_method_bench(int duration_sec,
12331248
const char *scenario,
12341249
uint64_t target_rps)
@@ -1241,9 +1256,17 @@ static int run_lookup_method_bench(int duration_sec,
12411256
return 1;
12421257
}
12431258

1244-
char path_storage[256][64];
1245-
nipc_str_view_t paths[256];
1246-
uint32_t pids[256];
1259+
char (*path_storage)[LOOKUP_METHOD_PATH_BYTES] =
1260+
calloc(item_count, sizeof(*path_storage));
1261+
nipc_str_view_t *paths = calloc(item_count, sizeof(*paths));
1262+
uint32_t *pids = malloc((size_t)item_count * sizeof(*pids));
1263+
if (!path_storage || !paths || !pids) {
1264+
free(path_storage);
1265+
free(paths);
1266+
free(pids);
1267+
return 1;
1268+
}
1269+
12471270
for (uint32_t i = 0; i < item_count; i++) {
12481271
int n = snprintf(path_storage[i], sizeof(path_storage[i]),
12491272
"/sys/fs/cgroup/bench/cg-%03u", i);
@@ -1252,9 +1275,13 @@ static int run_lookup_method_bench(int duration_sec,
12521275
pids[i] = 1000u + i;
12531276
}
12541277

1255-
uint8_t *req_buf = malloc(RESPONSE_BUF_SIZE);
1256-
uint8_t *resp_buf = malloc(RESPONSE_BUF_SIZE);
1278+
size_t io_buf_size = lookup_method_buffer_size(item_count);
1279+
uint8_t *req_buf = malloc(io_buf_size);
1280+
uint8_t *resp_buf = malloc(io_buf_size);
12571281
if (!req_buf || !resp_buf) {
1282+
free(path_storage);
1283+
free(paths);
1284+
free(pids);
12581285
free(req_buf);
12591286
free(resp_buf);
12601287
return 1;
@@ -1284,12 +1311,12 @@ static int run_lookup_method_bench(int duration_sec,
12841311
nipc_error_t err;
12851312

12861313
if (is_apps) {
1287-
req_len = nipc_apps_lookup_req_encode(pids, item_count, req_buf, RESPONSE_BUF_SIZE);
1314+
req_len = nipc_apps_lookup_req_encode(pids, item_count, req_buf, io_buf_size);
12881315
if (req_len == 0) {
12891316
errors++;
12901317
continue;
12911318
}
1292-
err = nipc_dispatch_apps_lookup(req_buf, req_len, resp_buf, RESPONSE_BUF_SIZE,
1319+
err = nipc_dispatch_apps_lookup(req_buf, req_len, resp_buf, io_buf_size,
12931320
&resp_len, apps_lookup_bench_handler, &ctx);
12941321
if (err == NIPC_OK) {
12951322
nipc_apps_lookup_resp_view_t view;
@@ -1298,12 +1325,12 @@ static int run_lookup_method_bench(int duration_sec,
12981325
err = NIPC_ERR_BAD_ITEM_COUNT;
12991326
}
13001327
} else {
1301-
req_len = nipc_cgroups_lookup_req_encode(paths, item_count, req_buf, RESPONSE_BUF_SIZE);
1328+
req_len = nipc_cgroups_lookup_req_encode(paths, item_count, req_buf, io_buf_size);
13021329
if (req_len == 0) {
13031330
errors++;
13041331
continue;
13051332
}
1306-
err = nipc_dispatch_cgroups_lookup(req_buf, req_len, resp_buf, RESPONSE_BUF_SIZE,
1333+
err = nipc_dispatch_cgroups_lookup(req_buf, req_len, resp_buf, io_buf_size,
13071334
&resp_len, cgroups_lookup_bench_handler, &ctx);
13081335
if (err == NIPC_OK) {
13091336
nipc_cgroups_lookup_resp_view_t view;
@@ -1345,6 +1372,9 @@ static int run_lookup_method_bench(int duration_sec,
13451372
fprintf(stderr, "lookup-method-bench: %lu errors\n", (unsigned long)errors);
13461373

13471374
latency_free(&lr);
1375+
free(path_storage);
1376+
free(paths);
1377+
free(pids);
13481378
free(req_buf);
13491379
free(resp_buf);
13501380
return errors > 0 ? 1 : 0;

0 commit comments

Comments
 (0)