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.
This commit is contained in:
Carsten Haitzler 2015-02-24 18:36:31 +09:00
parent cc5a4e9071
commit c28e58284a
3 changed files with 110 additions and 211 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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,