From c28e58284a4a93520c1f5e949c2c5219d475d75e Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 24 Feb 2015 18:36:31 +0900 Subject: [PATCH] efm - make dir listing far faster - no file magic content and dont sync this speed sup dir listing in efm drastically. first the e fm back end uses an io thread that just spools through everything fast and sends it over the mainloop to then send by ipc to e. and on the e side we no longer use the heavy file internal magic using api calls that wander all over a file for magic numbers - this is insanely slow and brings listing to a crawl. --- src/bin/e_fm.c | 13 +- src/bin/e_fm/e_fm_ipc.c | 306 +++++++++++++--------------------------- src/bin/e_fm_op.h | 2 +- 3 files changed, 110 insertions(+), 211 deletions(-) diff --git a/src/bin/e_fm.c b/src/bin/e_fm.c index 5c8c1b052..7b828265a 100644 --- a/src/bin/e_fm.c +++ b/src/bin/e_fm.c @@ -4584,6 +4584,15 @@ _e_fm2_icon_geom_adjust(E_Fm2_Icon *ic, int saved_x, int saved_y, int saved_w __ ic->y = y; } +static const char * +_mime_get(const char *path) +{ + const char *mime = efreet_mime_special_type_get(path); + if (!mime) mime = efreet_mime_globs_type_get(path); + if (!mime) mime = efreet_mime_fallback_type_get(path); + return mime; +} + static int _e_fm2_icon_fill(E_Fm2_Icon *ic, E_Fm2_Finfo *finf) { @@ -4614,7 +4623,7 @@ _e_fm2_icon_fill(E_Fm2_Icon *ic, E_Fm2_Finfo *finf) } else if (ic->info.real_link) { - mime = efreet_mime_type_get(ic->info.real_link); + mime = _mime_get(ic->info.real_link); if (!mime) /* XXX REMOVE/DEPRECATE ME LATER */ mime = e_fm_mime_filename_get(ic->info.file); @@ -4623,7 +4632,7 @@ _e_fm2_icon_fill(E_Fm2_Icon *ic, E_Fm2_Finfo *finf) if (!ic->info.mime) { - mime = efreet_mime_type_get(buf); + mime = _mime_get(buf); if (!mime) /* XXX REMOVE/DEPRECATE ME LATER */ mime = e_fm_mime_filename_get(ic->info.file); diff --git a/src/bin/e_fm/e_fm_ipc.c b/src/bin/e_fm/e_fm_ipc.c index 4a3f0ace7..8348afdf3 100644 --- a/src/bin/e_fm/e_fm_ipc.c +++ b/src/bin/e_fm/e_fm_ipc.c @@ -42,9 +42,6 @@ #undef E_TYPEDEFS #include "e_fm_main.h" #include "e_fm_shared_codec.h" -#define DEF_SYNC_NUM 8 -#define DEF_ROUND_TRIP 0.05 -#define DEF_ROUND_TRIP_TOLERANCE 0.01 #define DEF_MOD_BACKOFF 0.2 #ifndef strdupa @@ -65,14 +62,12 @@ struct _E_Dir int mon_ref; E_Dir *mon_real; Eina_List *fq; - Ecore_Idler *idler; - int dot_order; - int sync; - double sync_time; - int sync_num; + Eina_Iterator *lister_iterator; + Ecore_Thread *lister_thread; Eina_List *recent_mods; Ecore_Timer *recent_clean; - unsigned char cleaning : 1; + Eina_Bool cleaning : 1; + Eina_Bool delete_me : 1; }; struct _E_Fop @@ -122,7 +117,6 @@ Ecore_Ipc_Server *_e_fm_ipc_server = NULL; static Eina_List *_e_dirs = NULL; static Eina_List *_e_fops = NULL; -static int _e_sync_num = 0; static Eina_List *_e_fm_ipc_slaves = NULL; static Eina_List *_e_fm_tasks = NULL; @@ -159,11 +153,8 @@ static void _e_fm_ipc_file_add(E_Dir *ed, const char *path, int listing); static void _e_fm_ipc_file_del(E_Dir *ed, const char *path); static void _e_fm_ipc_file_mod(E_Dir *ed, const char *path); static void _e_fm_ipc_file_mon_dir_del(E_Dir *ed, const char *path); -static void _e_fm_ipc_file_mon_list_sync(E_Dir *ed); -static Eina_Bool _e_fm_ipc_cb_file_mon_list_idler(void *data); static Eina_Bool _e_fm_ipc_cb_fop_trash_idler(void *data); -static char *_e_str_list_remove(Eina_List **list, const char *str, int len); static void _e_fm_ipc_reorder(const char *file, const char *dst, const char *relative, int after); static void _e_fm_ipc_dir_del(E_Dir *ed); @@ -241,6 +232,86 @@ _e_fm_ipc_monitor_start(int id, const char *path) _e_fm_ipc_monitor_start_try(task); } +static void +_e_fm_ipc_cb_list_result(void *data, Ecore_Thread *thread EINA_UNUSED, void *msg_data) +{ + E_Dir *ed = data; + Eina_List *files = msg_data; + const char *s; + + if (!files) _e_fm_ipc_file_add(ed, "", 2); + else + { + EINA_LIST_FREE(files, s) + { + _e_fm_ipc_file_add(ed, s, 2); + eina_stringshare_del(s); + } + } +} + +static void +_e_fm_ipc_cb_list(void *data, Ecore_Thread *thread) +{ + E_Dir *ed = data; + Eina_List *files = NULL; + int i, total = 0; + Eina_File_Direct_Info *info; + Eina_Iterator *it = ed->lister_iterator; + char buf[4096]; + const char *s; + + if (!strcmp(ed->dir, "/")) snprintf(buf, sizeof(buf), "/.order"); + else snprintf(buf, sizeof(buf), "%s/.order", ed->dir); + if (ecore_file_exists(buf)) + { + s = eina_stringshare_add(buf); + files = eina_list_append(files, s); + } + i = 0; + EINA_ITERATOR_FOREACH(it, info) + { + if (!strcmp(info->path + info->name_start, ".order")) continue; + if (ecore_thread_check(thread)) + { + EINA_LIST_FREE(files, s) eina_stringshare_del(s); + break; + } + s = eina_stringshare_add(info->path); + files = eina_list_append(files, s); + total++; + i++; + if (i >= 16) + { + i = 0; + ecore_thread_feedback(thread, files); + files = NULL; + } + } + if (files) ecore_thread_feedback(thread, files); + if (total == 0) ecore_thread_feedback(thread, NULL); +} + +static void +_e_fm_ipc_cb_list_end(void *data, Ecore_Thread *thread EINA_UNUSED) +{ + E_Dir *ed = data; + ed->lister_thread = NULL; + eina_iterator_free(ed->lister_iterator); + ed->lister_iterator = NULL; + if (ed->delete_me) _e_fm_ipc_dir_del(ed); +} + +static void +_e_fm_ipc_cb_list_cancel(void *data, Ecore_Thread *thread EINA_UNUSED) +{ + E_Dir *ed = data; + ed->lister_thread = NULL; + eina_iterator_free(ed->lister_iterator); + ed->lister_iterator = NULL; + if (ed->delete_me) _e_fm_ipc_dir_del(ed); +} + static void _e_fm_ipc_monitor_start_try(E_Fm_Task *task) { @@ -271,14 +342,11 @@ _e_fm_ipc_monitor_start_try(E_Fm_Task *task) } else { - Eina_File_Direct_Info *info; - Eina_List *files = NULL; - char *dot_order = NULL; - /* create a new dir entry */ ed = calloc(1, sizeof(E_Dir)); ed->id = task->id; ed->dir = eina_stringshare_add(task->src); + ed->lister_iterator = it; if (!ped) { /* if no previous monitoring dir exists - this one @@ -294,94 +362,11 @@ _e_fm_ipc_monitor_start_try(E_Fm_Task *task) } _e_dirs = eina_list_append(_e_dirs, ed); - /* read everything except a .order, . and .. */ - EINA_ITERATOR_FOREACH(it, info) - { - if (!strcmp(info->path + info->name_start, ".order")) - { - dot_order = strdup(info->path); - continue; - } - files = eina_list_append(files, eina_stringshare_add(info->path + info->name_start)); - } - eina_iterator_free(it); - - /* if there was a .order - we need to parse it */ - if (dot_order) - { - Eina_File *f; - - f = eina_file_open(dot_order, EINA_FALSE); - if (f) - { - Eina_List *f2 = NULL; - char *map; - - /* This piece of code should really become generic and work like an iterator. - * I plan to add this feature in eina, but that would be for next generation of E, - * not E17. - */ - map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); - if (map) - { - const char *current = map; - const char *found; - size_t length = eina_file_size_get(f); - - /* inset files in order if the existed in file - * list before */ - while ((found = memchr(current, '\n', length))) - { - if (found - current > 1) - { - char *s = _e_str_list_remove(&files, current, found - current - 1); - if (s) f2 = eina_list_append(f2, s); - } - length -= found - current - 1; - current = found + 1; - } - - if (found == NULL && length > 0) - { - char *s = _e_str_list_remove(&files, current, length); - if (s) f2 = eina_list_append(f2, s); - } - - /* append whats left */ - files = eina_list_merge(f2, files); - - eina_file_map_free(f, map); - } - - eina_file_close(f); - } - } - ed->fq = files; - /* FIXME: if .order file- load it, sort all items int it - * that are in files then just append whatever is left in - * alphabetical order - */ - /* FIXME: maybe one day we can sort files here and handle - * .order file stuff here - but not today - */ - /* note that we had a .order at all */ - ed->dot_order = dot_order ? EINA_TRUE : EINA_FALSE; - if (dot_order) - { - /* if we did - tell the E about this FIRST - it will - * decide what to do if it first sees a .order or not */ - if (eina_list_count(files) == 1) - _e_fm_ipc_file_add(ed, dot_order, 2); - else - _e_fm_ipc_file_add(ed, dot_order, 1); - } - /* send empty file - indicate empty dir */ - if (!files) _e_fm_ipc_file_add(ed, "", 2); - /* and in an idler - list files, statting them etc. */ - ed->idler = ecore_idler_add(_e_fm_ipc_cb_file_mon_list_idler, ed); - ed->sync_num = DEF_SYNC_NUM; - - free(dot_order); + ed->lister_thread = ecore_thread_feedback_run(_e_fm_ipc_cb_list, + _e_fm_ipc_cb_list_result, + _e_fm_ipc_cb_list_end, + _e_fm_ipc_cb_list_cancel, + ed, EINA_TRUE); } } @@ -696,36 +681,6 @@ _e_fm_ipc_cb_server_data(void *data __UNUSED__, int type __UNUSED__, void *event ecore_main_loop_quit(); break; - case E_FM_OP_MONITOR_SYNC: /* mon list sync */ - { - Eina_List *l; - E_Dir *ed; - double sync_time; - - EINA_LIST_FOREACH(_e_dirs, l, ed) - { - if (ed->fq) - { - if (ed->sync == e->response) - { - sync_time = ecore_time_get() - ed->sync_time; - /* try keep round trips to round trip tolerance */ - if - (sync_time < (DEF_ROUND_TRIP - DEF_ROUND_TRIP_TOLERANCE)) - ed->sync_num += 1; - else if - (sync_time > (DEF_ROUND_TRIP + DEF_ROUND_TRIP_TOLERANCE)) - ed->sync_num -= 1; - /* always sync at least 1 file */ - if (ed->sync_num < 1) ed->sync_num = 1; - ed->idler = ecore_idler_add(_e_fm_ipc_cb_file_mon_list_idler, ed); - break; - } - } - } - } - break; - case E_FM_OP_ABORT: // abort copy/move/delete operation by user { E_Fm_Slave *slave = _e_fm_ipc_slave_get(e->ref); @@ -1198,58 +1153,6 @@ _e_fm_ipc_file_mon_dir_del(E_Dir *ed, const char *path) 0, ed->id, 0, (void *)path, strlen(path) + 1); } -static void -_e_fm_ipc_file_mon_list_sync(E_Dir *ed) -{ - _e_sync_num++; - if (_e_sync_num == 0) _e_sync_num = 1; - ed->sync = _e_sync_num; - ed->sync_time = ecore_time_get(); - ecore_ipc_server_send(_e_fm_ipc_server, - 6 /*E_IPC_DOMAIN_FM*/, - E_FM_OP_MONITOR_SYNC, - 0, ed->id, ed->sync, NULL, 0); -} - -static Eina_Bool -_e_fm_ipc_cb_file_mon_list_idler(void *data) -{ - E_Dir *ed; - int n = 0; - char *file, buf[4096]; - - ed = data; - /* FIXME: spool off files in idlers and handle sync req's */ - while (ed->fq) - { - file = eina_list_data_get(ed->fq); - if (!((ed->dot_order) && (!strcmp(file, ".order")))) - { - if (!strcmp(ed->dir, "/")) - snprintf(buf, sizeof(buf), "/%s", file); - else - snprintf(buf, sizeof(buf), "%s/%s", ed->dir, file); - _e_fm_ipc_file_add(ed, buf, 1); - } - eina_stringshare_del(file); - ed->fq = eina_list_remove_list(ed->fq, ed->fq); - n++; - if (n == ed->sync_num) - { - _e_fm_ipc_file_mon_list_sync(ed); - ed->idler = NULL; - if (!ed->fq) _e_fm_ipc_file_add(ed, "", 2); - return 0; - } - } - ed->sync_num = DEF_SYNC_NUM; - ed->sync = 0; - ed->sync_time = 0.0; - ed->idler = NULL; - if (!ed->fq) _e_fm_ipc_file_add(ed, "", 2); - return ECORE_CALLBACK_CANCEL; -} - static Eina_Bool _e_fm_ipc_cb_fop_trash_idler(void *data) { @@ -1333,22 +1236,6 @@ _e_fm_ipc_cb_fop_trash_idler(void *data) return ECORE_CALLBACK_CANCEL; } -static char * -_e_str_list_remove(Eina_List **list, const char *str, int len) -{ - Eina_List *l; - char *s; - - EINA_LIST_FOREACH(*list, l, s) - if (!strncmp(s, str, len)) - { - *list = eina_list_remove_list(*list, l); - return s; - } - - return NULL; -} - static void _e_fm_ipc_reorder(const char *file, const char *dst, const char *relative, int after) { @@ -1430,17 +1317,20 @@ _e_fm_ipc_dir_del(E_Dir *ed) void *data; E_Mod *m; + if (ed->lister_thread) + { + ed->delete_me = EINA_TRUE; + ecore_thread_cancel(ed->lister_thread); + return; + } eina_stringshare_del(ed->dir); - if (ed->idler) ecore_idler_del(ed->idler); - if (ed->recent_clean) - ecore_timer_del(ed->recent_clean); + if (ed->recent_clean) ecore_timer_del(ed->recent_clean); EINA_LIST_FREE(ed->recent_mods, m) { eina_stringshare_del(m->path); free(m); } - EINA_LIST_FREE(ed->fq, data) - eina_stringshare_del(data); + EINA_LIST_FREE(ed->fq, data) eina_stringshare_del(data); free(ed); } diff --git a/src/bin/e_fm_op.h b/src/bin/e_fm_op.h index c7f79bee5..fb073217a 100644 --- a/src/bin/e_fm_op.h +++ b/src/bin/e_fm_op.h @@ -26,7 +26,7 @@ typedef enum _E_Fm_Op_Type E_FM_OP_MKDIR, E_FM_OP_TRASH, E_FM_OP_MONITOR_START, - E_FM_OP_MONITOR_SYNC, + E_FM_OP_MONITOR_SYNC, // not used anymore E_FM_OP_MONITOR_END, E_FM_OP_MOUNT, E_FM_OP_UNMOUNT,