evas/cserve2: Scan shared indexes in client side

Read Image descriptors from the shared arrays

But, accessing the shared index can be a bit expensive, so
try to read from the socket before scanning the index,
without blocking.
This commit is contained in:
Jean-Philippe Andre 2013-07-31 20:29:41 +09:00
parent 08648ab2a5
commit f5d0f0aec3
5 changed files with 372 additions and 290 deletions

View File

@ -549,8 +549,10 @@ evas_cache2_shutdown(Evas_Cache2 *cache)
free(cache); free(cache);
} }
static void EAPI void
_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, Evas_Image_Load_Opts *lo) evas_cache2_image_cache_key_create(char *hkey, const char *path, size_t pathlen,
const char *key, size_t keylen,
const Evas_Image_Load_Opts *lo)
{ {
const char *ckey = "(null)"; const char *ckey = "(null)";
size_t size; size_t size;
@ -561,6 +563,7 @@ _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key,
memcpy(hkey + size, "//://", 5); memcpy(hkey + size, "//://", 5);
size += 5; size += 5;
if (key) ckey = key; if (key) ckey = key;
else keylen = 6;
memcpy(hkey + size, ckey, keylen); memcpy(hkey + size, ckey, keylen);
size += keylen; size += keylen;
if (lo) if (lo)
@ -634,7 +637,8 @@ _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key,
} }
EAPI Image_Entry * EAPI Image_Entry *
evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Evas_Image_Load_Opts *lo, int *error) evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key,
Evas_Image_Load_Opts *lo, int *error)
{ {
size_t size; size_t size;
size_t pathlen; size_t pathlen;
@ -659,7 +663,7 @@ evas_cache2_image_open(Evas_Cache2 *cache, const char *path, const char *key, Ev
size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN; size = pathlen + keylen + HKEY_LOAD_OPTS_STR_LEN;
hkey = alloca(sizeof(char) * size); hkey = alloca(sizeof(char) * size);
_create_hash_key(hkey, path, pathlen, key, keylen, lo); evas_cache2_image_cache_key_create(hkey, path, pathlen, key, keylen, lo);
DBG("Looking at the hash for key '%s'", hkey); DBG("Looking at the hash for key '%s'", hkey);
/* use local var to copy default load options to the image entry */ /* use local var to copy default load options to the image entry */
@ -816,7 +820,8 @@ _scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h,
if (!smooth) if (!smooth)
{ {
lo.scale_load.smooth = 1; lo.scale_load.smooth = 1;
_create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
im->key, keylen, &lo);
ret = eina_hash_find(im->cache2->activ, hkey); ret = eina_hash_find(im->cache2->activ, hkey);
if (ret) goto found; if (ret) goto found;
@ -827,7 +832,8 @@ _scaled_image_find(Image_Entry *im, int src_x, int src_y, int src_w, int src_h,
lo.scale_load.smooth = smooth; lo.scale_load.smooth = smooth;
} }
_create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
im->key, keylen, &lo);
ret = eina_hash_find(im->cache2->activ, hkey); ret = eina_hash_find(im->cache2->activ, hkey);
if (ret) goto found; if (ret) goto found;
@ -896,7 +902,8 @@ evas_cache2_image_scale_load(Image_Entry *im,
lo.scale_load.smooth = smooth; lo.scale_load.smooth = smooth;
lo.scale_load.scale_hint = im->scale_hint; lo.scale_load.scale_hint = im->scale_hint;
_create_hash_key(hkey, im->file, pathlen, im->key, keylen, &lo); evas_cache2_image_cache_key_create(hkey, im->file, pathlen,
im->key, keylen, &lo);
ret = _evas_cache_image_entry_new(im->cache2, hkey, NULL, im->file, im->key, ret = _evas_cache_image_entry_new(im->cache2, hkey, NULL, im->file, im->key,
&lo, &error); &lo, &error);

View File

@ -66,6 +66,7 @@ EAPI void evas_cache2_image_close(Image_Entry *im);
EAPI int evas_cache2_image_load_data(Image_Entry *ie); EAPI int evas_cache2_image_load_data(Image_Entry *ie);
EAPI void evas_cache2_image_unload_data(Image_Entry *im); EAPI void evas_cache2_image_unload_data(Image_Entry *im);
EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target); EAPI void evas_cache2_image_preload_data(Image_Entry *im, const void *target);
EAPI void evas_cache2_image_cache_key_create(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, const Evas_Image_Load_Opts *lo);
EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im); EAPI DATA32 * evas_cache2_image_pixels(Image_Entry *im);
EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im); EAPI Image_Entry * evas_cache2_image_writable(Image_Entry *im);

