[gnome-calendar] event: cache events



commit 941f3ee77d48f23fb2e63bb5c64e9e07c1b59fd5
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Thu Sep 7 02:09:09 2017 -0300

    event: cache events
    
    This speeds up Calendar a little bit, and more importantly,
    allows me to sleep well at night now.

 src/gcal-event.c   |   68 +++++++++++++++++++++++++++---
 src/gcal-event.h   |    1 +
 src/gcal-manager.c |   15 +++----
 src/gconstructor.h |  120 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 189 insertions(+), 15 deletions(-)
---
diff --git a/src/gcal-event.c b/src/gcal-event.c
index 41f8475..38cd464 100644
--- a/src/gcal-event.c
+++ b/src/gcal-event.c
@@ -18,6 +18,7 @@
 
 #define G_LOG_DOMAIN "GcalEvent"
 
+#include "gconstructor.h"
 #include "gcal-event.h"
 #include "gcal-utils.h"
 #include "gcal-recurrence.h"
@@ -134,6 +135,33 @@ enum {
   N_PROPS
 };
 
+
+/*
+ * GcalEvent cache
+ */
+
+static GHashTable *event_cache = NULL;
+
+G_DEFINE_CONSTRUCTOR (init_event_cache_map);
+
+static void
+init_event_cache_map (void)
+{
+  event_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+}
+
+G_DEFINE_DESTRUCTOR (destroy_event_cache_map);
+
+static void
+destroy_event_cache_map (void)
+{
+  g_hash_table_destroy (event_cache);
+}
+
+/*
+ * Auxiliary methods
+ */
+
 static GTimeZone*
 get_timezone_from_ical (ECalComponentDateTime *comp)
 {
@@ -428,6 +456,10 @@ gcal_event_finalize (GObject *object)
 {
   GcalEvent *self = (GcalEvent *)object;
 
+  g_debug ("Removing '%s' (%p) from cache", self->uid, self);
+
+  g_hash_table_remove (event_cache, self->uid);
+
   g_clear_pointer (&self->dt_start, g_date_time_unref);
   g_clear_pointer (&self->dt_end, g_date_time_unref);
   g_clear_pointer (&self->timezone, g_time_zone_unref);
@@ -791,12 +823,36 @@ gcal_event_new (ESource        *source,
                 ECalComponent  *component,
                 GError        **error)
 {
-  return g_initable_new (GCAL_TYPE_EVENT,
-                         NULL,
-                         error,
-                         "source", source,
-                         "component", component,
-                         NULL);
+  GcalEvent *event;
+  g_autofree gchar *uuid;
+
+  uuid = get_uuid_from_component (source, component);
+
+  if (g_hash_table_contains (event_cache, uuid))
+    {
+      g_debug ("Using cached value for %s", uuid);
+
+      event = g_hash_table_lookup (event_cache, uuid);
+      gcal_event_set_component_internal (event, component);
+      g_object_ref (event);
+    }
+  else
+    {
+      event = g_initable_new (GCAL_TYPE_EVENT,
+                              NULL,
+                              error,
+                              "source", source,
+                              "component", component,
+                              NULL);
+
+      if (event)
+        {
+          g_debug ("Adding %s to the cache", event->uid);
+          g_hash_table_insert (event_cache, event->uid, event);
+        }
+    }
+
+  return event;
 }
 
 /**
diff --git a/src/gcal-event.h b/src/gcal-event.h
index 6a1b805..1621bfc 100644
--- a/src/gcal-event.h
+++ b/src/gcal-event.h
@@ -129,6 +129,7 @@ void                 gcal_event_set_recurrence                   (GcalEvent
 
 GcalRecurrence*      gcal_event_get_recurrence                   (GcalEvent          *self);
 
+void                 gcal_event_remove_from_cache                (GcalEvent          *self);
 
 G_END_DECLS
 
diff --git a/src/gcal-manager.c b/src/gcal-manager.c
index ac62d76..e1d727c 100644
--- a/src/gcal-manager.c
+++ b/src/gcal-manager.c
@@ -483,6 +483,7 @@ on_event_created (GObject      *source_object,
     }
   else
     {
+      g_object_ref (data->event);
       gcal_manager_set_default_source (data->manager, gcal_event_get_source (data->event));
       g_debug ("Event: %s created successfully", new_uid);
     }
@@ -540,11 +541,13 @@ on_event_removed (GObject      *source_object,
                   gpointer      user_data)
 {
   ECalClient *client;
+  GcalEvent *event;
   GError *error;
 
   GCAL_ENTRY;
 
   client = E_CAL_CLIENT (source_object);
+  event = user_data;
   error = NULL;
 
   e_cal_client_remove_object_finish (client, result, &error);
@@ -554,9 +557,10 @@ on_event_removed (GObject      *source_object,
       /* FIXME: Notify the user somehow */
       g_warning ("Error removing event: %s", error->message);
       g_error_free (error);
+      GCAL_RETURN ();
     }
 
-  g_object_unref (user_data);
+  g_object_unref (event);
 
   GCAL_EXIT;
 }
