feat(stk.h, module, stk): improve dependency failure logging
- Add STK_MOD_DEP_LOG_BUFFER (2048) to stk.h for the dep failure message
buffer size.
- Add stk_log_dependency_failures(index, action) to module.c. Walks all
deps for the given module, skips satisfied ones, and builds a single
log line listing every unmet dep with its reason: "not found" or
"requires <constraint>, have <version>". The action parameter
("Deferring" / "Unloading") lets call sites produce contextually
appropriate messages:
- Deferring 'test_mod_dep': unmet deps: test_mod (not found)
- Unloading 'test_mod_dep': unmet deps: test_mod (not found), renderer (requires ^2.0.0, have 1.3.0)
- Replace the silent defer at init and the vague "unmet dependencies"
cascade log in stk_poll() with calls to stk_log_dependency_failures().
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
/* Buffers */
|
/* Buffers */
|
||||||
#define STK_LOG_PREFIX_BUFFER 64
|
#define STK_LOG_PREFIX_BUFFER 64
|
||||||
#define STK_MOD_DEP_OPERATOR_BUFFER 3
|
#define STK_MOD_DEP_OPERATOR_BUFFER 3
|
||||||
|
#define STK_MOD_DEP_LOG_BUFFER 2048
|
||||||
#define STK_MOD_DESC_BUFFER 256
|
#define STK_MOD_DESC_BUFFER 256
|
||||||
#define STK_MOD_DIR_BUFFER 256
|
#define STK_MOD_DIR_BUFFER 256
|
||||||
#define STK_MOD_ID_BUFFER 64
|
#define STK_MOD_ID_BUFFER 64
|
||||||
|
|||||||
+117
@@ -206,8 +206,18 @@ unsigned char stk_validate_dependencies(size_t count)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* has_dep(i, j, ctx): return 1 if node i depends on node j, 0 otherwise.
|
||||||
|
* Used by stk_kahn_sort to abstract over loaded modules vs incoming batch.
|
||||||
|
*/
|
||||||
typedef int (*stk_dep_query_fn)(size_t i, size_t j, void *ctx);
|
typedef int (*stk_dep_query_fn)(size_t i, size_t j, void *ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Core Kahn's topological sort. Produces dependencies-first ordering.
|
||||||
|
* on_cycle is called for each node not reachable (i.e. in a cycle).
|
||||||
|
* Returns STK_MOD_INIT_SUCCESS or STK_MOD_DEP_CIRCULAR_ERROR /
|
||||||
|
* STK_MOD_REALLOC_FAILURE.
|
||||||
|
*/
|
||||||
static unsigned char stk_kahn_sort(size_t count, size_t *order,
|
static unsigned char stk_kahn_sort(size_t count, size_t *order,
|
||||||
stk_dep_query_fn has_dep, void *ctx,
|
stk_dep_query_fn has_dep, void *ctx,
|
||||||
void (*on_cycle)(size_t i))
|
void (*on_cycle)(size_t i))
|
||||||
@@ -472,6 +482,87 @@ unsigned char stk_validate_dependencies_single(size_t index)
|
|||||||
return STK_MOD_INIT_SUCCESS;
|
return STK_MOD_INIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stk_log_dependency_failures(size_t index, const char *action)
|
||||||
|
{
|
||||||
|
char buf[STK_MOD_DEP_LOG_BUFFER];
|
||||||
|
size_t d, pos, len;
|
||||||
|
int found;
|
||||||
|
int first = 1;
|
||||||
|
|
||||||
|
if (stk_modules[index].dep_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
for (d = 0; d < stk_modules[index].dep_count; d++) {
|
||||||
|
found = is_mod_loaded(stk_modules[index].deps[d].id);
|
||||||
|
|
||||||
|
if (found >= 0 &&
|
||||||
|
(!stk_modules[index].deps[d].version[0] ||
|
||||||
|
stk_validate_constraint(stk_modules[index].deps[d].version,
|
||||||
|
stk_modules[found].version)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!first && pos < sizeof(buf) - 2) {
|
||||||
|
buf[pos++] = ',';
|
||||||
|
buf[pos++] = ' ';
|
||||||
|
}
|
||||||
|
first = 0;
|
||||||
|
|
||||||
|
if (found < 0) {
|
||||||
|
len = strlen(stk_modules[index].deps[d].id);
|
||||||
|
if (pos + len + 12 < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos, stk_modules[index].deps[d].id,
|
||||||
|
len);
|
||||||
|
pos += len;
|
||||||
|
memcpy(buf + pos, " (not found)", 12);
|
||||||
|
pos += 12;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len = strlen(stk_modules[index].deps[d].id);
|
||||||
|
if (pos + len < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos, stk_modules[index].deps[d].id,
|
||||||
|
len);
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
if (pos < sizeof(buf) - 1) {
|
||||||
|
buf[pos++] = ' ';
|
||||||
|
}
|
||||||
|
buf[pos++] = '(';
|
||||||
|
len = strlen("requires ");
|
||||||
|
if (pos + len < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos, "requires ", len);
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
len = strlen(stk_modules[index].deps[d].version);
|
||||||
|
if (pos + len < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos,
|
||||||
|
stk_modules[index].deps[d].version, len);
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
len = strlen(", have ");
|
||||||
|
if (pos + len < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos, ", have ", len);
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
len = strlen(stk_modules[found].version);
|
||||||
|
if (pos + len < sizeof(buf)) {
|
||||||
|
memcpy(buf + pos, stk_modules[found].version,
|
||||||
|
len);
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
if (pos < sizeof(buf) - 1)
|
||||||
|
buf[pos++] = ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf[pos] = '\0';
|
||||||
|
stk_log(STK_LOG_WARN, "%s '%s': unmet deps: %s", action,
|
||||||
|
stk_modules[index].id, buf);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char stk_module_load(const char *path, int index)
|
unsigned char stk_module_load(const char *path, int index)
|
||||||
{
|
{
|
||||||
unsigned char result;
|
unsigned char result;
|
||||||
@@ -631,6 +722,11 @@ static int stk_batch_has_dep(size_t i, size_t j, void *ctx)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort file_indices[] (length n) so that within the batch, modules whose ids
|
||||||
|
* appear as dependencies of others come first. Uses already-copied tmp files
|
||||||
|
* to read dep symbols. Falls back to original order if sort fails.
|
||||||
|
*/
|
||||||
void stk_sort_load_order(int *file_indices, size_t n,
|
void stk_sort_load_order(int *file_indices, size_t n,
|
||||||
char (*file_names)[STK_PATH_MAX], const char *tmp_dir)
|
char (*file_names)[STK_PATH_MAX], const char *tmp_dir)
|
||||||
{
|
{
|
||||||
@@ -665,6 +761,12 @@ cleanup:
|
|||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand indices[0..]*in_count to include all loaded modules that transitively
|
||||||
|
* depend on any module already in the set. Writes the expanded set back into
|
||||||
|
* indices[] and updates *out_count. indices[] must have capacity module_count.
|
||||||
|
* Returns 1 if any new dependents were added, 0 otherwise.
|
||||||
|
*/
|
||||||
void stk_collect_dependents(size_t *indices, size_t *count)
|
void stk_collect_dependents(size_t *indices, size_t *count)
|
||||||
{
|
{
|
||||||
size_t i, d;
|
size_t i, d;
|
||||||
@@ -673,6 +775,7 @@ void stk_collect_dependents(size_t *indices, size_t *count)
|
|||||||
do {
|
do {
|
||||||
changed = 0;
|
changed = 0;
|
||||||
for (i = 0; i < module_count; i++) {
|
for (i = 0; i < module_count; i++) {
|
||||||
|
/* skip if already in the set */
|
||||||
in_set = 0;
|
in_set = 0;
|
||||||
{
|
{
|
||||||
size_t k;
|
size_t k;
|
||||||
@@ -686,6 +789,7 @@ void stk_collect_dependents(size_t *indices, size_t *count)
|
|||||||
if (in_set)
|
if (in_set)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* check if any of its deps are in the set */
|
||||||
for (d = 0; d < stk_modules[i].dep_count; d++) {
|
for (d = 0; d < stk_modules[i].dep_count; d++) {
|
||||||
int dep_idx =
|
int dep_idx =
|
||||||
is_mod_loaded(stk_modules[i].deps[d].id);
|
is_mod_loaded(stk_modules[i].deps[d].id);
|
||||||
@@ -708,6 +812,11 @@ void stk_collect_dependents(size_t *indices, size_t *count)
|
|||||||
} while (changed);
|
} while (changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort indices[] (length n) so that dependents come before their dependencies.
|
||||||
|
* This is the reverse of topological order. indices[] is sorted in-place.
|
||||||
|
* Falls back to reverse-index order if topo sort fails or alloc fails.
|
||||||
|
*/
|
||||||
void stk_sort_unload_order(size_t *indices, size_t n)
|
void stk_sort_unload_order(size_t *indices, size_t n)
|
||||||
{
|
{
|
||||||
size_t *topo = NULL;
|
size_t *topo = NULL;
|
||||||
@@ -727,6 +836,10 @@ void stk_sort_unload_order(size_t *indices, size_t n)
|
|||||||
if (stk_topo_sort(module_count, topo) != STK_MOD_INIT_SUCCESS)
|
if (stk_topo_sort(module_count, topo) != STK_MOD_INIT_SUCCESS)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* topo[] is dependencies-first. Walk it in reverse to get
|
||||||
|
* dependents-first, picking only indices that are in our set.
|
||||||
|
*/
|
||||||
k = 0;
|
k = 0;
|
||||||
for (i = module_count; i > 0; --i) {
|
for (i = module_count; i > 0; --i) {
|
||||||
size_t mod = topo[i - 1];
|
size_t mod = topo[i - 1];
|
||||||
@@ -753,6 +866,7 @@ void stk_sort_unload_order(size_t *indices, size_t n)
|
|||||||
fallback:
|
fallback:
|
||||||
free(topo);
|
free(topo);
|
||||||
free(result);
|
free(result);
|
||||||
|
/* reverse index order: higher indices (dependents) first */
|
||||||
for (i = 0; i < n / 2; i++) {
|
for (i = 0; i < n / 2; i++) {
|
||||||
size_t tmp = indices[i];
|
size_t tmp = indices[i];
|
||||||
indices[i] = indices[n - 1 - i];
|
indices[i] = indices[n - 1 - i];
|
||||||
@@ -777,6 +891,7 @@ void stk_module_unload_all(void)
|
|||||||
stk_module_unload(order[i]);
|
stk_module_unload(order[i]);
|
||||||
free(order);
|
free(order);
|
||||||
} else {
|
} else {
|
||||||
|
/* fallback: reverse index order */
|
||||||
for (i = module_count; i > 0; --i)
|
for (i = module_count; i > 0; --i)
|
||||||
stk_module_unload(i - 1);
|
stk_module_unload(i - 1);
|
||||||
}
|
}
|
||||||
@@ -828,6 +943,7 @@ void stk_pending_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count)
|
|||||||
if (!paths || count == 0)
|
if (!paths || count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* First pass: overwrite existing entries and count truly new ones */
|
||||||
new_count = 0;
|
new_count = 0;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
@@ -863,6 +979,7 @@ void stk_pending_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count)
|
|||||||
free(stk_pending);
|
free(stk_pending);
|
||||||
stk_pending = new_pending;
|
stk_pending = new_pending;
|
||||||
|
|
||||||
|
/* Second pass: append only the truly new ones */
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
extract_module_id(paths[i], incoming_id);
|
extract_module_id(paths[i], incoming_id);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ size_t stk_module_count(void);
|
|||||||
unsigned char stk_module_preload(const char *path, int index);
|
unsigned char stk_module_preload(const char *path, int index);
|
||||||
unsigned char stk_module_activate(size_t index);
|
unsigned char stk_module_activate(size_t index);
|
||||||
unsigned char stk_validate_dependencies_single(size_t index);
|
unsigned char stk_validate_dependencies_single(size_t index);
|
||||||
|
void stk_log_dependency_failures(size_t index, const char *action);
|
||||||
void stk_module_discard(size_t index);
|
void stk_module_discard(size_t index);
|
||||||
unsigned char stk_module_load(const char *path, int index);
|
unsigned char stk_module_load(const char *path, int index);
|
||||||
unsigned char stk_module_load_init(const char *path, int index);
|
unsigned char stk_module_load_init(const char *path, int index);
|
||||||
@@ -130,9 +131,12 @@ static void stk_log_modules(void)
|
|||||||
unsigned char stk_init(void)
|
unsigned char stk_init(void)
|
||||||
{
|
{
|
||||||
char (*files)[STK_PATH_MAX] = NULL;
|
char (*files)[STK_PATH_MAX] = NULL;
|
||||||
size_t file_count, i, successful_loads = 0;
|
char (*test_scan)[STK_PATH_MAX];
|
||||||
|
size_t file_count, i, j, write, successful_loads = 0;
|
||||||
|
size_t index, test_count;
|
||||||
char full_path[STK_PATH_MAX_OS];
|
char full_path[STK_PATH_MAX_OS];
|
||||||
char tmp_path[STK_PATH_MAX_OS];
|
char tmp_path[STK_PATH_MAX_OS];
|
||||||
|
char mod_tmp_path[STK_PATH_MAX_OS];
|
||||||
int load_result;
|
int load_result;
|
||||||
unsigned char dep_result;
|
unsigned char dep_result;
|
||||||
size_t *order = NULL;
|
size_t *order = NULL;
|
||||||
@@ -140,9 +144,6 @@ unsigned char stk_init(void)
|
|||||||
platform_mkdir(stk_mod_dir);
|
platform_mkdir(stk_mod_dir);
|
||||||
build_path(stk_tmp_dir, sizeof(stk_tmp_dir), stk_mod_dir, stk_tmp_name);
|
build_path(stk_tmp_dir, sizeof(stk_tmp_dir), stk_mod_dir, stk_tmp_name);
|
||||||
if (platform_mkdir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) {
|
if (platform_mkdir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
char (*test_scan)[STK_PATH_MAX];
|
|
||||||
size_t test_count;
|
|
||||||
|
|
||||||
test_scan =
|
test_scan =
|
||||||
platform_directory_init_scan(stk_tmp_dir, &test_count);
|
platform_directory_init_scan(stk_tmp_dir, &test_count);
|
||||||
if (test_scan)
|
if (test_scan)
|
||||||
@@ -197,42 +198,32 @@ unsigned char stk_init(void)
|
|||||||
if (module_count == 0)
|
if (module_count == 0)
|
||||||
goto scanned;
|
goto scanned;
|
||||||
|
|
||||||
{
|
|
||||||
size_t j, write;
|
|
||||||
char mod_tmp_path[STK_PATH_MAX_OS];
|
|
||||||
|
|
||||||
order = malloc(module_count * sizeof(size_t));
|
order = malloc(module_count * sizeof(size_t));
|
||||||
if (order) {
|
if (order) {
|
||||||
dep_result = stk_topo_sort(module_count, order);
|
dep_result = stk_topo_sort(module_count, order);
|
||||||
if (dep_result != STK_MOD_INIT_SUCCESS)
|
if (dep_result != STK_MOD_INIT_SUCCESS)
|
||||||
stk_log(STK_LOG_ERROR,
|
stk_log(STK_LOG_ERROR, "Dependency sort failed: %s",
|
||||||
"Dependency sort failed: %s",
|
|
||||||
stk_error_string(dep_result));
|
stk_error_string(dep_result));
|
||||||
} else {
|
|
||||||
order = malloc(module_count * sizeof(size_t));
|
|
||||||
if (order)
|
|
||||||
for (j = 0; j < module_count; j++)
|
|
||||||
order[j] = j;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < module_count; j++) {
|
for (j = 0; j < module_count; j++) {
|
||||||
size_t idx = order ? order[j] : j;
|
index = order ? order[j] : j;
|
||||||
dep_result = stk_validate_dependencies_single(idx);
|
dep_result = stk_validate_dependencies_single(index);
|
||||||
if (dep_result != STK_MOD_INIT_SUCCESS) {
|
if (dep_result != STK_MOD_INIT_SUCCESS) {
|
||||||
|
stk_log_dependency_failures(index, "Deferring");
|
||||||
build_path(mod_tmp_path, sizeof(mod_tmp_path),
|
build_path(mod_tmp_path, sizeof(mod_tmp_path),
|
||||||
stk_tmp_dir, stk_modules[idx].id);
|
stk_tmp_dir, stk_modules[index].id);
|
||||||
strncat(mod_tmp_path, STK_MODULE_EXT,
|
strncat(mod_tmp_path, STK_MODULE_EXT,
|
||||||
sizeof(mod_tmp_path) -
|
sizeof(mod_tmp_path) - strlen(mod_tmp_path) -
|
||||||
strlen(mod_tmp_path) - 1);
|
1);
|
||||||
stk_pending_add(mod_tmp_path);
|
stk_pending_add(mod_tmp_path);
|
||||||
stk_module_discard(idx);
|
stk_module_discard(index);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stk_module_activate(idx) != STK_MOD_INIT_SUCCESS) {
|
if (stk_module_activate(index) != STK_MOD_INIT_SUCCESS) {
|
||||||
stk_log(STK_LOG_ERROR,
|
stk_log(STK_LOG_ERROR, "Failed to init module %s",
|
||||||
"Failed to init module %s",
|
stk_modules[index].id);
|
||||||
stk_modules[idx].id);
|
stk_module_discard(index);
|
||||||
stk_module_discard(idx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +241,6 @@ unsigned char stk_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
module_count = write;
|
module_count = write;
|
||||||
}
|
|
||||||
|
|
||||||
scanned:
|
scanned:
|
||||||
watch_handle = platform_directory_watch_start(stk_mod_dir);
|
watch_handle = platform_directory_watch_start(stk_mod_dir);
|
||||||
@@ -581,9 +571,7 @@ validate_deps:
|
|||||||
|
|
||||||
for (j = 0; j < cascade_count; j++) {
|
for (j = 0; j < cascade_count; j++) {
|
||||||
index = cascade_indices[j];
|
index = cascade_indices[j];
|
||||||
stk_log(STK_LOG_WARN,
|
stk_log_dependency_failures(index, "Unloading");
|
||||||
"Unloading '%s': unmet dependencies",
|
|
||||||
stk_modules[index].id);
|
|
||||||
build_path(cascade_tmp_path, sizeof(cascade_tmp_path),
|
build_path(cascade_tmp_path, sizeof(cascade_tmp_path),
|
||||||
stk_tmp_dir, stk_modules[index].id);
|
stk_tmp_dir, stk_modules[index].id);
|
||||||
strncat(cascade_tmp_path, STK_MODULE_EXT,
|
strncat(cascade_tmp_path, STK_MODULE_EXT,
|
||||||
|
|||||||
Reference in New Issue
Block a user