Compare commits

...
1 Commits
Author SHA1 Message Date
Roman Tarasov 24fba2be21 Reduce scanner directory watchers by default 2026-06-03 21:13:07 +03:00
5 changed files with 82 additions and 20 deletions

No files matched your search

+2
View File
@@ -61,6 +61,8 @@ Supported keys (all optional):
- `image_rw=<image_filename>` (repeatable; force read-write mode for this image filename)
- `image_sector=<image_filename>:<sector_size>` (repeatable; force sector size for this image filename)
- `scan_depth=<1..2>` (`1` = scan only first-level subfolders, `2` = also scan one additional nested level; default: `1`)
- `watch_subdirs=1|0` (`1` keeps vnode watchers on scan root subdirectories; default: `0`)
- `watch_image_files=1|0` (`1` keeps vnode watchers on discovered image files; default: `1`)
- `recursive_scan=1|0` (deprecated compatibility key; `1` forces `scan_depth=2`)
- `scan_interval_seconds=<1..3600>` (full scan loop interval; default: `15`)
- `stability_wait_seconds=<0..3600>` (minimum source age before processing; default: `10`)
+12
View File
@@ -45,6 +45,18 @@
# Default: 1
# scan_depth=1
# Directory watcher granularity:
# 1 -> keep vnode watchers on scan root subdirectories
# 0 -> watch only scan roots/parents and rely on targeted/full scans for children
# Default: 0
# watch_subdirs=0
# Image file watcher granularity:
# 1 -> keep vnode watchers on discovered image files
# 0 -> detect image file changes through targeted/full scans
# Default: 1
# watch_image_files=1
# Legacy compatibility:
# recursive_scan=1 forces scan_depth=2
# Default: disabled
+2
View File
@@ -116,6 +116,8 @@ typedef struct runtime_config {
bool kstuff_game_auto_toggle;
bool kstuff_crash_detection_enabled;
bool legacy_recursive_scan_forced;
bool watch_subdirs;
bool watch_image_files;
char global_fakelib_path[MAX_PATH];
uint32_t global_fakelib_exclude_title_count;
char global_fakelib_exclude_title_ids[MAX_FAKELIB_EXCLUDE_RULES][MAX_TITLE_ID];
+23
View File
@@ -257,6 +257,8 @@ static void init_runtime_config_defaults(runtime_config_state_t *state) {
state->cfg.kstuff_game_auto_toggle = true;
state->cfg.kstuff_crash_detection_enabled = true;
state->cfg.legacy_recursive_scan_forced = false;
state->cfg.watch_subdirs = false;
state->cfg.watch_image_files = true;
(void)strlcpy(state->cfg.global_fakelib_path, DEFAULT_GLOBAL_FAKELIB_PATH,
sizeof(state->cfg.global_fakelib_path));
state->cfg.scan_depth = DEFAULT_SCAN_DEPTH;
@@ -1241,6 +1243,24 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
continue;
}
if (strcasecmp(key, "watch_subdirs") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
continue;
}
state->cfg.watch_subdirs = bval;
continue;
}
if (strcasecmp(key, "watch_image_files") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
continue;
}
state->cfg.watch_image_files = bval;
continue;
}
if (strcasecmp(key, "backport_fakelib") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
@@ -1488,6 +1508,7 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
"legacy_recursive_scan_forced=%d backport_fakelib=%d "
"global_fakelib=%d global_fakelib_priority=%s "
"global_fakelib_path=%s global_fakelib_exclude=%u "
"watch_subdirs=%d watch_image_files=%d "
"kstuff_game_auto_toggle=%d kstuff_crash_detection=%d "
"kstuff_pause_delay_image_s=%u kstuff_pause_delay_direct_s=%u "
"exfat_backend=%s ufs_backend=%s "
@@ -1505,6 +1526,8 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
state->cfg.global_fakelib_mount_first ? "game" : "global",
state->cfg.global_fakelib_path,
state->cfg.global_fakelib_exclude_title_count,
state->cfg.watch_subdirs ? 1 : 0,
state->cfg.watch_image_files ? 1 : 0,
state->cfg.kstuff_game_auto_toggle ? 1 : 0,
state->cfg.kstuff_crash_detection_enabled ? 1 : 0,
state->cfg.kstuff_pause_delay_image_seconds,
+43 -20
View File
@@ -240,7 +240,12 @@ static bool fakelib_runtime_config_changed(const runtime_config_t *old_cfg,
static uint32_t scanner_config_topology_hash(void) {
uint32_t hash = 2166136261u;
int scan_path_count = get_scan_path_count();
uint32_t values[] = {runtime_config()->scan_depth, (uint32_t)scan_path_count};
uint32_t values[] = {
runtime_config()->scan_depth,
runtime_config()->watch_subdirs ? 1u : 0u,
runtime_config()->watch_image_files ? 1u : 0u,
(uint32_t)scan_path_count,
};
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
for (unsigned shift = 0; shift < 32u; shift += 8u) {
@@ -584,6 +589,7 @@ static bool resolve_watch_tree_rebuild_target(const scanner_watch_entry_t *entry
typedef struct {
int kq;
int scan_root_index;
bool watch_subdirs;
} register_watch_tree_ctx_t;
static sm_scan_tree_dir_visit_t register_watch_directory_visit(
@@ -592,9 +598,11 @@ static sm_scan_tree_dir_visit_t register_watch_directory_visit(
scanner_watch_kind_t kind =
(depth_from_root == 0u) ? SCANNER_WATCH_SCAN_ROOT
: SCANNER_WATCH_SCAN_SUBDIR;
if (!register_scanner_watch_entry(ctx->kq, ctx->scan_root_index, dir_path, kind,
(uint8_t)depth_from_root)) {
return SM_SCAN_TREE_DIR_ABORT;
if (depth_from_root == 0u || ctx->watch_subdirs) {
if (!register_scanner_watch_entry(ctx->kq, ctx->scan_root_index, dir_path,
kind, (uint8_t)depth_from_root)) {
return SM_SCAN_TREE_DIR_ABORT;
}
}
return SM_SCAN_TREE_DIR_DESCEND;
@@ -637,19 +645,28 @@ static bool rebuild_scan_root_watch_tree(int kq, int scan_root_index) {
return true;
}
unsigned int scan_depth = get_scan_depth_for_root(scan_root);
register_watch_tree_ctx_t walk_ctx = {
.kq = kq,
.scan_root_index = scan_root_index,
};
sm_scan_tree_callbacks_t callbacks = {
.on_directory = register_watch_directory_visit,
.on_image_file = register_watch_image_visit,
};
if (!sm_scan_tree_walk(scan_root, scan_root, 0u, scan_depth, &callbacks,
&walk_ctx)) {
return false;
const runtime_config_t *cfg = runtime_config();
if (!cfg->watch_subdirs && !cfg->watch_image_files) {
if (!register_scanner_watch_entry(kq, scan_root_index, scan_root,
SCANNER_WATCH_SCAN_ROOT, 0u)) {
return false;
}
} else {
unsigned int scan_depth = get_scan_depth_for_root(scan_root);
register_watch_tree_ctx_t walk_ctx = {
.kq = kq,
.scan_root_index = scan_root_index,
.watch_subdirs = cfg->watch_subdirs,
};
sm_scan_tree_callbacks_t callbacks = {
.on_directory = register_watch_directory_visit,
.on_image_file =
cfg->watch_image_files ? register_watch_image_visit : NULL,
};
if (!sm_scan_tree_walk(scan_root, scan_root, 0u, scan_depth, &callbacks,
&walk_ctx)) {
return false;
}
}
char backport_root[MAX_PATH];
@@ -690,10 +707,15 @@ static bool rebuild_scan_root_watch_subtree(int kq, int scan_root_index,
return true;
}
unsigned int scan_depth = get_scan_depth_for_root(scan_root);
if (!remove_scan_root_watch_entries_for_path(scan_root_index, rebuild_path))
return false;
const runtime_config_t *cfg = runtime_config();
if (!cfg->watch_subdirs && !cfg->watch_image_files) {
clear_scan_root_watch_tree_state(scan_root_index);
return true;
}
unsigned int scan_depth = get_scan_depth_for_root(scan_root);
if (rebuild_depth > scan_depth) {
clear_scan_root_watch_tree_state(scan_root_index);
return true;
@@ -702,10 +724,11 @@ static bool rebuild_scan_root_watch_subtree(int kq, int scan_root_index,
register_watch_tree_ctx_t walk_ctx = {
.kq = kq,
.scan_root_index = scan_root_index,
.watch_subdirs = cfg->watch_subdirs,
};
sm_scan_tree_callbacks_t callbacks = {
.on_directory = register_watch_directory_visit,
.on_image_file = register_watch_image_visit,
.on_image_file = cfg->watch_image_files ? register_watch_image_visit : NULL,
};
if (!sm_scan_tree_walk(scan_root, rebuild_path, rebuild_depth,
scan_depth - rebuild_depth, &callbacks, &walk_ctx)) {