evas/cserve2: Scan shared indexes in client side
authorJean-Philippe Andre <jp.andre@samsung.com>
Wed, 31 Jul 2013 11:29:41 +0000 (20:29 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Mon, 28 Oct 2013 06:47:13 +0000 (15:47 +0900)
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.

src/lib/evas/cache2/evas_cache2.c
src/lib/evas/cache2/evas_cache2.h
src/lib/evas/cserve2/evas_cs2.h
src/lib/evas/cserve2/evas_cs2_client.c
src/lib/evas/cserve2/evas_cs2_private.h

index 81fd78c..77585ab 100644 (file)
@@ -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);
index f6ba8f8..6f8e588 100644 (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 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);
index 7cb6e08..19bf806 100644 (file)
@@ -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];
index d7cd814..5b8e463 100644 (file)
@@ -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);
+        ERR("New index generation_id is the same as before: %d",
+            _index.generation_id);
      }
-   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)
+
+   _index.generation_id = msg->generation_id;
+
+   // 1. Strings (indexes and entries)
+
+   if (_index.strings_entries.data
+       && strncmp(_index.strings_entries.path, msg->strings_entries_path,
+                  SHARED_BUFFER_PATH_MAX) != 0)
      {
-        if (_index.images.header)
-          eina_file_map_free(_index.images.f, (void *) _index.images.header);
-        eina_file_close(_index.images.f);
+        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.fonts.f)
+
+   if (_index.strings_index.data
+       && strncmp(_index.strings_index.path, msg->strings_index_path,
+                  SHARED_BUFFER_PATH_MAX) != 0)
      {
-        if (_index.fonts.header)
-          eina_file_map_free(_index.fonts.f, (void *) _index.fonts.header);
-        eina_file_close(_index.fonts.f);
+        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;
      }
 
-   // 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);
+   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.index_path[0] && _index.strings.entries_path[0])
+   if (!_index.strings_entries.data
+       && _index.strings_entries.path[0]
+       && _index.strings_index.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
+        _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)
           {
-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 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.files.path[0])
+   if (_index.strings_entries.data &&
+       (!_index.strings_index.data && _index.strings_index.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))
+        _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)
           {
-             ERR("Shared index for files is too small: %u", sz);
-             eina_file_close(_index.files.f);
-             _index.files.f = NULL;
+             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
           {
-             _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++;
-               }
+             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.images.path[0])
+   _shared_index_remap_check(&_index.strings_index, sizeof(Index_Entry));
+   if (_index.strings_entries.data)
      {
-        _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))
+        if (eina_file_refresh(_index.strings_entries.f))
           {
-             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++;
-               }
+             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.fonts.path[0])
-     ERR("Not implemented yet: fonts shared index");
 
-   return ret;
-}
+   // 2. File indexes
 
-// 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;
+   eina_strlcpy(_index.files.path, msg->files_index_path, SHARED_BUFFER_PATH_MAX);
+   _shared_index_remap_check(&_index.files, sizeof(File_Data));
 
-   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;
+   // 3. Image indexes
+
+   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;
-
-   if (id <= 0) return NULL;
-   if (!_index.strings.data) return NULL;
+   Index_Entry *ie;
 
-   // 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)
-{
-   const char *path, *key, *loader;
-
-   if (!fd || !ie) return EINA_FALSE;
-   if (!ie->file && !ie->key)
-     return EINA_FALSE;
+#define SHARED_INDEX_CHECK(si, typ) \
+   do { if (!_shared_index_remap_check(&(si), sizeof(typ))) { \
+   CRIT("Failed to remap index"); return NULL; } } while (0)
 
-   path = _shared_string_get(fd->path);
-   key = _shared_string_get(fd->key);
-   loader = _shared_string_get(fd->loader_data);
+static const char *
+_shared_file_data_hkey_get(char *hkey, const char *file, const char *key,
+                           size_t hkey_size)
+{
+   size_t keylen, filelen;
 
-   if (!path && ie->file)
-     return EINA_FALSE;
-   if (ie->file && strcmp(path, ie->file))
-     return EINA_FALSE;
+   if (key) keylen = strlen(key) + 1;
+   filelen = strlen(file);
 
-   if (!key && ie->key)
-     return EINA_FALSE;
-   if (ie->key && strcmp(key, ie->key))
-     return EINA_FALSE;
+   if (filelen + keylen + 1 > hkey_size)
+     return NULL;
 
-   /*
-   if (!loader && ie->loader_data)
-     return EINA_FALSE;
-   if (strcmp(loader, ie->loader_data))
-     return EINA_FALSE;
-   */
+   memcpy(hkey, file, filelen);
+   hkey[filelen] = ':';
+   if (key)
+     memcpy(hkey + filelen + 1, key, keylen);
+   else
+     memcpy(hkey + filelen + 1, "(null)", 7);
 
-   // 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;
+
+   if (!_index.files.header || !_index.files.entries.fdata)
      return NULL;
 
-#warning FIXME Use safe count
-   for (k = 0; k < _index.files.header->count; k++)
+   // 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;
+     }
+
+   // 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 File_Data *fd = &(_index.files.entries.fdata[k]);
-        if (!fd->id) return NULL;
+        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;
 
-        if (_shared_image_entry_file_data_match(ie, fd))
+        file = _shared_string_get(fd->path);
+        if (!file)
           {
-             fdata = fd;
-             break;
+             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;
      }
 
-   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;
+   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);
 
+   // 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 = 0; k < _index.images.count; k++)
+   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;
 }
 
index 289119f..d1c5366 100644 (file)
@@ -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