event: cache events
This speeds up Calendar a little bit, and more importantly, allows me to sleep well at night now.
This commit is contained in:
+57
-1
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#define G_LOG_DOMAIN "GcalEvent"
|
#define G_LOG_DOMAIN "GcalEvent"
|
||||||
|
|
||||||
|
#include "gconstructor.h"
|
||||||
#include "gcal-event.h"
|
#include "gcal-event.h"
|
||||||
#include "gcal-utils.h"
|
#include "gcal-utils.h"
|
||||||
#include "gcal-recurrence.h"
|
#include "gcal-recurrence.h"
|
||||||
@@ -134,6 +135,33 @@ enum {
|
|||||||
N_PROPS
|
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*
|
static GTimeZone*
|
||||||
get_timezone_from_ical (ECalComponentDateTime *comp)
|
get_timezone_from_ical (ECalComponentDateTime *comp)
|
||||||
{
|
{
|
||||||
@@ -428,6 +456,10 @@ gcal_event_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
GcalEvent *self = (GcalEvent *)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_start, g_date_time_unref);
|
||||||
g_clear_pointer (&self->dt_end, g_date_time_unref);
|
g_clear_pointer (&self->dt_end, g_date_time_unref);
|
||||||
g_clear_pointer (&self->timezone, g_time_zone_unref);
|
g_clear_pointer (&self->timezone, g_time_zone_unref);
|
||||||
@@ -791,12 +823,36 @@ gcal_event_new (ESource *source,
|
|||||||
ECalComponent *component,
|
ECalComponent *component,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
return g_initable_new (GCAL_TYPE_EVENT,
|
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,
|
NULL,
|
||||||
error,
|
error,
|
||||||
"source", source,
|
"source", source,
|
||||||
"component", component,
|
"component", component,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
{
|
||||||
|
g_debug ("Adding %s to the cache", event->uid);
|
||||||
|
g_hash_table_insert (event_cache, event->uid, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ void gcal_event_set_recurrence (GcalEvent
|
|||||||
|
|
||||||
GcalRecurrence* gcal_event_get_recurrence (GcalEvent *self);
|
GcalRecurrence* gcal_event_get_recurrence (GcalEvent *self);
|
||||||
|
|
||||||
|
void gcal_event_remove_from_cache (GcalEvent *self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|||||||
+6
-9
@@ -483,6 +483,7 @@ on_event_created (GObject *source_object,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
g_object_ref (data->event);
|
||||||
gcal_manager_set_default_source (data->manager, gcal_event_get_source (data->event));
|
gcal_manager_set_default_source (data->manager, gcal_event_get_source (data->event));
|
||||||
g_debug ("Event: %s created successfully", new_uid);
|
g_debug ("Event: %s created successfully", new_uid);
|
||||||
}
|
}
|
||||||
@@ -540,11 +541,13 @@ on_event_removed (GObject *source_object,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
ECalClient *client;
|
ECalClient *client;
|
||||||
|
GcalEvent *event;
|
||||||
GError *error;
|
GError *error;
|
||||||
|
|
||||||
GCAL_ENTRY;
|
GCAL_ENTRY;
|
||||||
|
|
||||||
client = E_CAL_CLIENT (source_object);
|
client = E_CAL_CLIENT (source_object);
|
||||||
|
event = user_data;
|
||||||
error = NULL;
|
error = NULL;
|
||||||
|
|
||||||
e_cal_client_remove_object_finish (client, result, &error);
|
e_cal_client_remove_object_finish (client, result, &error);
|
||||||
@@ -554,9 +557,10 @@ on_event_removed (GObject *source_object,
|
|||||||
/* FIXME: Notify the user somehow */
|
/* FIXME: Notify the user somehow */
|
||||||
g_warning ("Error removing event: %s", error->message);
|
g_warning ("Error removing event: %s", error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
GCAL_RETURN ();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (user_data);
|
g_object_unref (event);
|
||||||
|
|
||||||
GCAL_EXIT;
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
@@ -1828,20 +1832,13 @@ gcal_manager_remove_event (GcalManager *manager,
|
|||||||
if (gcal_event_has_recurrence (event))
|
if (gcal_event_has_recurrence (event))
|
||||||
rid = e_cal_component_get_recurid_as_string (component);
|
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,
|
e_cal_client_remove_object (unit->client,
|
||||||
uid,
|
uid,
|
||||||
mod == GCAL_RECURRENCE_MOD_ALL ? NULL : rid,
|
mod == GCAL_RECURRENCE_MOD_ALL ? NULL : rid,
|
||||||
(ECalObjModType) mod,
|
(ECalObjModType) mod,
|
||||||
manager->async_ops,
|
manager->async_ops,
|
||||||
on_event_removed,
|
on_event_removed,
|
||||||
component);
|
event);
|
||||||
|
|
||||||
g_free (rid);
|
g_free (rid);
|
||||||
|
|
||||||
|
|||||||
@@ -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__ */
|
||||||
Reference in New Issue
Block a user