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:
Jean-Philippe Andre 2013-07-29 15:41:23 +09:00
parent 47be3a2b81
commit 88ef4131a0
7 changed files with 655 additions and 174 deletions

View File

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

View File

@ -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,19 +333,46 @@ _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:
// FIXME TODO: Repack image data array as well
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));
cserve2_index_list_send(cserve2_shared_array_name_get(_file_data_array),
cserve2_shared_array_name_get(_image_data_array),
NULL);
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;
}
cserve2_shared_array_del(_image_data_array);
_freed_image_entry_count = 0;
_image_data_array = sa;
updated = EINA_TRUE;
}
skip_images:
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

View File

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

View File

@ -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,14 +64,23 @@ cserve2_index_list_send(const char *files_index_path,
if (fonts_index_path)
eina_strlcpy(msg.fonts_index_path, fonts_index_path, 64);
iter = eina_hash_iterator_data_new(client_list);
EINA_ITERATOR_FOREACH(iter, client)
if (!client)
{
iter = eina_hash_iterator_data_new(client_list);
EINA_ITERATOR_FOREACH(iter, client)
{
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));
}
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));
}
eina_iterator_free(iter);
}
static void

View File

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

View File

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

View File

@ -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 {
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;
struct _Shared_Index {
char path[64];
Eina_File *f;
const Shared_Array_Header *header;
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);