Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ codebase-memory-mcp config reset auto_index # reset to default
| `CBM_CACHE_DIR` | `~/.cache/codebase-memory-mcp` | Override the database storage directory. All project indexes and config are stored here. |
| `CBM_DIAGNOSTICS` | `false` | Set to `1` or `true` to enable periodic diagnostics output to `/tmp/cbm-diagnostics-<pid>.json`. |
| `CBM_DOWNLOAD_URL` | *(GitHub releases)* | Override the download URL for updates. Used for testing or self-hosted deployments. |
| `CBM_WORKERS` | *(detected)* | Override the parallel-indexing worker count returned by `cbm_default_worker_count`. Useful inside containers where `sysconf(_SC_NPROCESSORS_ONLN)` reports host CPUs rather than the cgroup's effective quota. Range 1–256; invalid values are ignored with a warning. |

```bash
# Store indexes in a custom directory
Expand Down
18 changes: 17 additions & 1 deletion src/foundation/system_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
*/
#include "foundation/constants.h"

enum { DEFAULT_CORES = 1, MIN_WORKERS = 1 };
enum { DEFAULT_CORES = 1, MIN_WORKERS = 1, CBM_WORKERS_MAX = 256 };
#include "foundation/log.h"
#include "foundation/platform.h"
#include <stdint.h> // uint64_t
#include <stdlib.h> // strtol
#include <string.h>

#ifdef _WIN32
Expand Down Expand Up @@ -168,6 +170,20 @@ cbm_system_info_t cbm_system_info(void) {
}

int cbm_default_worker_count(bool initial) {
/* CBM_WORKERS env override (clamped to [1, CBM_WORKERS_MAX]).
* Useful inside containers where sysconf(_SC_NPROCESSORS_ONLN)
* reports host CPUs rather than the cgroup's effective CPU quota.
* Same precedence shape as other CBM_* env overrides:
* explicit override > implicit detection. */
char buf[CBM_SZ_32];
if (cbm_safe_getenv("CBM_WORKERS", buf, sizeof(buf), NULL) != NULL) {
long n = strtol(buf, NULL, CBM_DECIMAL_BASE);
if (n >= MIN_WORKERS && n <= CBM_WORKERS_MAX) {
return (int)n;
}
cbm_log_warn("workers.env.invalid", "value", buf, "fallback", "sysconf");
}

cbm_system_info_t info = cbm_system_info();
if (initial) {
/* Use all cores for initial indexing — user is waiting */
Expand Down
55 changes: 55 additions & 0 deletions tests/test_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
#include "test_framework.h"
#include "../src/foundation/platform.h"
#include <stdlib.h> /* setenv, unsetenv */
#include <unistd.h>

TEST(platform_now_ns) {
Expand Down Expand Up @@ -68,6 +69,57 @@ TEST(platform_mmap_nonexistent) {
PASS();
}

/*
* CBM_WORKERS env override for cbm_default_worker_count.
*
* Containers running cbm on a host with more CPUs than the cgroup's
* effective quota currently see ~host_cpu workers spawned because
* sysconf(_SC_NPROCESSORS_ONLN) is not cgroup-aware (see GitHub
* issue for the cgroup-detection ask). CBM_WORKERS is the smaller,
* explicit-override path that ships independently.
*/
TEST(platform_default_workers_env_override) {
setenv("CBM_WORKERS", "4", 1);
int n = cbm_default_worker_count(true);
ASSERT_EQ(n, 4);
/* initial=false should also honor the explicit override. */
int m = cbm_default_worker_count(false);
ASSERT_EQ(m, 4);
unsetenv("CBM_WORKERS");
PASS();
}

TEST(platform_default_workers_env_invalid) {
/* Out-of-range values (< 1 or > 256) and non-numeric strings
* fall back to the sysconf-derived default. */
int baseline = cbm_default_worker_count(true);
ASSERT_GT(baseline, 0);

setenv("CBM_WORKERS", "0", 1);
ASSERT_EQ(cbm_default_worker_count(true), baseline);

setenv("CBM_WORKERS", "-1", 1);
ASSERT_EQ(cbm_default_worker_count(true), baseline);

setenv("CBM_WORKERS", "9999", 1);
ASSERT_EQ(cbm_default_worker_count(true), baseline);

setenv("CBM_WORKERS", "not-a-number", 1);
ASSERT_EQ(cbm_default_worker_count(true), baseline);

unsetenv("CBM_WORKERS");
PASS();
}

TEST(platform_default_workers_env_unset) {
/* When CBM_WORKERS is unset the result matches today's behaviour
* (info.total_cores for initial=true, perf_cores-1 for false). */
unsetenv("CBM_WORKERS");
cbm_system_info_t info = cbm_system_info();
ASSERT_EQ(cbm_default_worker_count(true), info.total_cores);
PASS();
}

SUITE(platform) {
RUN_TEST(platform_now_ns);
RUN_TEST(platform_now_ms);
Expand All @@ -77,4 +129,7 @@ SUITE(platform) {
RUN_TEST(platform_file_size);
RUN_TEST(platform_mmap);
RUN_TEST(platform_mmap_nonexistent);
RUN_TEST(platform_default_workers_env_override);
RUN_TEST(platform_default_workers_env_invalid);
RUN_TEST(platform_default_workers_env_unset);
}