test(delete): differential + timing regression tests for per-directory delete plans
- Compare --delete-during/--delete-delay final state against rsync 3.4.1. - Force a mid-transfer failure through a byte-slicing proxy: --delete-during has removed the processed directory's extra, --delete-delay has not. - Create a destination entry while the transfer is in flight: it survives --delete-delay's snapshot but is removed by --delete-after's fresh end scan. - Cover the --delete-delay type-conflict case now matching rsync.
This commit is contained in:
@@ -1189,7 +1189,8 @@ static int send_chunk_delete_plans(Client* client, DeletePlanSender* plans, cons
|
||||
File* f = chunk->items[i];
|
||||
if (!f)
|
||||
continue;
|
||||
if (delete_plan_send_for_path(client->file_descriptor, plans, file_wire_path(f), f->is_dir) != 0)
|
||||
if (delete_plan_send_for_path(client->file_descriptor, plans, file_wire_path(f), f->is_dir) !=
|
||||
0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -259,8 +259,7 @@ int receiver_process(Config* config, int file_descriptor, const ReceiverSink* si
|
||||
the whole transfer succeeded. See receiver_process_pending() for how the -m
|
||||
receiver defers that commit until its disk writer has drained. */
|
||||
int receiver_process_pending(Config* config, int file_descriptor, const ReceiverSink* sink,
|
||||
DeleteManifest** pending_manifest,
|
||||
DeletePlanSession** pending_plans) {
|
||||
DeleteManifest** pending_manifest, DeletePlanSession** pending_plans) {
|
||||
Status status;
|
||||
if (!receive_status(file_descriptor, &status))
|
||||
return -1;
|
||||
|
||||
@@ -167,8 +167,8 @@ int receive_thread(void* pipeline_context) {
|
||||
|
||||
ReceiverSink sink = {
|
||||
receiver_enqueue_file, context, false, false, NULL, receiver_pipeline_note_delete_limit};
|
||||
if (receiver_process_pending((Config*)config, file_descriptor, &sink,
|
||||
&context->deferred_manifest, &context->deferred_plans) != 0) {
|
||||
if (receiver_process_pending((Config*)config, file_descriptor, &sink, &context->deferred_manifest,
|
||||
&context->deferred_plans) != 0) {
|
||||
receiver_thread_fail(context);
|
||||
protocol_session_unbind();
|
||||
return thrd_error;
|
||||
|
||||
+1
-2
@@ -966,8 +966,7 @@ void handler(int file_descriptor) {
|
||||
arrived; with the disk writer drained, commit the deferred removals.
|
||||
--delete-during already applied its plans on the receive thread. */
|
||||
if (context->deferred_plans) {
|
||||
DeleteCommitResult deletion =
|
||||
delete_plan_session_commit(context->deferred_plans, config);
|
||||
DeleteCommitResult deletion = delete_plan_session_commit(context->deferred_plans, config);
|
||||
if (deletion == DELETE_COMMIT_ERROR) {
|
||||
transfer_ok = false;
|
||||
} else if (deletion == DELETE_COMMIT_LIMIT_REACHED) {
|
||||
|
||||
@@ -484,7 +484,8 @@ typedef struct PlanSkips {
|
||||
int count;
|
||||
} PlanSkips;
|
||||
|
||||
static bool build_plan_skips(const Config* config, const DeletePlanSession* session, PlanSkips* out) {
|
||||
static bool build_plan_skips(const Config* config, const DeletePlanSession* session,
|
||||
PlanSkips* out) {
|
||||
out->entries = NULL;
|
||||
out->count = 0;
|
||||
int count = (config->delay_updates ? 1 : 0) + config->basis_count +
|
||||
@@ -569,8 +570,8 @@ static bool process_extra_dir(int dirfd, const char* name, const char* child_rel
|
||||
return false;
|
||||
}
|
||||
bool survives = false;
|
||||
bool ok = process_children(childfd, child_rel, NULL, NULL, false, force_now, skips, session,
|
||||
&survives);
|
||||
bool ok =
|
||||
process_children(childfd, child_rel, NULL, NULL, false, force_now, skips, session, &survives);
|
||||
close(childfd);
|
||||
if (!ok)
|
||||
return false;
|
||||
@@ -637,8 +638,8 @@ static bool process_children(int dirfd, const char* dir_rel, const ArrayList* ke
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
char* child_rel = (strcmp(dir_rel, ".") == 0) ? str_dup(entry->d_name)
|
||||
: path_cat(dir_rel, entry->d_name);
|
||||
char* child_rel =
|
||||
(strcmp(dir_rel, ".") == 0) ? str_dup(entry->d_name) : path_cat(dir_rel, entry->d_name);
|
||||
if (!child_rel) {
|
||||
operation_ok = false;
|
||||
continue;
|
||||
@@ -704,8 +705,8 @@ static bool apply_plan_dir(DeletePlanSession* session, const Config* config, con
|
||||
return false;
|
||||
}
|
||||
bool survives = false;
|
||||
bool ok = process_children(dirfd, dir, dirs, files, strcmp(dir, ".") == 0, false, &skips,
|
||||
session, &survives);
|
||||
bool ok = process_children(dirfd, dir, dirs, files, strcmp(dir, ".") == 0, false, &skips, session,
|
||||
&survives);
|
||||
free(skips.entries);
|
||||
close(dirfd);
|
||||
if (!ok)
|
||||
@@ -719,8 +720,8 @@ static bool apply_missing(DeletePlanSession* session, const Config* config) {
|
||||
session->missing_applied = true;
|
||||
if (session->missing->size == 0)
|
||||
return true;
|
||||
DeleteManifest manifest = {.keeps = NULL, .protected = NULL, .missing = session->missing,
|
||||
.dirs = NULL};
|
||||
DeleteManifest manifest = {
|
||||
.keeps = NULL, .protected = NULL, .missing = session->missing, .dirs = NULL};
|
||||
size_t remaining = budget_available(session) ? session->max_delete - session->deleted : 0;
|
||||
size_t deleted = 0;
|
||||
size_t skipped = 0;
|
||||
|
||||
Reference in New Issue
Block a user