View File

@ -275,6 +275,7 @@ struct _Msg_Font_Debug {
*/ */
struct _Msg_Index_List { struct _Msg_Index_List {
Msg_Base base; Msg_Base base;
int generation_id;
char strings_index_path[64]; char strings_index_path[64];
char strings_entries_path[64]; char strings_entries_path[64];
char files_index_path[64]; char files_index_path[64];

View File

@ -17,6 +17,9 @@
#ifdef EVAS_CSERVE2 #ifdef EVAS_CSERVE2
#define USE_SHARED_INDEX 1
#define SHARED_INDEX_ADD_TO_HASH 1
#define HKEY_LOAD_OPTS_STR_LEN 215
typedef void (*Op_Callback)(void *data, const void *msg, int size); typedef void (*Op_Callback)(void *data, const void *msg, int size);
struct _File_Entry { struct _File_Entry {
@ -47,6 +50,8 @@ static Eina_List *_requests = NULL;
static Index_Table _index; static Index_Table _index;
static const char *_shared_string_get(int id); static const char *_shared_string_get(int id);
static int _server_index_list_set(Msg_Base *data, int size); static int _server_index_list_set(Msg_Base *data, int size);
static const File_Data *_shared_file_data_get_by_id(unsigned int id);
static const Shm_Object *_shared_index_item_get_by_id(Shared_Index *si, int elemsize, unsigned int id);
static const File_Data *_shared_image_entry_file_data_find(Image_Entry *ie); 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); static const Image_Data *_shared_image_entry_image_data_find(Image_Entry *ie);
@ -902,10 +907,21 @@ int
evas_cserve2_image_load_wait(Image_Entry *ie) evas_cserve2_image_load_wait(Image_Entry *ie)
{ {
const File_Data *fd; const File_Data *fd;
Eina_Bool failed;
unsigned int rrid, rid;
if (!ie) if (!ie)
return CSERVE2_GENERIC; return CSERVE2_GENERIC;
if (!ie->open_rid)
return CSERVE2_NONE;
rid = ie->open_rid;
rrid = _server_dispatch(&failed);
if (rid == rrid)
return CSERVE2_NONE;
#if USE_SHARED_INDEX
fd = _shared_image_entry_file_data_find(ie); fd = _shared_image_entry_file_data_find(ie);
if (fd) if (fd)
{ {
@ -919,6 +935,7 @@ evas_cserve2_image_load_wait(Image_Entry *ie)
ie->open_rid = 0; ie->open_rid = 0;
return CSERVE2_NONE; return CSERVE2_NONE;
} }
#endif
if (ie->open_rid) if (ie->open_rid)
{ {
@ -959,6 +976,7 @@ evas_cserve2_image_load_data_wait(Image_Entry *ie)
if (!ie) if (!ie)
return CSERVE2_GENERIC; return CSERVE2_GENERIC;
#if USE_SHARED_INDEX
idata = _shared_image_entry_image_data_find(ie); idata = _shared_image_entry_image_data_find(ie);
if (idata) if (idata)
{ {
@ -997,6 +1015,7 @@ evas_cserve2_image_load_data_wait(Image_Entry *ie)
ie->load_rid = 0; ie->load_rid = 0;
return CSERVE2_NONE; return CSERVE2_NONE;
} }
#endif
load_wait: load_wait:
if (ie->load_rid) if (ie->load_rid)
@ -1607,6 +1626,7 @@ evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_F
// Fast access to shared index tables // Fast access to shared index tables
static Eina_Bool _shared_index_remap_check(Shared_Index *si, int elemsize);
// Returns the number of correctly opened index arrays // Returns the number of correctly opened index arrays
static int static int
@ -1614,7 +1634,6 @@ _server_index_list_set(Msg_Base *data, int size)
{ {
Msg_Index_List *msg = (Msg_Index_List *) data; Msg_Index_List *msg = (Msg_Index_List *) data;
unsigned sz; unsigned sz;
int ret = 0;
// TODO #1: Check populate rule. // TODO #1: Check populate rule.
// TODO #2: Protect memory for read-only access. // TODO #2: Protect memory for read-only access.
@ -1627,276 +1646,162 @@ _server_index_list_set(Msg_Base *data, int size)
return -1; return -1;
} }
// Reset index table if (_index.generation_id == msg->generation_id)
if (_index.strings.index_file)
{ {
if (_index.strings.index_header) ERR("New index generation_id is the same as before: %d",
eina_file_map_free(_index.strings.index_file, _index.generation_id);
(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 _index.generation_id = msg->generation_id;
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]) // 1. Strings (indexes and entries)
if (_index.strings_entries.data
&& strncmp(_index.strings_entries.path, msg->strings_entries_path,
SHARED_BUFFER_PATH_MAX) != 0)
{ {
_index.strings.index_file = eina_file_open(_index.strings.index_path, DBG("Updating string entries shm to: '%s'", msg->strings_entries_path);
EINA_TRUE); eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
sz = eina_file_size_get(_index.strings.index_file); eina_file_close(_index.strings_entries.f);
_index.strings.index_header = eina_file_map_all( _index.strings_entries.f = NULL;
_index.strings.index_file, EINA_FILE_POPULATE); _index.strings_entries.data = NULL;
if (_index.strings.index_header && sz > sizeof(Shared_Array_Header) }
&& sz >= (_index.strings.index_header->count * sizeof(Index_Entry)
+ sizeof(Shared_Array_Header))) if (_index.strings_index.data
&& strncmp(_index.strings_index.path, msg->strings_index_path,
SHARED_BUFFER_PATH_MAX) != 0)
{
DBG("Updating string indexes shm to: '%s'", msg->strings_index_path);
eina_file_map_free(_index.strings_index.f, _index.strings_index.data);
eina_file_close(_index.strings_index.f);
_index.strings_index.f = NULL;
_index.strings_index.data = NULL;
}
eina_strlcpy(_index.strings_entries.path, msg->strings_entries_path, SHARED_BUFFER_PATH_MAX);
eina_strlcpy(_index.strings_index.path, msg->strings_index_path, SHARED_BUFFER_PATH_MAX);
if (!_index.strings_entries.data
&& _index.strings_entries.path[0]
&& _index.strings_index.path[0])
{
_index.strings_entries.f = eina_file_open(_index.strings_entries.path, EINA_TRUE);
_index.strings_entries.size = eina_file_size_get(_index.strings_entries.f);
if (_index.strings_entries.size > 0)
_index.strings_entries.data = eina_file_map_all(_index.strings_entries.f, EINA_FILE_RANDOM);
if (!_index.strings_entries.data)
{ {
_index.strings.indexes = (Index_Entry *) ERR("Could not map strings entries from: '%s'", _index.strings_entries.path);
&(_index.strings.index_header[1]); eina_file_close(_index.strings_entries.f);
_index.strings.entries_file = eina_file_open( _index.strings_entries.f = NULL;
_index.strings.entries_path, EINA_TRUE); _index.strings_entries.data = NULL;
_index.strings.entries_size = eina_file_size_get( }
_index.strings.entries_file); else DBG("Mapped string entries from %s", _index.strings_entries.path);
_index.strings.data = eina_file_map_all( }
_index.strings.entries_file, EINA_FILE_RANDOM);
if (!_index.strings.entries_size || !_index.strings.data) if (_index.strings_entries.data &&
goto strings_map_failed; (!_index.strings_index.data && _index.strings_index.path[0]))
DBG("Mapped shared string table with indexes in %s and data in %s", {
_index.strings.index_path, _index.strings.entries_path); _index.strings_index.f = eina_file_open(_index.strings_index.path, EINA_TRUE);
sz = eina_file_size_get(_index.strings_index.f);
if (sz >= sizeof(Shared_Array_Header))
_index.strings_index.data = eina_file_map_all(_index.strings_index.f, EINA_FILE_RANDOM);
if (_index.strings_index.data)
{
DBG("Mapped string indexes from %s", _index.strings_index.path);
sz = eina_file_size_get(_index.strings_index.f);
_index.strings_index.count = (sz - sizeof(Shared_Array_Header)) / sizeof(Index_Entry);
if (_index.strings_index.count > _index.strings_index.header->count)
{
WRN("Detected larger index than advertised: %d > %d",
_index.strings_index.count, _index.strings_index.header->count);
_index.strings_index.count = _index.strings_index.header->count;
}
} }
else else
{ {
strings_map_failed: ERR("Could not map string indexes from %s", _index.strings_index.path);
eina_file_map_free(_index.strings.entries_file, eina_file_close(_index.strings_index.f);
(void *) _index.strings.data); eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data);
eina_file_close(_index.strings.entries_file); eina_file_close(_index.strings_entries.f);
eina_file_map_free(_index.strings.index_file, _index.strings_index.f = NULL;
(void *) _index.strings.index_header); _index.strings_entries.f = NULL;
eina_file_close(_index.strings.index_file); _index.strings_entries.data = NULL;
memset(&_index.strings, 0, sizeof(_index.strings));
} }
} }
if (_index.files.path[0]) _shared_index_remap_check(&_index.strings_index, sizeof(Index_Entry));
if (_index.strings_entries.data)
{ {
_index.files.f = eina_file_open(_index.files.path, EINA_TRUE); if (eina_file_refresh(_index.strings_entries.f))
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_map_free(_index.strings_entries.f, _index.strings_entries.data);
eina_file_close(_index.files.f); _index.strings_entries.data = eina_file_map_all(_index.strings_entries.f, EINA_FILE_RANDOM);
_index.files.f = NULL; _index.strings_entries.size = eina_file_size_get(_index.strings_entries.f);
}
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]) // 2. File indexes
ERR("Not implemented yet: fonts shared index");
return ret; eina_strlcpy(_index.files.path, msg->files_index_path, SHARED_BUFFER_PATH_MAX);
} _shared_index_remap_check(&_index.files, sizeof(File_Data));
// 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; // 3. Image indexes
if (!data1) return 1;
if (!data2) return -1;
obj = data1; eina_strlcpy(_index.images.path, msg->images_index_path, SHARED_BUFFER_PATH_MAX);
key = *((unsigned int *) data2); _shared_index_remap_check(&_index.images, sizeof(Image_Data));
if (obj->id == key) return 0;
if (obj->id < key)
return -1; // 4. Font indexes
else // TODO
return +1;
return 0;
} }
// FIXME: (almost) copy & paste from evas_cserve2_cache.c // FIXME: (almost) copy & paste from evas_cserve2_cache.c
static const char * static const char *
_shared_string_get(int id) _shared_string_get(int id)
{ {
const char *ret; Index_Entry *ie;
const Index_Entry *ie = NULL;
int k;
if (id <= 0) return NULL; ie = (Index_Entry *)
if (!_index.strings.data) return NULL; _shared_index_item_get_by_id(&_index.strings_index, sizeof(*ie), id);
// 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) return NULL;
if (ie->offset < 0) return NULL;
if (!ie->refcount) return NULL; if (!ie->refcount) return NULL;
if (ie->length + ie->offset > (int) _index.strings.entries_size) if (ie->offset + ie->length > _index.strings_entries.size) return NULL;
return NULL;
ret = _index.strings.data + ie->offset; return _index.strings_entries.data + ie->offset;
return ret;
} }
static inline Eina_Bool #define SHARED_INDEX_CHECK(si, typ) \
_shared_image_entry_file_data_match(Image_Entry *ie, const File_Data *fd) do { if (!_shared_index_remap_check(&(si), sizeof(typ))) { \
CRIT("Failed to remap index"); return NULL; } } while (0)
static const char *
_shared_file_data_hkey_get(char *hkey, const char *file, const char *key,
size_t hkey_size)
{ {
const char *path, *key, *loader; size_t keylen, filelen;
if (!fd || !ie) return EINA_FALSE; if (key) keylen = strlen(key) + 1;
if (!ie->file && !ie->key) filelen = strlen(file);
return EINA_FALSE;
path = _shared_string_get(fd->path); if (filelen + keylen + 1 > hkey_size)
key = _shared_string_get(fd->key); return NULL;
loader = _shared_string_get(fd->loader_data);
if (!path && ie->file) memcpy(hkey, file, filelen);
return EINA_FALSE; hkey[filelen] = ':';
if (ie->file && strcmp(path, ie->file)) if (key)
return EINA_FALSE; memcpy(hkey + filelen + 1, key, keylen);
else
memcpy(hkey + filelen + 1, "(null)", 7);
if (!key && ie->key) return hkey;
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 * static const File_Data *
@ -1904,32 +1809,122 @@ _shared_image_entry_file_data_find(Image_Entry *ie)
{ {
const File_Data *fdata = NULL; const File_Data *fdata = NULL;
File_Entry *fe; File_Entry *fe;
Eina_Bool add_to_hash = SHARED_INDEX_ADD_TO_HASH;
char hkey[PATH_MAX];
int k; int k;
DBG("Trying to find if image '%s:%s' is already opened by cserve2", DBG("Trying to find if image '%s:%s' is already opened by cserve2",
ie->file, ie->key); ie->file, ie->key);
if (!_index.files.entries.fdata) SHARED_INDEX_CHECK(_index.files, File_Data);
if (!_index.strings_index.header || !_index.strings_entries.data)
return NULL; return NULL;
#warning FIXME Use safe count if (!_index.files.header || !_index.files.entries.fdata)
for (k = 0; k < _index.files.header->count; k++) return NULL;
{
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)) // Direct access
{ fe = ie->data1;
fdata = fd; if (fe->server_file_id)
break; {
} if ((fdata = _shared_file_data_get_by_id(fe->server_file_id)) != NULL)
return fdata;
} }
DBG("Found file data for %s:%s: %d", ie->file, ie->key, fdata->id); // Check hash
fe = ie->data1; _shared_file_data_hkey_get(hkey, ie->file, ie->key, PATH_MAX);
fe->server_file_id = fdata->id; fdata = eina_hash_find(_index.files.entries_by_hkey, hkey);
return fdata; if (fdata)
return fdata;
// Scan shared index
for (k = _index.files.last_entry_in_hash;
k < _index.files.count && k < _index.files.header->emptyidx; k++)
{
const char *file, *key;
const File_Data *fd;
char fd_hkey[PATH_MAX];
fd = &(_index.files.entries.fdata[k]);
if (!fd->id) break;
if (!fd->refcount) continue;
file = _shared_string_get(fd->path);
if (!file)
{
ERR("Could not find filename for file %d", fd->id);
add_to_hash = EINA_FALSE;
continue;
}
key = _shared_string_get(fd->key);
_shared_file_data_hkey_get(fd_hkey, file, key, PATH_MAX);
if (add_to_hash)
{
eina_hash_add(_index.files.entries_by_hkey, fd_hkey, fd);
_index.files.last_entry_in_hash = k;
}
if (!strcmp(hkey, fd_hkey))
return fd;
}
return NULL;
}
static const Shm_Object *
_shared_index_item_get_by_id(Shared_Index *si, int elemsize, unsigned int id)
{
const Shm_Object *obj;
const char *base;
int low = 0, high, start_high;
int cur;
if (!si || elemsize <= 0 || !id)
return NULL;
// FIXME: HACK (consider all arrays always sorted by id)
high = si->header->emptyidx; // Should be si->header->sortedidx
if (high > si->count)
high = si->count;
base = si->data + sizeof(Shared_Array_Header);
// Binary search
start_high = high;
while(high != low)
{
cur = low + ((high - low) / 2);
obj = (Shm_Object *) (base + (elemsize * cur));
if (obj->id == id)
return obj;
if (obj->id < id)
low = cur + 1;
else
high = cur;
}
// Linear search
for (cur = start_high; cur < si->count; cur++)
{
obj = (Shm_Object *) (base + (elemsize * cur));
if (!obj->id)
return NULL;
if (obj->id == id)
return obj;
}
return NULL;
}
static const File_Data *
_shared_file_data_get_by_id(unsigned int id)
{
return (const File_Data *)
_shared_index_item_get_by_id(&_index.files, sizeof(File_Data), id);
} }
static inline Eina_Bool static inline Eina_Bool
@ -1945,9 +1940,6 @@ _shared_image_entry_image_data_match(Image_Entry *ie, const Image_Data *id)
return EINA_FALSE; return EINA_FALSE;
} }
#define SHARED_INDEX_CHECK(si, typ) \
if (!_shared_index_remap_check(&(si), sizeof(typ))) return NULL
static Eina_Bool static Eina_Bool
_shared_index_remap_check(Shared_Index *si, int elemsize) _shared_index_remap_check(Shared_Index *si, int elemsize)
{ {
@ -1957,22 +1949,39 @@ _shared_index_remap_check(Shared_Index *si, int elemsize)
// Note: all checks are unlikely to be true. // Note: all checks are unlikely to be true.
if (!si || elemsize <= 0) return EINA_FALSE; if (!si || elemsize <= 0) return EINA_FALSE;
if (si->generation_id != _index.generation_id) if (si->generation_id != _index.generation_id)
{ {
DBG("Generation ID changed."); DBG("Generation ID changed from %d to %d.",
if (si->f && si->data) si->generation_id, _index.generation_id);
if (si->f)
{ {
if (eina_file_refresh(si->f)) if (strncmp(si->path, eina_file_filename_get(si->f),
SHARED_BUFFER_PATH_MAX) != 0)
{ {
DBG("Remapping index."); DBG("Index file changed. Closing and reopening.");
eina_file_map_free(si->f, si->data); eina_file_map_free(si->f, si->data);
eina_file_close(si->f);
si->f = NULL;
si->data = NULL; si->data = NULL;
} }
} else
else if (si->f) {
{ if (si->data)
eina_file_close(si->f); {
si->f = NULL; if (eina_file_refresh(si->f))
{
DBG("Remapping index.");
eina_file_map_free(si->f, si->data);
si->data = NULL;
}
}
else
{
eina_file_close(si->f);
si->f = NULL;
}
}
} }
si->generation_id = _index.generation_id; si->generation_id = _index.generation_id;
} }
@ -2039,6 +2048,7 @@ _shared_index_remap_check(Shared_Index *si, int elemsize)
if (si->entries_by_hkey) eina_hash_free_buckets(si->entries_by_hkey); if (si->entries_by_hkey) eina_hash_free_buckets(si->entries_by_hkey);
else si->entries_by_hkey = eina_hash_string_small_new(NULL); else si->entries_by_hkey = eina_hash_string_small_new(NULL);
si->last_entry_in_hash = 0; si->last_entry_in_hash = 0;
si->entries.p = si->data + sizeof(Shared_Array_Header);
} }
return EINA_TRUE; return EINA_TRUE;
@ -2048,16 +2058,28 @@ static const Image_Data *
_shared_image_entry_image_data_find(Image_Entry *ie) _shared_image_entry_image_data_find(Image_Entry *ie)
{ {
const Image_Data *idata = NULL; const Image_Data *idata = NULL;
const char *shmpath;
File_Entry *fe; File_Entry *fe;
unsigned int file_id = 0; unsigned int file_id = 0;
Eina_Bool add_to_hash = SHARED_INDEX_ADD_TO_HASH;
int k; int k;
DBG("Trying to find if image '%s:%s' is already loaded by cserve2", DBG("Trying to find if image '%s:%s' is already loaded by cserve2",
ie->file, ie->key); ie->file, ie->key);
if (!_index.strings_entries.data || !_index.strings_index.data)
return NULL;
if (!_index.images.entries.idata || !_index.images.count) if (!_index.images.entries.idata || !_index.images.count)
return NULL; return NULL;
if (!ie->cache_key)
{
CRIT("Looking for an image in remote cache without hash key?");
return NULL;
}
fe = ie->data1; fe = ie->data1;
if (fe && fe->server_file_id) if (fe && fe->server_file_id)
file_id = fe->server_file_id; file_id = fe->server_file_id;
@ -2074,32 +2096,79 @@ _shared_image_entry_image_data_find(Image_Entry *ie)
SHARED_INDEX_CHECK(_index.images, Image_Data); SHARED_INDEX_CHECK(_index.images, Image_Data);
DBG("Looking for loaded image with file id %d", file_id); // Find in known entries hash. O(log n)
for (k = 0; k < _index.images.count; k++) DBG("Looking for %s in hash", ie->cache_key);
idata = (const Image_Data *)
eina_hash_find(_index.images.entries_by_hkey, ie->cache_key);
if (idata)
{ {
ERR("Image found in shared index (by cache_key).");
goto found;
}
// Linear search in non-hashed entries. O(n)
DBG("Looking for loaded image with file id %d", file_id);
for (k = _index.images.last_entry_in_hash; k < _index.images.count; k++)
{
const char *file, *key;
size_t keylen, filelen;
const File_Data *fd;
char *hkey;
const Image_Data *id = &(_index.images.entries.idata[k]); const Image_Data *id = &(_index.images.entries.idata[k]);
if (!id->id) return NULL; if (!id->id) return NULL;
if (!id->refcount) continue; if (!id->refcount) continue;
if (add_to_hash)
{
fd = _shared_file_data_get_by_id(id->file_id);
if (!fd)
{
ERR("Did not find file data for %d", id->file_id);
add_to_hash = EINA_FALSE;
continue;
}
key = _shared_string_get(fd->key);
file = _shared_string_get(fd->path);
if (!file)
{
ERR("No filename for file %d", fd->id);
add_to_hash = EINA_FALSE;
continue;
}
keylen = key ? strlen(key) : 0;
filelen = strlen(file);
hkey = alloca(filelen + keylen + HKEY_LOAD_OPTS_STR_LEN);
evas_cache2_image_cache_key_create(hkey, file, filelen,
key, keylen, &id->opts);
eina_hash_add(_index.images.entries_by_hkey, hkey, id);
_index.images.last_entry_in_hash = k;
}
if (id->file_id != file_id) continue; if (id->file_id != file_id) continue;
if (_shared_image_entry_image_data_match(ie, id)) if (_shared_image_entry_image_data_match(ie, id))
{ {
idata = id; idata = id;
break; goto found;
} }
} }
if (!idata) if (!idata)
return NULL; return NULL;
if (!_shared_string_get(idata->shm_id)) found:
shmpath = _shared_string_get(idata->shm_id);
if (!shmpath)
{ {
ERR("Found image but it is not loaded yet: %d (doload %d shm %s)", ERR("Found image but it is not loaded yet: %d (doload %d)",
idata->id, idata->doload, _shared_string_get(idata->shm_id)); idata->id, idata->doload);
return NULL; return NULL;
} }
DBG("Found image, loaded, in shm %s", _shared_string_get(idata->shm_id)); DBG("Found image, loaded, in shm %s", shmpath);
return idata; return idata;
} }

View File

@ -4,12 +4,15 @@
#include "evas_common_private.h" #include "evas_common_private.h"
#include "evas_cs2.h" #include "evas_cs2.h"
#define SHARED_BUFFER_PATH_MAX 64
typedef struct _Data_Entry Data_Entry; typedef struct _Data_Entry Data_Entry;
typedef struct _Font_Entry Font_Entry; typedef struct _Font_Entry Font_Entry;
typedef struct _Index_Table Index_Table; typedef struct _Index_Table Index_Table;
typedef struct _Shared_Index Shared_Index; typedef struct _Shared_Index Shared_Index;
typedef struct _Shared_Buffer Shared_Buffer;
struct _Data_Entry { struct _Data_Entry
{
unsigned int image_id; unsigned int image_id;
void (*preloaded_cb)(void *, Eina_Bool); void (*preloaded_cb)(void *, Eina_Bool);
struct { struct {
@ -23,14 +26,15 @@ struct _Data_Entry {
} shm; } shm;
}; };
struct _Shared_Index { struct _Shared_Index
char path[64]; {
char path[SHARED_BUFFER_PATH_MAX];
int generation_id; int generation_id;
Eina_File *f; Eina_File *f;
union union
{ {
const Shared_Array_Header *header; const Shared_Array_Header *header;
void *data; char *data;
}; };
union union
{ {
@ -45,19 +49,19 @@ struct _Shared_Index {
int last_entry_in_hash; int last_entry_in_hash;
}; };
struct _Index_Table { struct _Shared_Buffer
{
char path[SHARED_BUFFER_PATH_MAX];
Eina_File *f;
char *data;
int size;
};
struct _Index_Table
{
int generation_id; int generation_id;
// TODO: use Shared_Index Shared_Buffer strings_entries;
struct { Shared_Index strings_index;
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 files;
Shared_Index images; Shared_Index images;
Shared_Index fonts; // TODO Shared_Index fonts; // TODO