Preserve video temp mode and test durable file commit boundaries
This commit is contained in:
1 parent
aa7a9b74f4
commit
9e0949434e
3 files changed
+50
-9
No files matched your search
+2
-2
@@ -713,7 +713,7 @@ static int vc_run(struct vc_ctx* ctx) {
|
||||
static void vc_thread_entry(void* raw) {
|
||||
struct vc_ctx* ctx = raw;
|
||||
video_ffmpeg_init();
|
||||
if (file_io_paths(ctx->source, ctx->destination) || file_io_temp_open(&ctx->file, ctx->destination)) { ctx->error = -1; return; }
|
||||
if (file_io_paths(ctx->source, ctx->destination) || file_io_temp_open(&ctx->file, ctx->destination, 0)) { ctx->error = -1; return; }
|
||||
struct stat info;
|
||||
if (!stat(ctx->source, &info)) ctx->source_size = info.st_size;
|
||||
int error = vc_run(ctx);
|
||||
@@ -844,7 +844,7 @@ int video_extract_thumbnail(const char* src, const char* dst, int max_w) {
|
||||
}
|
||||
if (error < 0) goto done;
|
||||
phase = "write JPEG";
|
||||
if (file_io_temp_open(&output, dst)) { error = AVERROR(EIO); goto done; }
|
||||
if (file_io_temp_open(&output, dst, 0)) { error = AVERROR(EIO); goto done; }
|
||||
if (fwrite(packet->data, 1, packet->size, output.file) != (size_t)packet->size) {
|
||||
error = AVERROR(errno ? errno : EIO); goto done;
|
||||
}
|
||||
|
||||
+1
-1
@@ -884,7 +884,7 @@ if OS_LINUX
|
||||
test_media_primitives_LDFLAGS = -Wl,--wrap=fopen -Wl,--wrap=fdopen -Wl,--wrap=fread -Wl,--wrap=__fread_chk -Wl,--wrap=ferror \
|
||||
-Wl,--wrap=fwrite -Wl,--wrap=fflush -Wl,--wrap=fclose -Wl,--wrap=rename -Wl,--wrap=RAND_bytes \
|
||||
-Wl,--wrap=opendir -Wl,--wrap=readdir -Wl,--wrap=closedir -Wl,--wrap=fseeko \
|
||||
-Wl,--wrap=pthread_create -Wl,--wrap=u_calloc_impl -Wl,--wrap=uasync_post_reserved
|
||||
-Wl,--wrap=pthread_create -Wl,--wrap=u_calloc_impl -Wl,--wrap=uasync_post_reserved -Wl,--wrap=fsync
|
||||
endif
|
||||
|
||||
test_media_index_SOURCES = test_media_index.c
|
||||
|
||||
@@ -19,7 +19,8 @@ static char root[256], source[512], destination[512];
|
||||
static unsigned visits;
|
||||
|
||||
#ifdef __linux__
|
||||
enum fault { NONE, READ, WRITE, FLUSH, SOURCE_CLOSE, OUTPUT_CLOSE, FDOPEN, PUBLISH, OPEN_DIR, READ_DIR, CLOSE_DIR, SEEK, THREAD };
|
||||
enum fault { NONE, READ, WRITE, FLUSH, SOURCE_CLOSE, OUTPUT_CLOSE, FDOPEN, PUBLISH, OPEN_DIR, READ_DIR, CLOSE_DIR, SEEK, THREAD,
|
||||
SYNC_FILE, SYNC_DIRECTORY };
|
||||
static enum fault fault;
|
||||
static int injected, read_failed, rng_after = -1, allocation_after = -1;
|
||||
static FILE *input_file, *output_file;
|
||||
@@ -35,6 +36,7 @@ extern size_t __real_fwrite(const void*, size_t, size_t, FILE*);
|
||||
extern int __real_ferror(FILE*), __real_fflush(FILE*), __real_fclose(FILE*);
|
||||
extern int __real_rename(const char*, const char*), __real_RAND_bytes(unsigned char*, int);
|
||||
extern int __real_fseeko(FILE*, off_t, int);
|
||||
extern int __real_fsync(int);
|
||||
extern DIR *__real_opendir(const char*);
|
||||
extern struct dirent *__real_readdir(DIR*);
|
||||
extern int __real_closedir(DIR*);
|
||||
@@ -84,6 +86,11 @@ int __wrap_fclose(FILE *file) {
|
||||
return result;
|
||||
}
|
||||
int __wrap_rename(const char *from, const char *to) { return inject(PUBLISH) ? -1 : __real_rename(from, to); }
|
||||
int __wrap_fsync(int fd) {
|
||||
struct stat data; assert(!fstat(fd, &data));
|
||||
if (inject(S_ISDIR(data.st_mode) ? SYNC_DIRECTORY : SYNC_FILE)) return -1;
|
||||
return __real_fsync(fd);
|
||||
}
|
||||
int __wrap_RAND_bytes(unsigned char *out, int size) {
|
||||
if (rng_after == 0) { injected = 1; return 0; }
|
||||
if (rng_after > 0) rng_after--;
|
||||
@@ -169,7 +176,7 @@ static void temporary_tests(void) {
|
||||
struct file_io_temp outputs[3] = {0};
|
||||
char paths[3][FILE_IO_PATH_MAX], stale[FILE_IO_PATH_MAX];
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
assert(!file_io_temp_open(&outputs[i], destination));
|
||||
assert(!file_io_temp_open(&outputs[i], destination, 0));
|
||||
snprintf(paths[i], sizeof(paths[i]), "%s", outputs[i].temporary);
|
||||
assert(file_io_remove_orphan(paths[i]) == 0);
|
||||
assert(fputs("owned", outputs[i].file) >= 0 && !file_io_temp_finish(&outputs[i]));
|
||||
@@ -187,10 +194,10 @@ static void temporary_tests(void) {
|
||||
#ifdef __linux__
|
||||
struct file_io_temp failed = {0};
|
||||
fault = FDOPEN; injected = 0;
|
||||
assert(file_io_temp_open(&failed, destination) == -1 && injected); fault = NONE;
|
||||
assert(file_io_temp_open(&failed, destination, 0) == -1 && injected); fault = NONE;
|
||||
assert(failed.temporary[0] && file_io_remove_orphan(failed.temporary) == 0);
|
||||
file_io_temp_discard(&failed);
|
||||
assert(!file_io_temp_open(&failed, destination) && !file_io_temp_finish(&failed));
|
||||
assert(!file_io_temp_open(&failed, destination, 0) && !file_io_temp_finish(&failed));
|
||||
fault = PUBLISH; injected = 0;
|
||||
assert(file_io_temp_publish(&failed, source, destination) == -1 && injected); fault = NONE;
|
||||
assert(file_io_remove_orphan(failed.temporary) == 0); file_io_temp_discard(&failed);
|
||||
@@ -198,6 +205,40 @@ static void temporary_tests(void) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS active temp ownership: open/finished, multiple generations, publish/discard and failures");
|
||||
}
|
||||
|
||||
/* Ошибка до rename сохраняет прежний файл; отказ directory sync уже не отменяет замену. */
|
||||
static void durable_tests(void) {
|
||||
struct file_io_temp output = {0};
|
||||
write_text(destination, "previous");
|
||||
assert(!file_io_temp_open(&output, destination, FILE_IO_DURABLE));
|
||||
assert(fputs("durable", output.file) >= 0 && !file_io_temp_finish(&output));
|
||||
check_text(destination, "previous"); assert(file_io_remove_orphan(output.temporary) == 0);
|
||||
assert(!file_io_temp_publish(&output, source, destination) && !output.temporary[0]);
|
||||
file_io_temp_discard(&output); check_text(destination, "durable");
|
||||
assert(!file_io_sync_file(destination) && !file_io_sync_directory("relative-name"));
|
||||
#ifndef _WIN32
|
||||
assert(!file_io_sync_directory("/file"));
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
assert(!file_io_temp_open(&output, destination, FILE_IO_DURABLE));
|
||||
assert(fputs("failed", output.file) >= 0);
|
||||
fault = SYNC_FILE; injected = 0;
|
||||
assert(file_io_temp_finish(&output) == -1 && injected && !output.file && output.temporary[0]); fault = NONE;
|
||||
file_io_temp_discard(&output); check_text(destination, "durable");
|
||||
assert(!file_io_temp_open(&output, destination, FILE_IO_DURABLE));
|
||||
assert(fputs("installed", output.file) >= 0 && !file_io_temp_finish(&output));
|
||||
fault = SYNC_DIRECTORY; injected = 0;
|
||||
assert(file_io_temp_publish(&output, source, destination) == -1 && injected && !output.temporary[0]); fault = NONE;
|
||||
file_io_temp_discard(&output); check_text(destination, "installed");
|
||||
assert(!file_io_temp_open(&output, destination, 0));
|
||||
assert(fputs("ordinary", output.file) >= 0);
|
||||
fault = SYNC_FILE; injected = 0;
|
||||
assert(!file_io_temp_finish(&output) && !injected); fault = SYNC_DIRECTORY;
|
||||
assert(!file_io_temp_publish(&output, source, destination) && !injected); fault = NONE;
|
||||
file_io_temp_discard(&output); check_text(destination, "ordinary");
|
||||
#endif
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS durable temp: sync-before-close, rename commit point, directory failure and ordinary mode");
|
||||
}
|
||||
|
||||
static void crypto_tests(void) {
|
||||
uint8_t output[64], zero[64] = {0};
|
||||
memset(output, 0xa5, sizeof(output));
|
||||
@@ -291,7 +332,7 @@ static void registration_tests(struct UASYNC *ua) {
|
||||
struct temp_job { struct file_io_temp output; pthread_barrier_t barrier; int publish; };
|
||||
static void* temp_worker(void* arg) {
|
||||
struct temp_job* job = arg;
|
||||
assert(!file_io_temp_open(&job->output, destination));
|
||||
assert(!file_io_temp_open(&job->output, destination, 0));
|
||||
assert(fputs("worker", job->output.file) >= 0 && !file_io_temp_finish(&job->output));
|
||||
pthread_barrier_wait(&job->barrier); pthread_barrier_wait(&job->barrier);
|
||||
if (job->publish) assert(!file_io_temp_publish(&job->output, source, destination));
|
||||
@@ -384,7 +425,7 @@ int main(void) {
|
||||
#endif
|
||||
assert(!utun_mkdir(root, 0700)); snprintf(source, sizeof(source), "%s/source", root);
|
||||
snprintf(destination, sizeof(destination), "%s/destination", root);
|
||||
copy_tests(); temporary_tests(); crypto_tests(); size_and_walk_tests();
|
||||
copy_tests(); temporary_tests(); durable_tests(); crypto_tests(); size_and_walk_tests();
|
||||
struct UASYNC *ua = uasync_create(); assert(ua);
|
||||
registration_tests(ua);
|
||||
#ifdef __linux__
|
||||
|
||||
Reference in new issue
Block a user