forked from enlightenment/efl
evas/cserve2: Share paths of index tables with clients
- Send paths to all connected clients - Send paths upon connection from a new client - Client side: - Fast find opened images - Fast find loaded images - Optimize load by skipping socket wait Also, remap indexes when needed (file size changed) When index file grows, the clients are not notified, so they must constantly check that their mapping matches the current array size.
This commit is contained in:
parent
47be3a2b81
commit
88ef4131a0
|
@ -233,7 +233,7 @@ void cserve2_client_del(Client *client);
|
|||
void cserve2_client_deliver(Client *client);
|
||||
void cserve2_client_error_send(Client *client, unsigned int rid, int error_code);
|
||||
ssize_t cserve2_client_send(Client *client, const void *data, size_t size);
|
||||
void cserve2_index_list_send(const char *files_index_path, const char *images_index_path, const char *fonts_index_path);
|
||||
void cserve2_index_list_send(const char *strings_index_path, const char *strings_entries_path, const char *files_index_path, const char *images_index_path, const char *fonts_index_path, Client *client);
|
||||
|
||||
Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data);
|
||||
Eina_Bool cserve2_fd_watch_del(int fd);
|
||||
|
@ -357,6 +357,8 @@ void *cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid);
|
|||
|
||||
|
||||
// Shared strings
|
||||
const char *cserve2_shared_strings_table_name_get();
|
||||
const char *cserve2_shared_strings_index_name_get();
|
||||
int cserve2_shared_string_add(const char *str);
|
||||
int cserve2_shared_string_ref(int id);
|
||||
void cserve2_shared_string_del(int id);
|
||||
|
|
|
@ -148,7 +148,8 @@ struct _File_Watch {
|
|||
};
|
||||
|
||||
static unsigned int _entry_id = 0;
|
||||
static unsigned int _freed_entry_count = 0;
|
||||
static unsigned int _freed_file_entry_count = 0;
|
||||
static unsigned int _freed_image_entry_count = 0;
|
||||
|
||||
static Shared_Array *_file_data_array = NULL;
|
||||
static Shared_Array *_image_data_array = NULL;
|
||||
|
@ -315,12 +316,13 @@ _repack()
|
|||
{
|
||||
Shared_Array *sa;
|
||||
int count;
|
||||
Eina_Bool updated = EINA_FALSE;
|
||||
|
||||
// Repack when we have 10% fragmentation over the whole shm buffer
|
||||
|
||||
count = cserve2_shared_array_size_get(_file_data_array);
|
||||
if ((count > 0) && (_freed_entry_count > 100 ||
|
||||
((_freed_entry_count * 100) / count >= 10)))
|
||||
if ((count > 0) && (_freed_file_entry_count > 100 ||
|
||||
((_freed_file_entry_count * 100) / count >= 10)))
|
||||
{
|
||||
DBG("Repacking file data array: %s",
|
||||
cserve2_shared_array_name_get(_file_data_array));
|
||||
|
@ -331,18 +333,45 @@ _repack()
|
|||
if (!sa)
|
||||
{
|
||||
ERR("Failed to repack array. Keeping previous references!");
|
||||
return;
|
||||
goto skip_files;
|
||||
}
|
||||
|
||||
cserve2_shared_array_del(_file_data_array);
|
||||
_freed_entry_count = 0;
|
||||
_freed_file_entry_count = 0;
|
||||
_file_data_array = sa;
|
||||
updated = EINA_TRUE;
|
||||
}
|
||||
skip_files:
|
||||
|
||||
count = cserve2_shared_array_size_get(_image_data_array);
|
||||
if ((count > 0) && (_freed_image_entry_count > 100 ||
|
||||
((_freed_image_entry_count * 100) / count >= 10)))
|
||||
{
|
||||
DBG("Repacking image data array: %s",
|
||||
cserve2_shared_array_name_get(_image_data_array));
|
||||
|
||||
sa = cserve2_shared_array_repack(_image_data_array,
|
||||
_repack_skip_cb,
|
||||
_shm_object_id_cmp_cb, NULL);
|
||||
if (!sa)
|
||||
{
|
||||
ERR("Failed to repack array. Keeping previous references!");
|
||||
goto skip_images;
|
||||
}
|
||||
|
||||
// FIXME TODO: Repack image data array as well
|
||||
cserve2_shared_array_del(_image_data_array);
|
||||
_freed_image_entry_count = 0;
|
||||
_image_data_array = sa;
|
||||
updated = EINA_TRUE;
|
||||
}
|
||||
skip_images:
|
||||
|
||||
cserve2_index_list_send(cserve2_shared_array_name_get(_file_data_array),
|
||||
if (updated)
|
||||
cserve2_index_list_send(cserve2_shared_strings_index_name_get(),
|
||||
cserve2_shared_strings_table_name_get(),
|
||||
cserve2_shared_array_name_get(_file_data_array),
|
||||
cserve2_shared_array_name_get(_image_data_array),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
@ -404,6 +433,18 @@ _image_loaded_msg_create(Image_Entry *ientry, Image_Data *idata, int *size)
|
|||
msg->shm.image_size = cserve2_shm_size_get(ientry->shm);
|
||||
msg->alpha_sparse = idata->alpha_sparse;
|
||||
|
||||
if (idata->shm_id)
|
||||
{
|
||||
const char *old = cserve2_shared_string_get(idata->shm_id);
|
||||
if (strcmp(old, shmpath))
|
||||
{
|
||||
cserve2_shared_string_del(idata->shm_id);
|
||||
idata->shm_id = cserve2_shared_string_add(shmpath);
|
||||
}
|
||||
}
|
||||
else
|
||||
idata->shm_id = cserve2_shared_string_add(shmpath);
|
||||
|
||||
buf = (char *)msg + sizeof(*msg);
|
||||
memcpy(buf, shmpath, path_len);
|
||||
|
||||
|
@ -723,7 +764,7 @@ _scaling_prepare_and_do(Image_Entry *ientry, Image_Data *idata)
|
|||
cserve2_shm_unref(ientry->shm);
|
||||
cserve2_shared_string_del(idata->shm_id);
|
||||
ientry->shm = scale_shm;
|
||||
idata->shm_id = cserve2_shared_string_add(cserve2_shm_name_get(ientry->shm));
|
||||
idata->shm_id = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -891,6 +932,8 @@ _hash_image_entry_free(void *data)
|
|||
{
|
||||
_image_id_free(idata);
|
||||
_image_entry_free(ientry);
|
||||
_freed_image_entry_count++;
|
||||
_repack();
|
||||
}
|
||||
else ERR("Could not find image entry %u", ENTRYID(ientry));
|
||||
}
|
||||
|
@ -951,7 +994,7 @@ _hash_file_entry_free(void *data)
|
|||
_file_data_free(fd);
|
||||
_file_entry_free(fentry);
|
||||
|
||||
_freed_entry_count++;
|
||||
_freed_file_entry_count++;
|
||||
_repack();
|
||||
}
|
||||
|
||||
|
@ -1165,6 +1208,7 @@ _entry_unused_push(Image_Entry *ientry)
|
|||
|
||||
idata = _image_data_find(ENTRYID(ientry));
|
||||
if (!idata) return;
|
||||
idata->unused = EINA_TRUE;
|
||||
|
||||
size = _image_entry_size_get(ientry);
|
||||
if ((size > max_unused_mem_usage) || !(idata->doload))
|
||||
|
@ -1191,7 +1235,6 @@ _entry_unused_push(Image_Entry *ientry)
|
|||
unused_mem_usage = 0;
|
||||
}
|
||||
image_entries_lru = eina_list_append(image_entries_lru, ientry);
|
||||
idata->unused = EINA_TRUE;
|
||||
unused_mem_usage += size;
|
||||
}
|
||||
|
||||
|
@ -1303,6 +1346,13 @@ cserve2_cache_client_new(Client *client)
|
|||
client->files.referencing = eina_hash_int32_new(_entry_free_cb);
|
||||
client->images.referencing = eina_hash_int32_new(_entry_free_cb);
|
||||
client->fonts.referencing = NULL;
|
||||
|
||||
cserve2_index_list_send(cserve2_shared_strings_index_name_get(),
|
||||
cserve2_shared_strings_table_name_get(),
|
||||
cserve2_shared_array_name_get(_file_data_array),
|
||||
cserve2_shared_array_name_get(_image_data_array),
|
||||
NULL,
|
||||
client);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef struct _Data_Shm Data_Shm;
|
||||
typedef struct _Index_Entry Index_Entry;
|
||||
typedef struct _Block Block;
|
||||
typedef struct _Shared_Index Shared_Index;
|
||||
|
||||
|
@ -60,16 +59,6 @@ struct _Block
|
|||
int32_t shmid;
|
||||
};
|
||||
|
||||
struct _Index_Entry
|
||||
{
|
||||
int32_t id; // Write last, can't be 0
|
||||
int32_t refcount;
|
||||
// Block entry
|
||||
int32_t length;
|
||||
int32_t offset;
|
||||
int32_t shmid;
|
||||
};
|
||||
|
||||
|
||||
// Data blocks will be aligned to blocks of DATA_BLOCKSIZE bytes to reduce
|
||||
// fragmentation (after del). 16 is convenient for debugging with hd :)
|
||||
|
@ -159,7 +148,7 @@ _block_rbtree_block_find(const Block *node, const void *key,
|
|||
|
||||
// Data shm
|
||||
|
||||
Data_Shm *
|
||||
static Data_Shm *
|
||||
_shared_data_shm_new(int size)
|
||||
{
|
||||
Data_Shm *ds;
|
||||
|
@ -194,7 +183,7 @@ _shared_data_shm_new(int size)
|
|||
return ds;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
_shared_data_shm_del(Data_Shm *ds)
|
||||
{
|
||||
if (!ds) return;
|
||||
|
@ -202,7 +191,7 @@ _shared_data_shm_del(Data_Shm *ds)
|
|||
free(ds);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
_shared_data_shm_resize(Data_Shm *ds, size_t newsize)
|
||||
{
|
||||
Shm_Handle *shm;
|
||||
|
@ -803,6 +792,24 @@ cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid)
|
|||
|
||||
// Shared strings
|
||||
|
||||
const char *
|
||||
cserve2_shared_strings_table_name_get()
|
||||
{
|
||||
if (!_string_mempool)
|
||||
return NULL;
|
||||
|
||||
return cserve2_shm_name_get(_string_mempool->ds->shm);
|
||||
}
|
||||
|
||||
const char *
|
||||
cserve2_shared_strings_index_name_get()
|
||||
{
|
||||
if (!_string_mempool)
|
||||
return NULL;
|
||||
|
||||
return cserve2_shared_array_name_get(_string_mempool->index->sa);
|
||||
}
|
||||
|
||||
int
|
||||
cserve2_shared_string_add(const char *str)
|
||||
{
|
||||
|
|
|
@ -36,17 +36,27 @@ cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
|
|||
}
|
||||
|
||||
void
|
||||
cserve2_index_list_send(const char *files_index_path,
|
||||
cserve2_index_list_send(const char *strings_index_path,
|
||||
const char *strings_entries_path,
|
||||
const char *files_index_path,
|
||||
const char *images_index_path,
|
||||
const char *fonts_index_path)
|
||||
const char *fonts_index_path,
|
||||
Client *client)
|
||||
{
|
||||
Eina_Iterator *iter;
|
||||
Client *client;
|
||||
Msg_Index_List msg;
|
||||
const int size = sizeof(msg);
|
||||
|
||||
INF("New shared index: strings: '%s':'%s' files: '%s' images: '%s', fonts: '%s'",
|
||||
strings_index_path, strings_entries_path,
|
||||
files_index_path, images_index_path, fonts_index_path);
|
||||
|
||||
memset(&msg, 0, size);
|
||||
msg.base.type = CSERVE2_INDEX_LIST;
|
||||
if (strings_index_path)
|
||||
eina_strlcpy(msg.strings_index_path, strings_index_path, 64);
|
||||
if (strings_entries_path)
|
||||
eina_strlcpy(msg.strings_entries_path, strings_entries_path, 64);
|
||||
if (files_index_path)
|
||||
eina_strlcpy(msg.files_index_path, files_index_path, 64);
|
||||
if (images_index_path)
|
||||
|
@ -54,6 +64,8 @@ cserve2_index_list_send(const char *files_index_path,
|
|||
if (fonts_index_path)
|
||||
eina_strlcpy(msg.fonts_index_path, fonts_index_path, 64);
|
||||
|
||||
if (!client)
|
||||
{
|
||||
iter = eina_hash_iterator_data_new(client_list);
|
||||
EINA_ITERATOR_FOREACH(iter, client)
|
||||
{
|
||||
|
@ -62,6 +74,13 @@ cserve2_index_list_send(const char *files_index_path,
|
|||
cserve2_client_send(client, &msg, sizeof(msg));
|
||||
}
|
||||
eina_iterator_free(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Sending updated list of indexes to client %d", client->id);
|
||||
cserve2_client_send(client, &size, sizeof(size));
|
||||
cserve2_client_send(client, &msg, sizeof(msg));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -275,12 +275,15 @@ struct _Msg_Font_Debug {
|
|||
*/
|
||||
struct _Msg_Index_List {
|
||||
Msg_Base base;
|
||||
char strings_index_path[64];
|
||||
char strings_entries_path[64];
|
||||
char files_index_path[64];
|
||||
char images_index_path[64];
|
||||
char fonts_index_path[64];
|
||||
};
|
||||
|
||||
typedef struct _Shm_Object Shm_Object;
|
||||
typedef struct _Index_Entry Index_Entry;
|
||||
typedef struct _File_Data File_Data;
|
||||
typedef struct _Image_Data Image_Data;
|
||||
typedef struct _Shared_Array_Header Shared_Array_Header;
|
||||
|
@ -304,6 +307,15 @@ struct _Shm_Object
|
|||
SHMOBJECT;
|
||||
};
|
||||
|
||||
struct _Index_Entry
|
||||
{
|
||||
SHMOBJECT;
|
||||
// Block entry
|
||||
int32_t length;
|
||||
int32_t offset;
|
||||
int32_t shmid;
|
||||
};
|
||||
|
||||
struct _File_Data {
|
||||
SHMOBJECT;
|
||||
string_t path;
|
||||
|
|
|
@ -21,6 +21,7 @@ typedef void (*Op_Callback)(void *data, const void *msg, int size);
|
|||
|
||||
struct _File_Entry {
|
||||
unsigned int file_id;
|
||||
unsigned int server_file_id;
|
||||
};
|
||||
|
||||
struct _Client_Request {
|
||||
|
@ -44,7 +45,10 @@ static Eina_List *_requests = NULL;
|
|||
|
||||
// Shared index table
|
||||
static Index_Table _index;
|
||||
static const char *_shared_string_get(int id);
|
||||
static int _server_index_list_set(Msg_Base *data, int size);
|
||||
static const File_Data *_shared_image_entry_file_data_find(Image_Entry *ie);
|
||||
static const Image_Data *_shared_image_entry_image_data_find(Image_Entry *ie);
|
||||
|
||||
#ifndef UNIX_PATH_MAX
|
||||
#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path)
|
||||
|
@ -325,123 +329,6 @@ _next_rid(void)
|
|||
return _rid_count++;
|
||||
}
|
||||
|
||||
// Returns the number of correctly opened index arrays
|
||||
static int
|
||||
_server_index_list_set(Msg_Base *data, int size)
|
||||
{
|
||||
Msg_Index_List *msg = (Msg_Index_List *) data;
|
||||
unsigned sz;
|
||||
int ret = 0;
|
||||
|
||||
if (size != sizeof(*msg) || msg->base.type != CSERVE2_INDEX_LIST)
|
||||
{
|
||||
CRIT("Invalid message! type: %d, size: %d (expected %d)",
|
||||
msg->base.type, size, (int) sizeof(*msg));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Reset index table
|
||||
if (_index.files.f)
|
||||
{
|
||||
if (_index.files.header)
|
||||
eina_file_map_free(_index.files.f, (void *) _index.files.header);
|
||||
eina_file_close(_index.files.f);
|
||||
}
|
||||
if (_index.images.f)
|
||||
{
|
||||
if (_index.images.header)
|
||||
eina_file_map_free(_index.images.f, (void *) _index.images.header);
|
||||
eina_file_close(_index.images.f);
|
||||
}
|
||||
if (_index.fonts.f)
|
||||
{
|
||||
if (_index.fonts.header)
|
||||
eina_file_map_free(_index.fonts.f, (void *) _index.fonts.header);
|
||||
eina_file_close(_index.fonts.f);
|
||||
}
|
||||
memset(&_index, 0, sizeof(_index));
|
||||
|
||||
// Open new indexes
|
||||
eina_strlcpy(_index.files.path, msg->files_index_path, 64);
|
||||
eina_strlcpy(_index.images.path, msg->images_index_path, 64);
|
||||
eina_strlcpy(_index.fonts.path, msg->fonts_index_path, 64);
|
||||
|
||||
if (_index.files.path[0])
|
||||
{
|
||||
_index.files.f = eina_file_open(_index.files.path, EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.files.f);
|
||||
if (sz < sizeof(Shared_Array_Header))
|
||||
{
|
||||
ERR("Shared index for files is too small: %u", sz);
|
||||
eina_file_close(_index.files.f);
|
||||
_index.files.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.files.header = eina_file_map_all(_index.files.f,
|
||||
EINA_FILE_WILLNEED);
|
||||
if (sz < (_index.files.header->count * sizeof(File_Data)
|
||||
+ sizeof(Shared_Array_Header)))
|
||||
{
|
||||
ERR("Shared index size does not match array size: %u / %u",
|
||||
sz, _index.files.header->count);
|
||||
eina_file_map_free(_index.files.f,
|
||||
(void *) _index.files.header);
|
||||
eina_file_close(_index.files.f);
|
||||
_index.files.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.files.entries = (File_Data *) &(_index.files.header[1]);
|
||||
DBG("Mapped files shared index '%s' at %p: %u entries max",
|
||||
_index.files.path, _index.files.header,
|
||||
_index.files.header->count);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_index.images.path[0])
|
||||
{
|
||||
_index.images.f = eina_file_open(_index.images.path, EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.images.f);
|
||||
if (sz < sizeof(Shared_Array_Header))
|
||||
{
|
||||
ERR("Shared index for images is too small: %u", sz);
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.images.header = eina_file_map_all(_index.images.f,
|
||||
EINA_FILE_WILLNEED);
|
||||
if (sz < (_index.images.header->count * sizeof(Image_Data)
|
||||
+ sizeof(Shared_Array_Header)))
|
||||
{
|
||||
ERR("Shared index size does not match array size: %u / %u",
|
||||
sz, _index.images.header->count);
|
||||
eina_file_map_free(_index.images.f,
|
||||
(void *) _index.images.header);
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.images.entries = (Image_Data *) &(_index.images.header[1]);
|
||||
DBG("Mapped images shared index '%s' at %p: %u entries max",
|
||||
_index.images.path, _index.images.header,
|
||||
_index.images.header->count);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_index.fonts.path[0])
|
||||
ERR("Not implemented yet: fonts shared index");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
_server_dispatch(Eina_Bool *failed)
|
||||
{
|
||||
|
@ -546,7 +433,10 @@ _image_opened_cb(void *data, const void *msg_received, int size)
|
|||
*/
|
||||
//DBG("Received OPENED for RID: %d [open_rid: %d]", answer->rid, ie->open_rid);
|
||||
if (answer->rid != ie->open_rid)
|
||||
{
|
||||
WRN("Message rid (%d) differs from expected rid (open_rid: %d)", answer->rid, ie->open_rid);
|
||||
return;
|
||||
}
|
||||
ie->open_rid = 0;
|
||||
|
||||
if (answer->type != CSERVE2_OPENED)
|
||||
|
@ -639,7 +529,10 @@ _image_loaded_cb(void *data, const void *msg_received, int size)
|
|||
|
||||
//DBG("Received LOADED for RID: %d [load_rid: %d]", answer->rid, ie->load_rid);
|
||||
if (answer->rid != ie->load_rid)
|
||||
{
|
||||
WRN("Message rid (%d) differs from expected rid (load_rid: %d)", answer->rid, ie->load_rid);
|
||||
return;
|
||||
}
|
||||
ie->load_rid = 0;
|
||||
|
||||
if (!ie->data2)
|
||||
|
@ -1008,9 +901,25 @@ evas_cserve2_image_load(Image_Entry *ie)
|
|||
int
|
||||
evas_cserve2_image_load_wait(Image_Entry *ie)
|
||||
{
|
||||
const File_Data *fd;
|
||||
|
||||
if (!ie)
|
||||
return CSERVE2_GENERIC;
|
||||
|
||||
fd = _shared_image_entry_file_data_find(ie);
|
||||
if (fd)
|
||||
{
|
||||
INF("Bypassing socket wait (open_rid %d)", ie->open_rid);
|
||||
ie->w = fd->w;
|
||||
ie->h = fd->h;
|
||||
ie->flags.alpha = fd->alpha;
|
||||
ie->animated.loop_hint = fd->loop_hint;
|
||||
ie->animated.loop_count = fd->loop_count;
|
||||
ie->animated.frame_count = fd->frame_count;
|
||||
ie->open_rid = 0;
|
||||
return CSERVE2_NONE;
|
||||
}
|
||||
|
||||
if (ie->open_rid)
|
||||
{
|
||||
if (!_server_dispatch_until(ie->open_rid))
|
||||
|
@ -1045,9 +954,51 @@ evas_cserve2_image_data_load(Image_Entry *ie)
|
|||
int
|
||||
evas_cserve2_image_load_data_wait(Image_Entry *ie)
|
||||
{
|
||||
const Image_Data *idata;
|
||||
|
||||
if (!ie)
|
||||
return CSERVE2_GENERIC;
|
||||
|
||||
idata = _shared_image_entry_image_data_find(ie);
|
||||
if (idata)
|
||||
{
|
||||
// FIXME: Ugly copy & paste from _loaded_handle
|
||||
Data_Entry *dentry = ie->data2;
|
||||
RGBA_Image *im = (RGBA_Image *)ie;
|
||||
const char *shmpath;
|
||||
|
||||
shmpath = _shared_string_get(idata->shm_id);
|
||||
if (!shmpath) goto load_wait;
|
||||
INF("Bypassing image load socket wait. Image found: %d in %s",
|
||||
idata->id, shmpath);
|
||||
|
||||
dentry->shm.mmap_offset = 0;
|
||||
dentry->shm.use_offset = 0;
|
||||
dentry->shm.f = eina_file_open(shmpath, EINA_TRUE);
|
||||
dentry->shm.mmap_size = eina_file_size_get(dentry->shm.f);
|
||||
dentry->shm.image_size = dentry->shm.mmap_size;
|
||||
|
||||
dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED,
|
||||
dentry->shm.mmap_offset,
|
||||
dentry->shm.mmap_size);
|
||||
if (!dentry->shm.data)
|
||||
{
|
||||
DBG("could not mmap the shm file: %d %m", errno);
|
||||
eina_file_close(dentry->shm.f);
|
||||
dentry->shm.f = NULL;
|
||||
goto load_wait;
|
||||
}
|
||||
|
||||
im->image.data = dentry->shm.data;
|
||||
ie->flags.alpha_sparse = idata->alpha_sparse;
|
||||
ie->flags.loaded = EINA_TRUE;
|
||||
im->image.no_free = 1;
|
||||
|
||||
ie->load_rid = 0;
|
||||
return CSERVE2_NONE;
|
||||
}
|
||||
|
||||
load_wait:
|
||||
if (ie->load_rid)
|
||||
{
|
||||
if (!_server_dispatch_until(ie->load_rid))
|
||||
|
@ -1652,4 +1603,431 @@ evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_F
|
|||
return &(out->base);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fast access to shared index tables
|
||||
|
||||
|
||||
// Returns the number of correctly opened index arrays
|
||||
static int
|
||||
_server_index_list_set(Msg_Base *data, int size)
|
||||
{
|
||||
Msg_Index_List *msg = (Msg_Index_List *) data;
|
||||
unsigned sz;
|
||||
int ret = 0;
|
||||
|
||||
// TODO #1: Check populate rule.
|
||||
// TODO #2: Protect memory for read-only access.
|
||||
// TODO #3: Optimize file reopen/remap (esp. strings table)
|
||||
|
||||
if (size != sizeof(*msg) || msg->base.type != CSERVE2_INDEX_LIST)
|
||||
{
|
||||
CRIT("Invalid message! type: %d, size: %d (expected %d)",
|
||||
msg->base.type, size, (int) sizeof(*msg));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Reset index table
|
||||
if (_index.strings.index_file)
|
||||
{
|
||||
if (_index.strings.index_header)
|
||||
eina_file_map_free(_index.strings.index_file,
|
||||
(void *) _index.strings.index_header);
|
||||
eina_file_close(_index.strings.index_file);
|
||||
}
|
||||
if (_index.strings.entries_file)
|
||||
{
|
||||
if (_index.strings.index_header)
|
||||
eina_file_map_free(_index.strings.entries_file,
|
||||
(void *) _index.strings.index_header);
|
||||
eina_file_close(_index.strings.entries_file);
|
||||
}
|
||||
if (_index.files.f)
|
||||
{
|
||||
if (_index.files.header)
|
||||
eina_file_map_free(_index.files.f, (void *) _index.files.header);
|
||||
eina_file_close(_index.files.f);
|
||||
}
|
||||
if (_index.images.f)
|
||||
{
|
||||
if (_index.images.header)
|
||||
eina_file_map_free(_index.images.f, (void *) _index.images.header);
|
||||
eina_file_close(_index.images.f);
|
||||
}
|
||||
if (_index.fonts.f)
|
||||
{
|
||||
if (_index.fonts.header)
|
||||
eina_file_map_free(_index.fonts.f, (void *) _index.fonts.header);
|
||||
eina_file_close(_index.fonts.f);
|
||||
}
|
||||
|
||||
// Open new indexes
|
||||
eina_strlcpy(_index.strings.index_path, msg->strings_index_path, 64);
|
||||
eina_strlcpy(_index.strings.entries_path, msg->strings_entries_path, 64);
|
||||
eina_strlcpy(_index.files.path, msg->files_index_path, 64);
|
||||
eina_strlcpy(_index.images.path, msg->images_index_path, 64);
|
||||
eina_strlcpy(_index.fonts.path, msg->fonts_index_path, 64);
|
||||
|
||||
if (_index.strings.index_path[0] && _index.strings.entries_path[0])
|
||||
{
|
||||
_index.strings.index_file = eina_file_open(_index.strings.index_path,
|
||||
EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.strings.index_file);
|
||||
_index.strings.index_header = eina_file_map_all(
|
||||
_index.strings.index_file, EINA_FILE_POPULATE);
|
||||
if (_index.strings.index_header && sz > sizeof(Shared_Array_Header)
|
||||
&& sz >= (_index.strings.index_header->count * sizeof(Index_Entry)
|
||||
+ sizeof(Shared_Array_Header)))
|
||||
{
|
||||
_index.strings.indexes = (Index_Entry *)
|
||||
&(_index.strings.index_header[1]);
|
||||
_index.strings.entries_file = eina_file_open(
|
||||
_index.strings.entries_path, EINA_TRUE);
|
||||
_index.strings.entries_size = eina_file_size_get(
|
||||
_index.strings.entries_file);
|
||||
_index.strings.data = eina_file_map_all(
|
||||
_index.strings.entries_file, EINA_FILE_RANDOM);
|
||||
if (!_index.strings.entries_size || !_index.strings.data)
|
||||
goto strings_map_failed;
|
||||
DBG("Mapped shared string table with indexes in %s and data in %s",
|
||||
_index.strings.index_path, _index.strings.entries_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
strings_map_failed:
|
||||
eina_file_map_free(_index.strings.entries_file,
|
||||
(void *) _index.strings.data);
|
||||
eina_file_close(_index.strings.entries_file);
|
||||
eina_file_map_free(_index.strings.index_file,
|
||||
(void *) _index.strings.index_header);
|
||||
eina_file_close(_index.strings.index_file);
|
||||
memset(&_index.strings, 0, sizeof(_index.strings));
|
||||
}
|
||||
}
|
||||
|
||||
if (_index.files.path[0])
|
||||
{
|
||||
_index.files.f = eina_file_open(_index.files.path, EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.files.f);
|
||||
if (sz < sizeof(Shared_Array_Header))
|
||||
{
|
||||
ERR("Shared index for files is too small: %u", sz);
|
||||
eina_file_close(_index.files.f);
|
||||
_index.files.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.files.header = eina_file_map_all(_index.files.f,
|
||||
EINA_FILE_POPULATE);
|
||||
if (sz < (_index.files.header->count * sizeof(File_Data)
|
||||
+ sizeof(Shared_Array_Header)))
|
||||
{
|
||||
ERR("Shared index size does not match array size: %u / %u",
|
||||
sz, _index.files.header->count);
|
||||
eina_file_map_free(_index.files.f,
|
||||
(void *) _index.files.header);
|
||||
eina_file_close(_index.files.f);
|
||||
_index.files.f = NULL;
|
||||
_index.files.header = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.files.entries.fdata =
|
||||
(File_Data *) &(_index.files.header[1]);
|
||||
DBG("Mapped files shared index '%s' at %p: %u entries max",
|
||||
_index.files.path, _index.files.header,
|
||||
_index.files.header->count);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_index.images.path[0])
|
||||
{
|
||||
_index.images.f = eina_file_open(_index.images.path, EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.images.f);
|
||||
if (sz < sizeof(Shared_Array_Header))
|
||||
{
|
||||
ERR("Shared index for images is too small: %u", sz);
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = eina_file_size_get(_index.images.f);
|
||||
_index.images.header = eina_file_map_all(_index.images.f,
|
||||
EINA_FILE_POPULATE);
|
||||
if (sz < (_index.images.header->count * sizeof(Image_Data)
|
||||
+ sizeof(Shared_Array_Header)))
|
||||
{
|
||||
ERR("Shared index size does not match array size: %u / %u",
|
||||
sz, _index.images.header->count);
|
||||
eina_file_map_free(_index.images.f,
|
||||
(void *) _index.images.header);
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = NULL;
|
||||
_index.images.header = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index.images.count = (size - sizeof(Shared_Array_Header))
|
||||
/ sizeof(Image_Data);
|
||||
_index.images.entries.idata =
|
||||
(Image_Data *) &(_index.images.header[1]);
|
||||
DBG("Mapped images shared index '%s' at %p: %u entries max",
|
||||
_index.images.path, _index.images.header,
|
||||
_index.images.header->count);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_index.fonts.path[0])
|
||||
ERR("Not implemented yet: fonts shared index");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// FIXME: Copy & paste from evas_cserve2_cache.c
|
||||
static int
|
||||
_shm_object_id_cmp_cb(const void *data1, const void *data2)
|
||||
{
|
||||
const Shm_Object *obj;
|
||||
unsigned int key;
|
||||
|
||||
if (data1 == data2) return 0;
|
||||
if (!data1) return 1;
|
||||
if (!data2) return -1;
|
||||
|
||||
obj = data1;
|
||||
key = *((unsigned int *) data2);
|
||||
if (obj->id == key) return 0;
|
||||
if (obj->id < key)
|
||||
return -1;
|
||||
else
|
||||
return +1;
|
||||
}
|
||||
|
||||
// FIXME: (almost) copy & paste from evas_cserve2_cache.c
|
||||
static const char *
|
||||
_shared_string_get(int id)
|
||||
{
|
||||
const char *ret;
|
||||
const Index_Entry *ie = NULL;
|
||||
int k;
|
||||
|
||||
if (id <= 0) return NULL;
|
||||
if (!_index.strings.data) return NULL;
|
||||
|
||||
// Binary search
|
||||
if (_index.strings.index_header->sortedidx > 0)
|
||||
{
|
||||
int low = 0;
|
||||
int high = _index.strings.index_header->sortedidx;
|
||||
int prev = -1;
|
||||
int r;
|
||||
k = high / 2;
|
||||
while (prev != k)
|
||||
{
|
||||
ie = &(_index.strings.indexes[k]);
|
||||
r = _shm_object_id_cmp_cb(ie, &id);
|
||||
if (!r)
|
||||
goto found;
|
||||
else if (r > 0)
|
||||
high = k;
|
||||
else
|
||||
low = k;
|
||||
prev = k;
|
||||
k = low + (high - low) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Linear search O(n)
|
||||
k = _index.strings.index_header->sortedidx;
|
||||
for (; k < _index.strings.index_header->emptyidx; k++)
|
||||
{
|
||||
ie = &(_index.strings.indexes[k]);
|
||||
if (!_shm_object_id_cmp_cb(ie, &id))
|
||||
goto found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
if (!ie) return NULL;
|
||||
if (!ie->refcount) return NULL;
|
||||
if (ie->length + ie->offset > (int) _index.strings.entries_size)
|
||||
return NULL;
|
||||
|
||||
ret = _index.strings.data + ie->offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
_shared_image_entry_file_data_match(Image_Entry *ie, const File_Data *fd)
|
||||
{
|
||||
const char *path, *key, *loader;
|
||||
|
||||
if (!fd || !ie) return EINA_FALSE;
|
||||
if (!ie->file && !ie->key)
|
||||
return EINA_FALSE;
|
||||
|
||||
path = _shared_string_get(fd->path);
|
||||
key = _shared_string_get(fd->key);
|
||||
loader = _shared_string_get(fd->loader_data);
|
||||
|
||||
if (!path && ie->file)
|
||||
return EINA_FALSE;
|
||||
if (ie->file && strcmp(path, ie->file))
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!key && ie->key)
|
||||
return EINA_FALSE;
|
||||
if (ie->key && strcmp(key, ie->key))
|
||||
return EINA_FALSE;
|
||||
|
||||
/*
|
||||
if (!loader && ie->loader_data)
|
||||
return EINA_FALSE;
|
||||
if (strcmp(loader, ie->loader_data))
|
||||
return EINA_FALSE;
|
||||
*/
|
||||
|
||||
// Check w,h ?
|
||||
// Not sure which load opts should be checked here
|
||||
DBG("Found a match for %s:%s", ie->file, ie->key);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static const File_Data *
|
||||
_shared_image_entry_file_data_find(Image_Entry *ie)
|
||||
{
|
||||
const File_Data *fdata = NULL;
|
||||
File_Entry *fe;
|
||||
int k;
|
||||
|
||||
DBG("Trying to find if image '%s:%s' is already opened by cserve2",
|
||||
ie->file, ie->key);
|
||||
|
||||
if (!_index.files.entries.fdata)
|
||||
return NULL;
|
||||
|
||||
#warning FIXME Use safe count
|
||||
for (k = 0; k < _index.files.header->count; k++)
|
||||
{
|
||||
const File_Data *fd = &(_index.files.entries.fdata[k]);
|
||||
if (!fd->id) return NULL;
|
||||
if (!fd->refcount) continue;
|
||||
|
||||
if (_shared_image_entry_file_data_match(ie, fd))
|
||||
{
|
||||
fdata = fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("Found file data for %s:%s: %d", ie->file, ie->key, fdata->id);
|
||||
fe = ie->data1;
|
||||
fe->server_file_id = fdata->id;
|
||||
return fdata;
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
_shared_image_entry_image_data_match(Image_Entry *ie, const Image_Data *id)
|
||||
{
|
||||
int cmp;
|
||||
cmp = memcmp(&ie->load_opts, &id->opts, sizeof(ie->load_opts));
|
||||
if (!cmp)
|
||||
{
|
||||
DBG("Found loaded image entry at %d", id->id);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static const Image_Data *
|
||||
_shared_image_entry_image_data_find(Image_Entry *ie)
|
||||
{
|
||||
const Image_Data *idata = NULL;
|
||||
File_Entry *fe;
|
||||
unsigned int file_id = 0;
|
||||
int k;
|
||||
|
||||
DBG("Trying to find if image '%s:%s' is already loaded by cserve2",
|
||||
ie->file, ie->key);
|
||||
|
||||
if (!_index.images.entries.idata || !_index.images.count)
|
||||
return NULL;
|
||||
|
||||
fe = ie->data1;
|
||||
if (fe && fe->server_file_id)
|
||||
file_id = fe->server_file_id;
|
||||
else
|
||||
{
|
||||
const File_Data *fdata = _shared_image_entry_file_data_find(ie);
|
||||
if (!fdata)
|
||||
{
|
||||
ERR("File is not opened by cserve2");
|
||||
return NULL;
|
||||
}
|
||||
file_id = fdata->id;
|
||||
}
|
||||
|
||||
// FIXME. Factorize and simplify.
|
||||
if (_index.images.count != _index.images.header->count)
|
||||
{
|
||||
size_t sz;
|
||||
WRN("Image entries array has been resized from %d to %d. Remapping.",
|
||||
_index.images.count, _index.images.header->count);
|
||||
eina_file_map_free(_index.images.f, (void *) _index.images.header);
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = eina_file_open(_index.images.path, EINA_TRUE);
|
||||
sz = eina_file_size_get(_index.images.f);
|
||||
_index.images.header = eina_file_map_new(_index.images.f, EINA_FILE_RANDOM,
|
||||
0, sz); //eina_file_map_all(_index.images.f, EINA_FILE_RANDOM);
|
||||
_index.images.count = _index.images.header->count;
|
||||
if (_index.images.count * sizeof(Image_Data) + sizeof(Shared_Array_Header) > sz)
|
||||
CRIT("New mapping might be too small!");
|
||||
if (!_index.images.header)
|
||||
{
|
||||
ERR("Could not remap the array!");
|
||||
eina_file_close(_index.images.f);
|
||||
_index.images.f = NULL;
|
||||
_index.images.entries.idata = NULL;
|
||||
return NULL;
|
||||
}
|
||||
_index.images.entries.idata =
|
||||
(Image_Data *) &(_index.images.header[1]);
|
||||
}
|
||||
|
||||
DBG("Looking for loaded image with file id %d", file_id);
|
||||
for (k = 0; k < _index.images.count; k++)
|
||||
{
|
||||
const Image_Data *id = &(_index.images.entries.idata[k]);
|
||||
if (!id->id) return NULL;
|
||||
if (!id->refcount) continue;
|
||||
if (id->file_id != file_id) continue;
|
||||
|
||||
if (_shared_image_entry_image_data_match(ie, id))
|
||||
{
|
||||
idata = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!idata)
|
||||
return NULL;
|
||||
|
||||
if (!_shared_string_get(idata->shm_id))
|
||||
{
|
||||
ERR("Found image but it is not loaded yet: %d (doload %d shm %s)",
|
||||
idata->id, idata->doload, _shared_string_get(idata->shm_id));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBG("Found image, loaded, in shm %s", _shared_string_get(idata->shm_id));
|
||||
return idata;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
#include "evas_common_private.h"
|
||||
#include "evas_cs2.h"
|
||||
|
||||
typedef struct _Data_Entry Data_Entry;
|
||||
typedef struct _Font_Entry Font_Entry;
|
||||
typedef struct _Index_Table Index_Table;
|
||||
typedef struct _Shared_Index Shared_Index;
|
||||
|
||||
struct _Data_Entry {
|
||||
unsigned int image_id;
|
||||
void (*preloaded_cb)(void *, Eina_Bool);
|
||||
|
@ -18,30 +23,38 @@ struct _Data_Entry {
|
|||
} shm;
|
||||
};
|
||||
|
||||
struct _Index_Table {
|
||||
struct {
|
||||
struct _Shared_Index {
|
||||
char path[64];
|
||||
Eina_File *f;
|
||||
const Shared_Array_Header *header;
|
||||
const File_Data *entries;
|
||||
} files;
|
||||
struct {
|
||||
char path[64];
|
||||
Eina_File *f;
|
||||
const Shared_Array_Header *header;
|
||||
const Image_Data *entries;
|
||||
} images;
|
||||
struct {
|
||||
char path[64];
|
||||
Eina_File *f;
|
||||
const Shared_Array_Header *header;
|
||||
const void *entries; // FIXME
|
||||
} fonts;
|
||||
union
|
||||
{
|
||||
const Index_Entry *index; // TODO for strings
|
||||
const Image_Data *idata;
|
||||
const File_Data *fdata;
|
||||
// TODO Fonts
|
||||
} entries;
|
||||
int count;
|
||||
Eina_Hash *entries_by_hkey;
|
||||
int last_entry_in_hash;
|
||||
};
|
||||
|
||||
typedef struct _Data_Entry Data_Entry;
|
||||
typedef struct _Font_Entry Font_Entry;
|
||||
typedef struct _Index_Table Index_Table;
|
||||
struct _Index_Table {
|
||||
// TODO: use Shared_Index
|
||||
struct {
|
||||
char index_path[64];
|
||||
char entries_path[64];
|
||||
Eina_File *index_file;
|
||||
Eina_File *entries_file;
|
||||
const Shared_Array_Header *index_header;
|
||||
const Index_Entry *indexes;
|
||||
const char *data;
|
||||
size_t entries_size;
|
||||
} strings;
|
||||
Shared_Index files;
|
||||
Shared_Index images;
|
||||
Shared_Index fonts; // TODO
|
||||
};
|
||||
|
||||
int evas_cserve2_init(void);
|
||||
int evas_cserve2_shutdown(void);
|
||||
|
|
Loading…
Reference in New Issue