From 941f3ee77d48f23fb2e63bb5c64e9e07c1b59fd5 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 7 Sep 2017 02:09:09 -0300 Subject: [PATCH] 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(-) create mode 100644 src/gconstructor.h diff --git a/src/gcal-event.c b/src/gcal-event.c index 41f8475d..38cd4649 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 6a1b8050..1621bfc6 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 ac62d76f..e1d727c6 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 00000000..dccb0314 --- /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__ */