efm - sync much more often to avoid hangs/stalls with lots of data

do big ops like big copies of 3 or 5gb files over to an nfs mount or a
slow thumbdrive... the os can happily store it all in RAM. but then
any stats on that file still being flushed stall - definitely on nfs.
this leads to much badness. so sync ever 0.2 sec OR every 512k worth
of writes to stay interactive. it's a big worse for perf and maybe a
bit worse on wear but it's far more usable.

@opt
This commit is contained in:
Carsten Haitzler 2021-02-09 13:25:13 +00:00
parent 077f704fd0
commit 15e1519d64
1 changed files with 109 additions and 1 deletions

View File

@ -48,6 +48,8 @@ void *alloca(size_t);
#define COPYBUFSIZE 16384
#define REMOVECHUNKSIZE 4096
#define NB_PASS 3
#define SYNC_TIME 0.2
#define SYNC_BYTES (512 * 1024)
#define E_FREE(p) do { free(p); p = NULL; } while (0)
@ -126,6 +128,9 @@ Eina_List *_e_fm_op_separator = NULL;
char *_e_fm_op_stdin_buffer = NULL;
double _e_fm_op_last_sync = 0.0;
unsigned long long _e_fm_op_bytes_sync = 0;
struct _E_Fm_Op_Task
{
struct
@ -422,6 +427,7 @@ skip_arg:
_e_fm_op_set_up_idlers();
_e_fm_op_last_sync = ecore_time_get();
ecore_main_loop_begin();
quit:
@ -1160,6 +1166,7 @@ static void
_e_fm_op_copy_stat_info(E_Fm_Op_Task *task)
{
struct utimbuf ut;
double now = ecore_time_get();
if (!task->dst.name) return;
@ -1170,6 +1177,17 @@ _e_fm_op_copy_stat_info(E_Fm_Op_Task *task)
ut.actime = task->src.st.st_atime;
ut.modtime = task->src.st.st_mtime;
utime(task->dst.name, &ut);
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->dst.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
}
static int
@ -1234,6 +1252,7 @@ static int
_e_fm_op_copy_dir(E_Fm_Op_Task *task)
{
struct stat st;
double now = ecore_time_get();
/* Directory. Just create one in destatation. */
if (mkdir(task->dst.name,
@ -1264,7 +1283,20 @@ _e_fm_op_copy_dir(E_Fm_Op_Task *task)
"Cannot make directory '%s': %s.",
task->dst.name);
}
else
{
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->dst.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
}
task->dst.done += task->src.st.st_size;
_e_fm_op_update_progress(task, task->src.st.st_size, 0);
@ -1279,6 +1311,7 @@ _e_fm_op_copy_link(E_Fm_Op_Task *task)
{
char *lnk_path;
size_t lnk_len;
double now = ecore_time_get();
lnk_path = ecore_file_readlink(task->src.name);
if (!lnk_path)
@ -1316,6 +1349,20 @@ _e_fm_op_copy_link(E_Fm_Op_Task *task)
_E_FM_OP_ERROR_SEND_WORK(task, E_FM_OP_ERROR, "Cannot create link from '%s' to '%s': %s.", buf, task->dst.name);
}
}
else
{
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->dst.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
}
free(lnk_path);
task->dst.done += task->src.st.st_size;
@ -1330,6 +1377,8 @@ _e_fm_op_copy_link(E_Fm_Op_Task *task)
static int
_e_fm_op_copy_fifo(E_Fm_Op_Task *task)
{
double now = ecore_time_get();
if (mkfifo(task->dst.name, task->src.st.st_mode) == -1)
{
if (errno == EEXIST)
@ -1342,6 +1391,20 @@ _e_fm_op_copy_fifo(E_Fm_Op_Task *task)
else
_E_FM_OP_ERROR_SEND_WORK(task, E_FM_OP_ERROR, "Cannot make FIFO at '%s': %s.", task->dst.name);
}
else
{
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->dst.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
}
_e_fm_op_copy_stat_info(task);
@ -1389,13 +1452,19 @@ static int
_e_fm_op_copy_chunk(E_Fm_Op_Task *task)
{
E_Fm_Op_Copy_Data *data;
size_t dread, dwrite;
unsigned long long dread, dwrite;
char buf[COPYBUFSIZE];
double now = ecore_time_get();
data = task->data;
if (_e_fm_op_abort)
{
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
syncfs(fileno(data->to));
_e_fm_op_last_sync = now;
}
_e_fm_op_rollback(task);
task->finished = 1;
@ -1408,6 +1477,12 @@ _e_fm_op_copy_chunk(E_Fm_Op_Task *task)
if (!feof(data->from))
_E_FM_OP_ERROR_SEND_WORK(task, E_FM_OP_ERROR, "Cannot read data from '%s': %s.", task->dst.name);
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
fflush(data->to);
syncfs(fileno(data->to));
_e_fm_op_last_sync = now;
}
fclose(data->from);
fclose(data->to);
data->to = NULL;
@ -1425,6 +1500,15 @@ _e_fm_op_copy_chunk(E_Fm_Op_Task *task)
}
dwrite = fwrite(buf, 1, dread, data->to);
_e_fm_op_bytes_sync += dread;
if (((now - _e_fm_op_last_sync) > SYNC_TIME) ||
(_e_fm_op_bytes_sync > SYNC_BYTES))
{
fflush(data->to);
syncfs(fileno(data->to));
_e_fm_op_last_sync = now;
_e_fm_op_bytes_sync = 0;
}
if (dwrite < dread)
_E_FM_OP_ERROR_SEND_WORK(task, E_FM_OP_ERROR, "Cannot write data to '%s': %s.", task->dst.name);
@ -1700,6 +1784,8 @@ _e_fm_op_symlink_atom(E_Fm_Op_Task *task)
static int
_e_fm_op_remove_atom(E_Fm_Op_Task *task)
{
double now = ecore_time_get();
if (_e_fm_op_abort) return 1;
E_FM_OP_DEBUG("Remove: %s\n", task->src.name);
@ -1715,6 +1801,17 @@ _e_fm_op_remove_atom(E_Fm_Op_Task *task)
If this happens (for example new files were created after the scan was
complete), implicitly delete everything. */
ecore_file_recursive_rm(task->src.name);
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->src.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
task->finished = 1; /* Make sure that task is removed. */
return 1;
}
@ -1724,6 +1821,17 @@ _e_fm_op_remove_atom(E_Fm_Op_Task *task)
}
else if (unlink(task->src.name) == -1)
_E_FM_OP_ERROR_SEND_WORK(task, E_FM_OP_ERROR, "Cannot remove file '%s': %s.", task->src.name);
if ((now - _e_fm_op_last_sync) > SYNC_TIME)
{
int fd = open(task->src.name, O_RDWR);
if (fd >= 0)
{
syncfs(fd);
_e_fm_op_last_sync = now;
close(fd);
}
}
task->dst.done += REMOVECHUNKSIZE;
_e_fm_op_update_progress(task, REMOVECHUNKSIZE, 0);