diff --git a/src/lib/evas/cache2/evas_cache2.c b/src/lib/evas/cache2/evas_cache2.c index 81fd78c8d8..77585abe47 100644 --- a/src/lib/evas/cache2/evas_cache2.c +++ b/src/lib/evas/cache2/evas_cache2.c @@ -549,8 +549,10 @@ evas_cache2_shutdown(Evas_Cache2 *cache) free(cache); } -static void -_create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, size_t keylen, Evas_Image_Load_Opts *lo) +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) { const char *ckey = "(null)"; 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); size += 5; if (key) ckey = key; + else keylen = 6; memcpy(hkey + size, ckey, keylen); size += keylen; if (lo) @@ -634,7 +637,8 @@ _create_hash_key(char *hkey, const char *path, size_t pathlen, const char *key, } 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 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; 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); /* 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) { 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); 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; } - _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); if (ret) goto found; @@ -896,7 +902,8 @@ evas_cache2_image_scale_load(Image_Entry *im, lo.scale_load.smooth = smooth; 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, &lo, &error); diff --git a/src/lib/evas/cache2/evas_cache2.h b/src/lib/evas/cache2/evas_cache2.h index f6ba8f881e..6f8e588493 100644 --- a/src/lib/evas/cache2/evas_cache2.h +++ b/src/lib/evas/cache2/evas_cache2.h @@ -66,6 +66,7 @@ EAPI void evas_cache2_image_close(Image_Entry *im); 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_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 Image_Entry * evas_cache2_image_writable(Image_Entry *im); diff --git a/src/lib/evas/cserve2/evas_cs2.h b/src/lib/evas/cserve2/evas_cs2.h index 7cb6e08375..19bf8063ac 100644 --- a/src/lib/evas/cserve2/evas_cs2.h +++ b/src/lib/evas/cserve2/evas_cs2.h @@ -275,6 +275,7 @@ struct _Msg_Font_Debug { */ struct _Msg_Index_List { Msg_Base base; + int generation_id; char strings_index_path[64]; char strings_entries_path[64]; char files_index_path[64]; diff --git a/src/lib/evas/cserve2/evas_cs2_client.c b/src/lib/evas/cserve2/evas_cs2_client.c index d7cd8147c5..5b8e463f10 100644 --- a/src/lib/evas/cserve2/evas_cs2_client.c +++ b/src/lib/evas/cserve2/evas_cs2_client.c @@ -17,6 +17,9 @@ #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); struct _File_Entry { @@ -47,6 +50,8 @@ static Eina_List *_requests = NULL; 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_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 Image_Data *_shared_image_entry_image_data_find(Image_Entry *ie); @@ -902,10 +907,21 @@ int evas_cserve2_image_load_wait(Image_Entry *ie) { const File_Data *fd; + Eina_Bool failed; + unsigned int rrid, rid; if (!ie) 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); if (fd) { @@ -919,6 +935,7 @@ evas_cserve2_image_load_wait(Image_Entry *ie) ie->open_rid = 0; return CSERVE2_NONE; } +#endif if (ie->open_rid) { @@ -959,6 +976,7 @@ evas_cserve2_image_load_data_wait(Image_Entry *ie) if (!ie) return CSERVE2_GENERIC; +#if USE_SHARED_INDEX idata = _shared_image_entry_image_data_find(ie); if (idata) { @@ -997,6 +1015,7 @@ evas_cserve2_image_load_data_wait(Image_Entry *ie) ie->load_rid = 0; return CSERVE2_NONE; } +#endif load_wait: 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 +static Eina_Bool _shared_index_remap_check(Shared_Index *si, int elemsize); // Returns the number of correctly opened index arrays static int @@ -1614,7 +1634,6 @@ _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. @@ -1627,276 +1646,162 @@ _server_index_list_set(Msg_Base *data, int size) return -1; } - // Reset index table - if (_index.strings.index_file) + if (_index.generation_id == msg->generation_id) { - 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); + ERR("New index generation_id is the same as before: %d", + _index.generation_id); } - // 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); + _index.generation_id = msg->generation_id; - 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, - 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))) + DBG("Updating string entries shm to: '%s'", msg->strings_entries_path); + eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data); + eina_file_close(_index.strings_entries.f); + _index.strings_entries.f = NULL; + _index.strings_entries.data = NULL; + } + + 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 *) - &(_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); + ERR("Could not map strings entries from: '%s'", _index.strings_entries.path); + eina_file_close(_index.strings_entries.f); + _index.strings_entries.f = NULL; + _index.strings_entries.data = NULL; + } + else DBG("Mapped string entries from %s", _index.strings_entries.path); + } + + if (_index.strings_entries.data && + (!_index.strings_index.data && _index.strings_index.path[0])) + { + _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 { -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)); + ERR("Could not map string indexes from %s", _index.strings_index.path); + eina_file_close(_index.strings_index.f); + eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data); + eina_file_close(_index.strings_entries.f); + _index.strings_index.f = NULL; + _index.strings_entries.f = NULL; + _index.strings_entries.data = NULL; } } - 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); - sz = eina_file_size_get(_index.files.f); - if (sz < sizeof(Shared_Array_Header)) + if (eina_file_refresh(_index.strings_entries.f)) { - 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++; - } + eina_file_map_free(_index.strings_entries.f, _index.strings_entries.data); + _index.strings_entries.data = eina_file_map_all(_index.strings_entries.f, EINA_FILE_RANDOM); + _index.strings_entries.size = eina_file_size_get(_index.strings_entries.f); } } - 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"); + // 2. File indexes - 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; - if (!data1) return 1; - if (!data2) return -1; + // 3. Image indexes - obj = data1; - key = *((unsigned int *) data2); - if (obj->id == key) return 0; - if (obj->id < key) - return -1; - else - return +1; + eina_strlcpy(_index.images.path, msg->images_index_path, SHARED_BUFFER_PATH_MAX); + _shared_index_remap_check(&_index.images, sizeof(Image_Data)); + + + // 4. Font indexes + // TODO + + return 0; } // 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; + Index_Entry *ie; - 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: + ie = (Index_Entry *) + _shared_index_item_get_by_id(&_index.strings_index, sizeof(*ie), id); if (!ie) return NULL; + if (ie->offset < 0) return NULL; if (!ie->refcount) return NULL; - if (ie->length + ie->offset > (int) _index.strings.entries_size) - return NULL; + if (ie->offset + ie->length > _index.strings_entries.size) return NULL; - ret = _index.strings.data + ie->offset; - return ret; + return _index.strings_entries.data + ie->offset; } -static inline Eina_Bool -_shared_image_entry_file_data_match(Image_Entry *ie, const File_Data *fd) +#define SHARED_INDEX_CHECK(si, typ) \ + 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 (!ie->file && !ie->key) - return EINA_FALSE; + if (key) keylen = strlen(key) + 1; + filelen = strlen(file); - path = _shared_string_get(fd->path); - key = _shared_string_get(fd->key); - loader = _shared_string_get(fd->loader_data); + if (filelen + keylen + 1 > hkey_size) + return NULL; - if (!path && ie->file) - return EINA_FALSE; - if (ie->file && strcmp(path, ie->file)) - return EINA_FALSE; + memcpy(hkey, file, filelen); + hkey[filelen] = ':'; + if (key) + memcpy(hkey + filelen + 1, key, keylen); + else + memcpy(hkey + filelen + 1, "(null)", 7); - 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; + return hkey; } static const File_Data * @@ -1904,32 +1809,122 @@ _shared_image_entry_file_data_find(Image_Entry *ie) { const File_Data *fdata = NULL; File_Entry *fe; + Eina_Bool add_to_hash = SHARED_INDEX_ADD_TO_HASH; + char hkey[PATH_MAX]; int k; DBG("Trying to find if image '%s:%s' is already opened by cserve2", 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; -#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 (!_index.files.header || !_index.files.entries.fdata) + return NULL; - if (_shared_image_entry_file_data_match(ie, fd)) - { - fdata = fd; - break; - } + // Direct access + fe = ie->data1; + if (fe->server_file_id) + { + 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); - fe = ie->data1; - fe->server_file_id = fdata->id; - return fdata; + // Check hash + _shared_file_data_hkey_get(hkey, ie->file, ie->key, PATH_MAX); + fdata = eina_hash_find(_index.files.entries_by_hkey, hkey); + 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 @@ -1945,9 +1940,6 @@ _shared_image_entry_image_data_match(Image_Entry *ie, const Image_Data *id) return EINA_FALSE; } -#define SHARED_INDEX_CHECK(si, typ) \ - if (!_shared_index_remap_check(&(si), sizeof(typ))) return NULL - static Eina_Bool _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. if (!si || elemsize <= 0) return EINA_FALSE; + if (si->generation_id != _index.generation_id) { - DBG("Generation ID changed."); - if (si->f && si->data) + DBG("Generation ID changed from %d to %d.", + 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_close(si->f); + si->f = NULL; si->data = NULL; } - } - else if (si->f) - { - eina_file_close(si->f); - si->f = NULL; + else + { + if (si->data) + { + 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; } @@ -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); else si->entries_by_hkey = eina_hash_string_small_new(NULL); si->last_entry_in_hash = 0; + si->entries.p = si->data + sizeof(Shared_Array_Header); } return EINA_TRUE; @@ -2048,16 +2058,28 @@ static const Image_Data * _shared_image_entry_image_data_find(Image_Entry *ie) { const Image_Data *idata = NULL; + const char *shmpath; File_Entry *fe; unsigned int file_id = 0; + Eina_Bool add_to_hash = SHARED_INDEX_ADD_TO_HASH; int k; + DBG("Trying to find if image '%s:%s' is already loaded by cserve2", ie->file, ie->key); + if (!_index.strings_entries.data || !_index.strings_index.data) + return NULL; + if (!_index.images.entries.idata || !_index.images.count) return NULL; + if (!ie->cache_key) + { + CRIT("Looking for an image in remote cache without hash key?"); + return NULL; + } + fe = ie->data1; if (fe && 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); - DBG("Looking for loaded image with file id %d", file_id); - for (k = 0; k < _index.images.count; k++) + // Find in known entries hash. O(log n) + 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]); + if (!id->id) return NULL; 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 (_shared_image_entry_image_data_match(ie, id)) { idata = id; - break; + goto found; } } if (!idata) 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)", - idata->id, idata->doload, _shared_string_get(idata->shm_id)); + ERR("Found image but it is not loaded yet: %d (doload %d)", + idata->id, idata->doload); 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; } diff --git a/src/lib/evas/cserve2/evas_cs2_private.h b/src/lib/evas/cserve2/evas_cs2_private.h index 289119f34d..d1c53660b1 100644 --- a/src/lib/evas/cserve2/evas_cs2_private.h +++ b/src/lib/evas/cserve2/evas_cs2_private.h @@ -4,12 +4,15 @@ #include "evas_common_private.h" #include "evas_cs2.h" +#define SHARED_BUFFER_PATH_MAX 64 typedef struct _Data_Entry Data_Entry; typedef struct _Font_Entry Font_Entry; typedef struct _Index_Table Index_Table; typedef struct _Shared_Index Shared_Index; +typedef struct _Shared_Buffer Shared_Buffer; -struct _Data_Entry { +struct _Data_Entry +{ unsigned int image_id; void (*preloaded_cb)(void *, Eina_Bool); struct { @@ -23,14 +26,15 @@ struct _Data_Entry { } shm; }; -struct _Shared_Index { - char path[64]; +struct _Shared_Index +{ + char path[SHARED_BUFFER_PATH_MAX]; int generation_id; Eina_File *f; union { const Shared_Array_Header *header; - void *data; + char *data; }; union { @@ -45,19 +49,19 @@ struct _Shared_Index { 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; - // 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_Buffer strings_entries; + Shared_Index strings_index; Shared_Index files; Shared_Index images; Shared_Index fonts; // TODO