ethumb: cache exists result.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 28 Apr 2011 17:00:13 +0000 (17:00 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 28 Apr 2011 17:00:13 +0000 (17:00 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ethumb@59017 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/Ethumb.c
src/lib/Ethumb.h
src/lib/client/Ethumb_Client.c

index 953215a..ba445b7 100644 (file)
@@ -1563,7 +1563,7 @@ ethumb_exists(Ethumb *e)
    return r;
 }
 
-Evas *
+EAPI Evas *
 ethumb_evas_get(const Ethumb *e)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
@@ -1571,7 +1571,7 @@ ethumb_evas_get(const Ethumb *e)
    return e->sub_e;
 }
 
-Ecore_Evas *
+EAPI Ecore_Evas *
 ethumb_ecore_evas_get(const Ethumb *e)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
@@ -1579,7 +1579,7 @@ ethumb_ecore_evas_get(const Ethumb *e)
    return e->sub_ee;
 }
 
-Ethumb *
+EAPI Ethumb *
 ethumb_dup(const Ethumb *e)
 {
    Ecore_Evas *ee;
@@ -1659,7 +1659,7 @@ ethumb_dup(const Ethumb *e)
   if (e1->Param != e2->Param)                   \
     return EINA_TRUE;
 
-Eina_Bool
+EAPI Eina_Bool
 ethumb_cmp(const Ethumb *e1, const Ethumb *e2)
 {
    CHECK_DELTA(thumb_dir);
@@ -1684,3 +1684,89 @@ ethumb_cmp(const Ethumb *e1, const Ethumb *e2)
 
    return EINA_FALSE;
 }
+
+EAPI unsigned int
+ethumb_length(__UNUSED__ const void *key)
+{
+   return sizeof (Ethumb);
+}
+
+#define CMP_PARAM(Param)                       \
+  if (e1->Param != e2->Param)                  \
+    return e1->Param - e2->Param;
+
+EAPI int
+ethumb_key_cmp(const void *key1, __UNUSED__ int key1_length,
+               const void *key2, __UNUSED__ int key2_length)
+{
+   const Ethumb *e1 = key1;
+   const Ethumb *e2 = key2;
+
+   CMP_PARAM(thumb_dir);
+   CMP_PARAM(category);
+   CMP_PARAM(thumb_dir);
+   CMP_PARAM(category);
+   CMP_PARAM(tw);
+   CMP_PARAM(th);
+   CMP_PARAM(format);
+   CMP_PARAM(aspect);
+   CMP_PARAM(orientation);
+   CMP_PARAM(crop_x);
+   CMP_PARAM(crop_y);
+   CMP_PARAM(quality);
+   CMP_PARAM(compress);
+   CMP_PARAM(rw);
+   CMP_PARAM(rh);
+   CMP_PARAM(video.start);
+   CMP_PARAM(video.time);
+   CMP_PARAM(video.interval);
+   CMP_PARAM(video.ntimes);
+   CMP_PARAM(video.fps);
+   CMP_PARAM(document.page);
+   CMP_PARAM(src_path);
+   CMP_PARAM(src_key);
+
+   return 0;
+}
+
+#undef CMP_PARAM
+
+#define HASH_PARAM_I(Param) r ^= eina_hash_int32((unsigned int*) &e->Param, 0);
+#ifdef __LP64__
+# define HASH_PARAM_P(Param) r ^= eina_hash_int64((unsigned long int*) &e->Param, 0);
+#else
+# define HASH_PARAM_P(Param) r ^= eina_hash_int32((unsigned int*) &e->Param, 0);
+#endif
+#define HASH_PARAM_D(Param) r ^= eina_hash_int64((unsigned long int*)&e->Param, 0);
+#define HASH_PARAM_F(Param) r ^= eina_hash_int32((unsigned int*) &e->Param, 0);
+
+EAPI int
+ethumb_hash(const void *key, int key_length)
+{
+   const Ethumb *e = key;
+   int r = 0;
+
+   HASH_PARAM_P(thumb_dir);
+   HASH_PARAM_P(category);
+   HASH_PARAM_I(tw);
+   HASH_PARAM_I(th);
+   HASH_PARAM_I(format);
+   HASH_PARAM_I(aspect);
+   HASH_PARAM_I(orientation);
+   HASH_PARAM_F(crop_x);
+   HASH_PARAM_F(crop_y);
+   HASH_PARAM_I(quality);
+   HASH_PARAM_I(compress);
+   HASH_PARAM_P(src_path);
+   HASH_PARAM_P(src_key);
+   HASH_PARAM_I(rw);
+   HASH_PARAM_I(rh);
+   HASH_PARAM_D(video.start);
+   HASH_PARAM_D(video.time);
+   HASH_PARAM_D(video.interval);
+   HASH_PARAM_I(video.ntimes);
+   HASH_PARAM_I(video.fps);
+   HASH_PARAM_I(document.page);
+
+   return r;
+}
index afa0220..dc7b133 100644 (file)
@@ -186,6 +186,10 @@ EAPI Eina_Bool ethumb_exists(Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL
 
 EAPI Ethumb *ethumb_dup(const Ethumb *e) EINA_ARG_NONNULL(1);
 EAPI Eina_Bool ethumb_cmp(const Ethumb *e1, const Ethumb *e2) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT EINA_PURE;
+EAPI int ethumb_hash(const void *key, int key_length) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
+EAPI int ethumb_key_cmp(const void *key1, int key1_length,
+                       const void *key2, int key2_length) EINA_ARG_NONNULL(1, 3) EINA_WARN_UNUSED_RESULT EINA_PURE;
+EAPI unsigned int ethumb_length(const void *key) EINA_PURE EINA_WARN_UNUSED_RESULT;
 
   /**
  * @}
index 3e05fac..8572775 100644 (file)
@@ -169,14 +169,14 @@ struct _ethumb_pending_gen
 };
 
 typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists;
+typedef struct _Ethumb_Async_Exists_Cb Ethumb_Async_Exists_Cb;
 
 struct _Ethumb_Async_Exists
 {
    Ethumb *dup;
    Ethumb_Client *source;
 
-   Ethumb_Client_Thumb_Exists_Cb exists_cb;
-   const void *data;
+   Eina_List *callbacks;
 
    Ecore_Thread *thread;
    int refcount;
@@ -184,6 +184,12 @@ struct _Ethumb_Async_Exists
    Eina_Bool exists : 1;
 };
 
+struct _Ethumb_Async_Exists_Cb
+{
+   Ethumb_Client_Thumb_Exists_Cb exists_cb;
+   const void *data;
+};
+
 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
@@ -193,6 +199,7 @@ static const char fdo_bus_name[] = "org.freedesktop.DBus";
 static const char fdo_path[] = "/org/freedesktop/DBus";
 
 static int _initcount = 0;
+static Eina_Hash *_exists_request = NULL;
 
 static void _ethumb_client_generated_cb(void *data, DBusMessage *msg);
 static void _ethumb_client_get_name_owner(void *data, DBusMessage *msg, DBusError *err);
@@ -252,6 +259,20 @@ __dbus_iter_type_check(int type, int expected, const char *expected_name)
   while (0)
 
 static void
+_ethumb_async_delete(void *data)
+{
+   Ethumb_Async_Exists *async = data;
+
+   ethumb_free(async->dup);
+   async->source->refcount--;
+
+   if (async->source->delete_me == EINA_TRUE)
+     ethumb_client_disconnect(async->source);
+
+   free(async);
+}
+
+static void
 _ethumb_client_name_owner_changed(void *data, DBusMessage *msg)
 {
    DBusError err;
@@ -495,40 +516,38 @@ static void
 _ethumb_client_exists_end(void *data, Ecore_Thread *thread)
 {
    Ethumb_Async_Exists *async = data;
+   Ethumb_Async_Exists_Cb *cb;
    Ethumb *tmp = async->source->ethumb;
 
    async->source->ethumb = async->dup;
    async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup);
-   async->exists_cb(async->source, (Ethumb_Exists*) async, async->exists, (void*) async->data);
-   async->source->ethumb = tmp;
 
-   ethumb_free(async->dup);
-   async->source->refcount--;
+   EINA_LIST_FREE(async->callbacks, cb)
+     cb->exists_cb(async->source, (Ethumb_Exists*) async, async->exists, (void*) cb->data);
 
-   if (async->source->delete_me == EINA_TRUE)
-     ethumb_client_disconnect(async->source);
+   async->source->ethumb = tmp;
+   async->thread = NULL;
 
-   free(async);
+   eina_hash_del(_exists_request, async->dup, async);
 }
 
 static void
 _ethumb_client_exists_cancel(void *data, Ecore_Thread *thread)
 {
+   Ethumb_Async_Exists_Cb *cb;
    Ethumb_Async_Exists *async = data;
    Ethumb *tmp = async->source->ethumb;
 
    async->source->ethumb = async->dup;
    async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup);
-   async->exists_cb(async->source, (Ethumb_Exists*) async, EINA_FALSE, (void*) async->data);
-   async->source->ethumb = tmp;
 
-   ethumb_free(async->dup);
-   async->source->refcount--;
+   EINA_LIST_FREE(async->callbacks, cb)
+     cb->exists_cb(async->source, (Ethumb_Exists*) async, EINA_FALSE, (void*) cb->data);
 
-   if (async->source->delete_me == EINA_TRUE)
-     ethumb_client_disconnect(async->source);
+   async->source->ethumb = tmp;
+   async->thread = NULL;
 
-   free(async);
+   eina_hash_del(_exists_request, async->dup, async);
 }
 
 /**
@@ -574,6 +593,12 @@ ethumb_client_init(void)
    ethumb_init();
    e_dbus_init();
 
+   _exists_request = eina_hash_new(ethumb_length,
+                                   ethumb_key_cmp,
+                                   ethumb_hash,
+                                   _ethumb_async_delete,
+                                   3);
+
    return ++_initcount;
 }
 
@@ -600,6 +625,8 @@ ethumb_client_shutdown(void)
    if (_initcount > 0)
      return _initcount;
 
+   /* should find a non racy solution to closing all pending exists request */
+
    e_dbus_shutdown();
    ethumb_shutdown();
    eina_log_domain_unregister(_log_dom);
@@ -2122,13 +2149,33 @@ ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const cha
 EAPI Ethumb_Exists *
 ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)
 {
+   Ethumb_Async_Exists_Cb *cb;
    Ethumb_Async_Exists *async;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
 
+   cb = malloc(sizeof (Ethumb_Async_Exists_Cb));
+   if (!cb)
+     {
+        exists_cb(client, NULL, EINA_FALSE, (void*) data);
+        return NULL;
+     }
+
+   cb->exists_cb = exists_cb;
+   cb->data = data;
+
+   async = eina_hash_find(_exists_request, client->ethumb);
+   if (async)
+     {
+        async->refcount++;
+        async->callbacks = eina_list_append(async->callbacks, cb);
+        return (Ethumb_Exists*) async;
+     }
+
    async = malloc(sizeof (Ethumb_Async_Exists));
    if (!async)
      {
+        free(cb);
         exists_cb(client, NULL, EINA_FALSE, (void*) data);
         return NULL;
      }
@@ -2136,16 +2183,18 @@ ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb
    async->dup = ethumb_dup(client->ethumb);
    async->source = client;
    async->source->refcount++;
-   async->exists_cb = exists_cb;
-   async->data = data;
    async->exists = EINA_FALSE;
 
+   async->callbacks = eina_list_append(NULL, cb);
+
    async->refcount = 1;
    async->thread = ecore_thread_run(_ethumb_client_exists_heavy,
                                    _ethumb_client_exists_end,
                                    _ethumb_client_exists_cancel,
                                    async);
 
+   eina_hash_direct_add(_exists_request, async->dup, async);
+
    return (Ethumb_Exists*) async;
 }