From 13bf124bfc41360a65ca08fca066077d272bf247 Mon Sep 17 00:00:00 2001 From: Dave Peticolas Date: Mon, 6 Nov 2000 22:42:35 +0000 Subject: [PATCH] Tyson Dowd's patch to use GCaches for string caching in the engine. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3121 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/engine/Transaction.c | 67 +++++++++++++++++++++++----------------- src/engine/gnc-engine.c | 7 ++++- src/engine/gnc-engine.h | 19 ++++++++++++ src/engine/kvp_frame.c | 16 +++++++--- 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 640824bf0f..1b9cc0b2a1 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -42,6 +42,7 @@ #include "date.h" #include "gnc-commodity.h" #include "gnc-engine-util.h" +#include "gnc-engine.h" /* * The "force_double_entry" flag determines how @@ -91,8 +92,8 @@ xaccInitSplit(Split * split) split->acc = NULL; split->parent = NULL; - split->action = g_strdup(""); - split->memo = g_strdup(""); + split->action = g_cache_insert(gnc_string_cache, ""); + split->memo = g_cache_insert(gnc_string_cache, ""); split->reconciled = NREC; split->damount = gnc_numeric_zero(); split->value = gnc_numeric_zero(); @@ -140,8 +141,8 @@ xaccCloneSplit (Split *s) split->acc = s->acc; split->parent = s->parent; - split->action = g_strdup(s->action); - split->memo = g_strdup(s->memo); + split->action = g_cache_insert(gnc_string_cache, s->action); + split->memo = g_cache_insert(gnc_string_cache, s->memo); split->reconciled = s->reconciled; split->damount = s->damount; split->value = s->value; @@ -173,8 +174,8 @@ xaccFreeSplit( Split *split ) { if (!split) return; - g_free (split->memo); - g_free (split->action); + g_cache_remove(gnc_string_cache, split->memo); + g_cache_remove(gnc_string_cache, split->action); /* just in case someone looks up freed memory ... */ split->memo = NULL; @@ -207,8 +208,9 @@ xaccSplitEqual(const Split *sa, const Split *sb, if(!guid_equal(&(sa->guid), &(sb->guid))) return FALSE; } - if(safe_strcmp(sa->memo, sb->memo) != 0) return FALSE; - if(safe_strcmp(sa->action, sb->action) != 0) return FALSE; + /* Since these strings are cached we can just use pointer equality */ + if(sa->memo != sb->memo) return FALSE; + if(sa->action != sb->action) return FALSE; if(kvp_frame_compare(sa->kvp_data, sb->kvp_data) != 0) return FALSE; @@ -557,8 +559,8 @@ static void xaccInitTransaction (Transaction * trans) { /* Fill in some sane defaults */ - trans->num = g_strdup(""); - trans->description = g_strdup(""); + trans->num = g_cache_insert(gnc_string_cache, ""); + trans->description = g_cache_insert(gnc_string_cache, ""); trans->splits = NULL; @@ -605,8 +607,8 @@ xaccCloneTransaction (Transaction *t) trans = g_new(Transaction, 1); - trans->num = g_strdup(t->num); - trans->description = g_strdup(t->description); + trans->num = g_cache_insert(gnc_string_cache, t->num); + trans->description = g_cache_insert(gnc_string_cache, t->description); trans->splits = g_list_copy (t->splits); for (node = trans->splits; node; node = node->next) @@ -648,8 +650,8 @@ xaccFreeTransaction (Transaction *trans) trans->splits = NULL; /* free up transaction strings */ - g_free (trans->num); - g_free (trans->description); + g_cache_remove(gnc_string_cache, trans->num); + g_cache_remove(gnc_string_cache, trans->description); /* just in case someone looks up freed memory ... */ trans->num = NULL; @@ -698,8 +700,11 @@ xaccTransEqual(const Transaction *ta, const Transaction *tb, if(!timespec_equal(&(ta->date_entered), &(tb->date_entered))) return FALSE; if(!timespec_equal(&(ta->date_posted), &(tb->date_posted))) return FALSE; - if(safe_strcmp(ta->num, tb->num) != 0) return FALSE; - if(safe_strcmp(ta->description, tb->description) != 0) return FALSE; + /* Since we use cached strings, we can just compare pointer + * equality for num and description + */ + if(ta->num != tb->num) return FALSE; + if(ta->description != tb->description) return FALSE; if(kvp_frame_compare(ta->kvp_data, tb->kvp_data) != 0) return FALSE; @@ -1219,14 +1224,14 @@ xaccSplitRebalance (Split *split) xaccTransAppendSplit (trans, s); xaccAccountInsertSplit (split->acc, s); - g_free (s->memo); - g_free (s->action); + g_cache_remove(gnc_string_cache, s->memo); + g_cache_remove(gnc_string_cache, s->action); xaccSplitSetValue(s, gnc_numeric_neg(split->value)); xaccSplitSetShareAmount(s, gnc_numeric_neg(split->value)); - s->memo = g_strdup (split->memo); - s->action = g_strdup (split->action); + s->memo = g_cache_insert(gnc_string_cache, split->memo); + s->action = g_cache_insert(gnc_string_cache, split->action); } } } @@ -1425,9 +1430,11 @@ xaccTransRollbackEdit (Transaction *trans) #define PUT_BACK(val) { g_free(trans->val); \ trans->val=orig->val; orig->val=NULL; } +#define PUT_BACK_CACHE(val) { g_cache_remove(gnc_string_cache, trans->val); \ + trans->val=orig->val; orig->val=NULL; } PUT_BACK (num); - PUT_BACK (description); + PUT_BACK_CACHE (description); trans->date_entered.tv_sec = orig->date_entered.tv_sec; trans->date_entered.tv_nsec = orig->date_entered.tv_nsec; @@ -1903,8 +1910,8 @@ xaccTransSetNum (Transaction *trans, const char *xnum) if (!trans || !xnum) return; CHECK_OPEN (trans); - tmp = g_strdup (xnum); - g_free (trans->num); + tmp = g_cache_insert(gnc_string_cache, (gpointer) xnum); + g_cache_remove(gnc_string_cache, trans->num); trans->num = tmp; MarkChanged (trans); } @@ -1916,8 +1923,8 @@ xaccTransSetDescription (Transaction *trans, const char *desc) if (!trans || !desc) return; CHECK_OPEN (trans); - tmp = g_strdup (desc); - g_free (trans->description); + tmp = g_cache_insert(gnc_string_cache, (gpointer) desc); + g_cache_remove(gnc_string_cache, trans->description); trans->description = tmp; MarkChanged (trans); } @@ -1991,8 +1998,9 @@ xaccSplitSetMemo (Split *split, const char *memo) { char * tmp; if (!split || !memo) return; - tmp = g_strdup (memo); - g_free (split->memo); + + tmp = g_cache_insert(gnc_string_cache, (gpointer) memo); + g_cache_remove(gnc_string_cache, split->memo); split->memo = tmp; MARK_SPLIT (split); } @@ -2002,8 +2010,9 @@ xaccSplitSetAction (Split *split, const char *actn) { char * tmp; if (!split || !actn) return; - tmp = g_strdup (actn); - g_free (split->action); + + tmp = g_cache_insert(gnc_string_cache, (gpointer) actn); + g_cache_remove(gnc_string_cache, split->action); split->action = tmp; MARK_SPLIT (split); } diff --git a/src/engine/gnc-engine.c b/src/engine/gnc-engine.c index 58039d01fa..16561f1711 100644 --- a/src/engine/gnc-engine.c +++ b/src/engine/gnc-engine.c @@ -29,7 +29,7 @@ static GList * engine_init_hooks = NULL; static gnc_commodity_table * known_commodities = NULL; static int engine_is_initialized = 0; - +GCache * gnc_string_cache = NULL; /******************************************************************** * gnc_engine_init @@ -43,6 +43,11 @@ gnc_engine_init(int argc, char ** argv) { engine_is_initialized = 1; + /* initialize the string cache */ + gnc_string_cache = g_cache_new( (GCacheNewFunc) g_strdup, + g_free, (GCacheDupFunc) g_strdup, g_free, g_str_hash, + g_str_hash, g_str_equal); + /* initialize the commodity table (it starts empty) */ known_commodities = gnc_commodity_table_new(); diff --git a/src/engine/gnc-engine.h b/src/engine/gnc-engine.h index bfdca3d3fe..d65e0cc606 100644 --- a/src/engine/gnc-engine.h +++ b/src/engine/gnc-engine.h @@ -41,5 +41,24 @@ void gnc_engine_add_init_hook(gnc_engine_init_hook_t hook); /* this is a global table of known commodity types. */ gnc_commodity_table * gnc_engine_commodities(void); +/* Many strings used throughout the engine are likely to be duplicated. + * So we provide a reference counted cache system for the strings, which + * shares strings whenever possible. + * + * Use g_cache_insert to insert a string into the cache (it will return a + * pointer to the cached string). + * Basically you should use this instead of g_strdup. + * + * Use g_cache_remove (giving it a pointer to a cached string) if the string + * is unused. If this is the last reference to the string it will be + * removed from the cache, otherwise it will just decrement the + * reference count. + * Basically you should use this instead of g_free. + * + * Note that all the work is done when inserting or removing. Once + * cached the strings are just plain C strings. + */ +extern GCache *gnc_string_cache; + #endif diff --git a/src/engine/kvp_frame.c b/src/engine/kvp_frame.c index c25c42d4e5..88961c46d6 100644 --- a/src/engine/kvp_frame.c +++ b/src/engine/kvp_frame.c @@ -23,11 +23,15 @@ #include "kvp_frame.h" #include "guid.h" +#include "gnc-engine.h" #include #include #include + /* Note that we keep the keys for this hash table in a GCache + * (gnc_string_cache), as it is likely we will see the same keys + * over and over again */ struct _kvp_frame { GHashTable * hash; }; @@ -84,7 +88,7 @@ kvp_frame_new(void) { static void kvp_frame_delete_worker(gpointer key, gpointer value, gpointer user_data) { - g_free(key); + g_cache_remove(gnc_string_cache, key); kvp_value_delete((kvp_value *)value); } @@ -107,7 +111,7 @@ kvp_frame_copy_worker(gpointer key, gpointer value, gpointer user_data) { kvp_frame * dest = (kvp_frame *)user_data; g_hash_table_freeze(dest->hash); g_hash_table_insert(dest->hash, - (gpointer)g_strdup(key), + (gpointer)g_cache_insert(gnc_string_cache, key), (gpointer)kvp_value_copy(value)); g_hash_table_thaw(dest->hash); } @@ -142,11 +146,15 @@ kvp_frame_set_slot_destructively(kvp_frame * frame, const char * slot, & orig_key, & orig_value); if(key_exists) { g_hash_table_remove(frame->hash, slot); - g_free(orig_key); + g_cache_remove(gnc_string_cache, orig_key); kvp_value_delete(orig_value); } - if(new_value) g_hash_table_insert(frame->hash, g_strdup(slot), new_value); + if(new_value) { + g_hash_table_insert(frame->hash, + g_cache_insert(gnc_string_cache, (gpointer) slot), + new_value); + } g_hash_table_thaw(frame->hash); }