Merge branch 'feat/parity-f4' into feat/parity-next

This commit is contained in:
2026-09-22 23:20:21 +02:00
4 changed files with 103 additions and 26 deletions
+53 -2
View File
@@ -1148,6 +1148,43 @@ send_fail:
static int scan_directory_multithreaded(void* pipeline_context) {
PipelineContextSender* context = (PipelineContextSender*)pipeline_context;
protocol_session_bind(&context->allocation_session);
if (context->prescan_chunks != NULL) {
/* --delete-before replays the pre-scan that built the early keep-set as the
data pass (rsync builds one file list). Feed the retained chunks straight
into the pipeline instead of re-reading the source, so a file created
after the pre-scan is neither transferred nor kept. The chunk also
carries the directory times captured by that scan (there is no later
scan), so no scanner is created here. */
bool failed = false;
for (int i = 0; i < context->prescan_chunks->size; i++) {
Chunk* chunk = (Chunk*)context->prescan_chunks->items[i];
/* Move ownership out of the retained list so a cleanup here never
double-frees a chunk the queue now owns. */
context->prescan_chunks->items[i] = NULL;
if (chunk == NULL)
continue;
if (!queue_enqueue_multithreaded_cancel(
context->queue_scanner, chunk, &context->mutex_scanner,
&context->condition_not_empty_scanner, &context->condition_not_full_scanner,
&context->cancelled)) {
chunk_destroy(chunk);
failed = true;
break;
}
}
mtx_lock(&context->mutex_scanner);
context->scanner_done = true;
cnd_broadcast(&context->condition_not_empty_scanner);
cnd_broadcast(&context->condition_not_full_scanner);
mtx_unlock(&context->mutex_scanner);
if (failed) {
pipeline_cancel(context);
protocol_session_unbind();
return thrd_error;
}
protocol_session_unbind();
return thrd_success;
}
PreparedScanner prepared;
/* -j/--threads=N sizes the parallel scanner's worker pool; 0 (bare -j) lets
* the scanner apply its built-in default. */
@@ -2032,13 +2069,27 @@ int send_files_multithreaded(Config* config) {
if (prepared_ok)
prepared.options.plan_dirs = context->plan_dirs;
} else {
/* --delete-before: retain the pre-scan chunks as the pipeline's data
pass (rsync's single file list) so a source file created after the
scan is not transferred. No later scan runs, so this pass must also
capture the deferred directory times and the --stats directory
count. */
context->manifest = array_list_create(free);
prepared_ok = prepared_ok && context->manifest != NULL;
context->prescan_chunks = array_list_create(chunk_destroy);
prepared_ok = prepared_ok && context->manifest != NULL && context->prescan_chunks != NULL;
if (prepared_ok) {
prepared.options.dir_entries = context->dir_entries;
prepared.options.dir_entries_mutex = &context->dir_entries_mutex;
prepared.options.dir_count = config->stats ? &context->dir_count : NULL;
if (!append_implied_dir_times(config, context->dir_entries))
prepared_ok = false;
}
}
bool prebuilt =
prepared_ok &&
scan_paths_only(config, &prepared.options, context->manifest, context->delete_plans,
&context->scan_had_io_error, &pre_scan_non_dir, NULL, false);
&context->scan_had_io_error, &pre_scan_non_dir, context->prescan_chunks,
context->prescan_chunks != NULL);
prepared_scanner_destroy(&prepared);
if (per_dir && prebuilt) {
const char* walk_root = delete_plan_walk_root(config, context->synced_dirs);
+3
View File
@@ -37,6 +37,7 @@ PipelineContextSender* pipeline_context_sender_create(Config* config, Queue* que
context->scan_had_io_error = false;
context->remove_source_files = NULL;
context->early_delete = false;
context->prescan_chunks = NULL;
context->delete_plans = NULL;
context->delete_suppressed = false;
context->scan_stopped_early = false;
@@ -194,6 +195,8 @@ void pipeline_context_sender_destroy(PipelineContextSender* context) {
if (context->manifest) {
array_list_delete(context->manifest);
}
if (context->prescan_chunks)
array_list_delete(context->prescan_chunks);
if (context->delete_plans)
delete_plan_sender_destroy(context->delete_plans);
if (context->excluded_paths)
+7
View File
@@ -78,6 +78,13 @@ typedef struct {
path-only pre-scan on the calling thread and the pipeline scanner must not
append to it. Set once before the worker threads start. */
bool early_delete;
/* --delete-before: the path-only pre-scan that built the early keep-set,
retained as the pipeline's file list (owning Chunk*; consumed and NULLed by
the scanner thread) so the data pass replays rsync's single file list
instead of re-reading the source. NULL in every other mode, where the
scanner thread scans normally. Set once before the worker threads start
and freed with the context. */
ArrayList* prescan_chunks;
/* Non-NULL for --delete-during/--delete-delay: the per-directory plan set
prebuilt by the path-only pre-scan on the calling thread. The sender
thread transmits the root plan before any data and the remaining plans