dovecot-2.2: doveadm fs delete: Added -n parameter to asynchrono...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Jan 10 00:19:32 EET 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/b6ab0e056c0b
changeset: 17091:b6ab0e056c0b
user: Timo Sirainen <tss at iki.fi>
date: Fri Jan 10 00:19:19 2014 +0200
description:
doveadm fs delete: Added -n parameter to asynchronously delete multiple files at once.
diffstat:
src/doveadm/doveadm-fs.c | 130 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 108 insertions(+), 22 deletions(-)
diffs (185 lines):
diff -r f9a11e81209f -r b6ab0e056c0b src/doveadm/doveadm-fs.c
--- a/src/doveadm/doveadm-fs.c Wed Jan 08 11:24:36 2014 -0500
+++ b/src/doveadm/doveadm-fs.c Fri Jan 10 00:19:19 2014 +0200
@@ -9,6 +9,7 @@
#include "doveadm.h"
#include <stdio.h>
+#include <unistd.h>
static void fs_cmd_help(doveadm_command_t *cmd);
static void cmd_fs_delete(int argc, char *argv[]);
@@ -181,56 +182,123 @@
fs_deinit(&fs);
}
-static void cmd_fs_delete_dir_recursive(struct fs *fs, const char *path)
+struct fs_delete_ctx {
+ unsigned int files_count;
+ struct fs_file **files;
+};
+
+static bool cmd_fs_delete_ctx_run(struct fs_delete_ctx *ctx)
+{
+ unsigned int i;
+ bool ret = FALSE;
+
+ for (i = 0; i < ctx->files_count; i++) {
+ if (ctx->files[i] == NULL)
+ ;
+ else if (fs_delete(ctx->files[i]) == 0)
+ fs_file_deinit(&ctx->files[i]);
+ else if (errno == EAGAIN)
+ ret = TRUE;
+ else {
+ i_error("fs_delete(%s) failed: %s",
+ fs_file_path(ctx->files[i]),
+ fs_file_last_error(ctx->files[i]));
+ doveadm_exit_code = EX_TEMPFAIL;
+ }
+ }
+ return ret;
+}
+
+static void
+cmd_fs_delete_dir_recursive(struct fs *fs, unsigned int async_count,
+ const char *path)
{
struct fs_iter *iter;
- struct fs_file *file;
- ARRAY_TYPE(const_string) dirs;
+ ARRAY_TYPE(const_string) fnames;
+ struct fs_delete_ctx ctx;
const char *fname, *const *fnamep;
+ unsigned int i;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.files_count = I_MAX(async_count, 1);
+ ctx.files = t_new(struct fs_file *, ctx.files_count);
/* delete subdirs first. all fs backends can't handle recursive
lookups, so save the list first. */
- t_array_init(&dirs, 8);
+ t_array_init(&fnames, 8);
iter = fs_iter_init(fs, path, FS_ITER_FLAG_DIRS);
while ((fname = fs_iter_next(iter)) != NULL) {
fname = t_strdup(fname);
- array_append(&dirs, &fname, 1);
+ array_append(&fnames, &fname, 1);
}
if (fs_iter_deinit(&iter) < 0) {
i_error("fs_iter_deinit(%s) failed: %s",
path, fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
- array_foreach(&dirs, fnamep) T_BEGIN {
- cmd_fs_delete_dir_recursive(fs,
+ array_foreach(&fnames, fnamep) T_BEGIN {
+ cmd_fs_delete_dir_recursive(fs, async_count,
t_strdup_printf("%s/%s", path, *fnamep));
} T_END;
- /* delete files */
+ /* delete files. again because we're doing this asynchronously finish
+ the iteration first. */
+ array_clear(&fnames);
iter = fs_iter_init(fs, path, 0);
- while ((fname = fs_iter_next(iter)) != NULL) T_BEGIN {
- file = fs_file_init(fs, t_strdup_printf("%s/%s", path, fname),
- FS_OPEN_MODE_READONLY);
- if (fs_delete(file) < 0) {
- i_error("fs_delete(%s) failed: %s",
- fs_file_path(file), fs_file_last_error(file));
- doveadm_exit_code = EX_TEMPFAIL;
- }
- fs_file_deinit(&file);
- } T_END;
+ while ((fname = fs_iter_next(iter)) != NULL) {
+ fname = t_strdup(fname);
+ array_append(&fnames, &fname, 1);
+ }
if (fs_iter_deinit(&iter) < 0) {
i_error("fs_iter_deinit(%s) failed: %s",
path, fs_last_error(fs));
doveadm_exit_code = EX_TEMPFAIL;
}
+
+ array_foreach(&fnames, fnamep) T_BEGIN {
+ fname = *fnamep;
+ retry:
+ for (i = 0; i < ctx.files_count; i++) {
+ if (ctx.files[i] != NULL)
+ continue;
+
+ ctx.files[i] = fs_file_init(fs,
+ t_strdup_printf("%s/%s", path, fname),
+ FS_OPEN_MODE_READONLY | FS_OPEN_FLAG_ASYNC |
+ FS_OPEN_FLAG_ASYNC_NOQUEUE);
+ fname = NULL;
+ break;
+ }
+ cmd_fs_delete_ctx_run(&ctx);
+ if (fname != NULL) {
+ if (fs_wait_async(fs) < 0) {
+ i_error("fs_wait_async() failed: %s", fs_last_error(fs));
+ doveadm_exit_code = EX_TEMPFAIL;
+ break;
+ }
+ goto retry;
+ }
+ } T_END;
+ while (doveadm_exit_code == 0 && cmd_fs_delete_ctx_run(&ctx)) {
+ if (fs_wait_async(fs) < 0) {
+ i_error("fs_wait_async() failed: %s", fs_last_error(fs));
+ doveadm_exit_code = EX_TEMPFAIL;
+ break;
+ }
+ }
+ for (i = 0; i < ctx.files_count; i++) {
+ if (ctx.files[i] != NULL)
+ fs_file_deinit(&ctx.files[i]);
+ }
}
-static void cmd_fs_delete_recursive(int argc, char *argv[])
+static void
+cmd_fs_delete_recursive(int argc, char *argv[], unsigned int async_count)
{
struct fs *fs;
fs = cmd_fs_init(&argc, &argv, 1, cmd_fs_delete);
- cmd_fs_delete_dir_recursive(fs, argv[0]);
+ cmd_fs_delete_dir_recursive(fs, async_count, argv[0]);
fs_deinit(&fs);
}
@@ -238,9 +306,27 @@
{
struct fs *fs;
struct fs_file *file;
+ bool recursive = FALSE;
+ unsigned int async_count = 0;
+ int c;
- if (null_strcmp(argv[1], "-R") == 0) {
- cmd_fs_delete_recursive(argc-1, argv+1);
+ while ((c = getopt(argc, argv, "Rn:")) > 0) {
+ switch (c) {
+ case 'R':
+ recursive = TRUE;
+ break;
+ case 'n':
+ if (str_to_uint(optarg, &async_count) < 0)
+ i_fatal("Invalid -n parameter: %s", optarg);
+ break;
+ default:
+ fs_cmd_help(cmd_fs_delete);
+ }
+ }
+ argc -= optind; argv += optind;
+
+ if (recursive) {
+ cmd_fs_delete_recursive(argc+1, argv-1, async_count);
return;
}
More information about the dovecot-cvs
mailing list