@@ -1828,20 +1832,13 @@ gcal_manager_remove_event (GcalManager           *manager,
   if (gcal_event_has_recurrence (event))
     rid = e_cal_component_get_recurid_as_string (component);
 
-  /*
-   * While we're removing the event, we don't want the component
-   * to be destroyed, so take a reference of the component while
-   * we're deleting it.
-   */
-  g_object_ref (component);
-
   e_cal_client_remove_object (unit->client,
                               uid,
                               mod == GCAL_RECURRENCE_MOD_ALL ? NULL : rid,
                               (ECalObjModType) mod,
                               manager->async_ops,
                               on_event_removed,
-                              component);
+                              event);
 
   g_free (rid);
 
diff --git a/src/gconstructor.h b/src/gconstructor.h
new file mode 100644
index 0000000..dccb031
--- /dev/null
+++ b/src/gconstructor.h
@@ -0,0 +1,120 @@
+/*
+  If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and
+  destructors, in a sane way, including e.g. on library unload. If not you're on
+  your own.
+
+  Some compilers need #pragma to handle this, which does not work with macros,
+  so the way you need to use this is (for constructors):
+
+  #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
+  #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor)
+  #endif
+  G_DEFINE_CONSTRUCTOR(my_constructor)
+  static void my_constructor(void) {
+   ...
+  }
+
+*/
+
+#ifndef __GTK_DOC_IGNORE__
+
+#if  __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
+#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void);
+
+#elif defined (_MSC_VER) && (_MSC_VER >= 1500)
+/* Visual studio 2008 and later has _Pragma */
+
+#define G_HAS_CONSTRUCTORS 1
+
+/* We do some weird things to avoid the constructors being optimized
+ * away on VS2015 if WholeProgramOptimization is enabled. First we
+ * make a reference to the array from the wrapper to make sure its
+ * references. Then we use a pragma to make sure the wrapper function
+ * symbol is always included at the link stage. Also, the symbols
+ * need to be extern (but not dllexport), even though they are not
+ * really used from another object file.
+ */
+
+/* We need to account for differences between the mangling of symbols
+ * for Win32 (x86) and x64 programs, as symbols on Win32 are prefixed
+ * with an underscore but symbols on x64 are not.
+ */
+#ifdef _WIN64
+#define G_MSVC_SYMBOL_PREFIX ""
+#else
+#define G_MSVC_SYMBOL_PREFIX "_"
+#endif
+
+#define G_DEFINE_CONSTRUCTOR(_func) G_MSVC_CTOR (_func, G_MSVC_SYMBOL_PREFIX)
+#define G_DEFINE_DESTRUCTOR(_func) G_MSVC_DTOR (_func, G_MSVC_SYMBOL_PREFIX)
+
+#define G_MSVC_CTOR(_func,_sym_prefix) \
+  static void _func(void); \
+  extern int (* _array ## _func)(void);              \
+  int _func ## _wrapper(void) { _func(); g_slist_find (NULL,  _array ## _func); return 0; } \
+  __pragma(comment(linker,"/include:" _sym_prefix # _func "_wrapper")) \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _wrapper;
+
+#define G_MSVC_DTOR(_func,_sym_prefix) \
+  static void _func(void); \
+  extern int (* _array ## _func)(void);              \
+  int _func ## _constructor(void) { atexit (_func); g_slist_find (NULL,  _array ## _func); return 0; } \
+   __pragma(comment(linker,"/include:" _sym_prefix # _func "_constructor")) \
+  __pragma(section(".CRT$XCU",read)) \
+  __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined (_MSC_VER)
+
+#define G_HAS_CONSTRUCTORS 1
+
+/* Pre Visual studio 2008 must use #pragma section */
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _wrapper(void) { _func(); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper;
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  section(".CRT$XCU",read)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void); \
+  static int _func ## _constructor(void) { atexit (_func); return 0; } \
+  __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor;
+
+#elif defined(__SUNPRO_C)
+
+/* This is not tested, but i believe it should work, based on:
+ * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c
+ */
+
+#define G_HAS_CONSTRUCTORS 1
+
+#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1
+#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1
+
+#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \
+  init(_func)
+#define G_DEFINE_CONSTRUCTOR(_func) \
+  static void _func(void);
+
+#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \
+  fini(_func)
+#define G_DEFINE_DESTRUCTOR(_func) \
+  static void _func(void);
+
+#else
+
+/* constructors not supported for this compiler */
+
+#endif
+
+#endif /* __GTK_DOC_IGNORE__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]