1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
|
/* File: methodcache.c
* Author: Fred Wobus (fw@sanger.ac.uk)
* Copyright (c) J Thierry-Mieg and R Durbin, 1999
* -------------------------------------------------------------------
* Acedb is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* or see the on-line version at http://www.gnu.org/copyleft/gpl.txt
* -------------------------------------------------------------------
* This file is part of the ACEDB genome database package, written by
* Richard Durbin (Sanger Centre, UK) rd@sanger.ac.uk, and
* Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.crbm.cnrs-mop.fr
*
* Description: implementation of MethodCache class
* maintains a list of objects that represent
* object of class Method in memory.
* Exported functions: See methodcache.h
* HISTORY:
* Last edited: Oct 5 16:15 1999 (fw)
* Created: Thu Sep 23 10:40:39 1999 (fw)
* CVS info: $Id$
*-------------------------------------------------------------------
*/
#include "acedb.h"
#include "method.h"
#include "methodcache.h"
#include "whooks/classes.h"
/* complete opaque MethodCacheStuct */
struct MethodCacheStruct {
Array entries;
STORE_HANDLE handle; /* contains all METHOD structs whether
* contained in the cache-array or
* derived from a cached struct */
} ;
static void methodCacheFinalise (void *block);
static BOOL methodCacheExists (MethodCache mcache);
static METHOD *methodCacheInsert (MethodCache mcache,
METHOD *meth, char *aceDiff);
/******************************************************************
************************* public functions ***********************
******************************************************************/
MethodCache methodCacheCreate (STORE_HANDLE handle)
/* Create a new method-cache upon the given handle
* There should be one cache per context, e.g.
* a cache per FMAP instance, so within this context
* we don't duplicate METHOD struct for the same objects
* RETURNS:
* a new cache-struct pointer (alloc'd upon handle) */
{
MethodCache mcache;
mcache = (MethodCache)halloc(sizeof(struct MethodCacheStruct), handle);
blockSetFinalise (mcache, methodCacheFinalise);
/* these will be explicitly destroyed by finalisation */
mcache->entries = arrayCreate (lexMax(_VMethod), METHOD*);
mcache->handle = handleCreate();
return mcache;
} /* methodCacheCreate */
/************************************************************/
void methodCacheDestroy (MethodCache mcache)
/* just to avoid a #define to messfree - must not do anymore
* in this function - all work is done in methodCacheFinalise */
{
messfree (mcache);
} /* methodCacheDestroy */
/************************************************************/
METHOD *methodCacheGet (MethodCache mcache, KEY methodKey,
char *aceDiff)
/* Find the method for the given key in the cache
* or create a new struct from it's object
* in the database and insert it into the cache.
* If a valid string, aceDiff will be applied to derive
* a slight variation to the actual database-OBJ.
* RETURNS:
* the method struct
* This struct will be tied to the cache's memory finalisation
* OR
* NULL if Method of the given is neither in Cache
* nor in database
*/
{
METHOD *meth = NULL;
int index;
if (!methodCacheExists(mcache))
messcrash ("methodCacheGet() - reveived invalid mcache");
if (!methodKey)
return NULL;
if (class(methodKey) != _VMethod)
return NULL;
/* OK, so the KEY seems allright */
index = KEYKEY(lexAliasOf(methodKey));
if (index < arrayMax(mcache->entries))
meth = arr (mcache->entries, index, METHOD*);
if (meth)
/* method already in the cache */
{
if (!methodExists(meth))
messcrash("methodCacheGet() - found invalid METHOD in cache");
if (!meth->isCached)
messcrash("methodCacheGet() - Method:%s at slot %d should "
"have been marked as cached!",
meth->name, index);
}
else
/* wasn't in cache - load from DB
* NOTE: the new struct is alloc'd on the cache's handle */
meth = methodCreateFromObj (methodKey, mcache->handle);
if (meth != NULL)
/* loading from DB may have failed */
meth = methodCacheInsert (mcache, meth, aceDiff);
return meth; /* WARNING - may be NULL */
} /* methodCacheGet */
/************************************************************/
METHOD *methodCacheGetByName (MethodCache mcache, char *methodName,
char *aceText, char *aceDiff)
/* Find a METHOD struct in the cache by its name
* if it isn't found, a new one struct will be created
* by using the aceText to initilise the object,
* and it will be inserted into the cache then.
* If a valid string, aceDiff will be applied to derive
* a slight variation to the actual database-OBJ.
* NOTE: safer way to access the cache - never returns NULL!
* RETURNS:
* struct pointer of METHOD, which is tied into the cache.
* This struct will be tied to the cache's memory finalisation
* That pointer is NEVER NULL!
*/
{
KEY methodKey = 0;
METHOD *meth = NULL;
if (!methodCacheExists(mcache))
messcrash ("methodCacheGetByName() - reveived invalid mcache");
if (lexword2key (methodName, &methodKey, _VMethod))
/* obj exists in DB - se we get it either from cache or load it
* the aceDiff will be applied in the process */
meth = methodCacheGet (mcache,
methodKey, aceDiff);/* may return NULL */
if (meth == NULL)
/* couldn't get it from the cache and it doesn't exist in the DB */
{
/* by allocating it on the cache's handle it'll be tied into the
* cache's memory finalisation, the user must not destroy the
* struct explicitly, it gets killed when the cache goes */
meth = methodCreateFromDef (methodName,
aceText, mcache->handle);
meth = methodCacheInsert (mcache, meth, aceDiff);
}
return meth;
} /* methodCacheGetByName */
/******************************************************************
************************ private functions ***********************
******************************************************************/
static BOOL methodCacheExists (MethodCache mcache)
/* determine whether the MethodCache pointer is valid
* RETURNS
* TRUE if a valid non-NULL pointer
* otherwise FALSE
*/
{
if (mcache && arrayExists(mcache->entries))
/* we could use an extra ->magic in this struct, but
* it's enough for now to verify the Array which uses a magic */
return TRUE;
return FALSE;
} /* methodCacheExists */
/************************************************************/
static void methodCacheFinalise (void *block)
/* clear up memory allocated for the method-cache
* we kill all the method-structs in the cache
* and then kill the cache-array */
{
MethodCache mcache = (MethodCache)block;
if (!methodCacheExists(mcache))
messcrash("methodCacheFinalise() - received invalid pointer");
/* This'll kill all METHOD structs that are in the cache-array
* or were derived from a cached struct */
handleDestroy (mcache->handle);
arrayDestroy (mcache->entries);
return;
} /* methodCacheFinalise */
/************************************************************/
static METHOD *methodCacheInsert (MethodCache mcache,
METHOD *meth, char *aceDiff)
/* Add the given struct into the given method-cache.
* The structs are kept in an array indexed by the
* number of the object in the class Method,
* i.e. KEYKEY(meth->key)
* cached objects are marked and not cached again.
* If aceDiff is a not-empty string, an additional copy is
* of the struct is made. This copy will be tied into the
* cache's memory finalisation, but not added to the cache
* directly as it would end up at the same index as the original
* struct that correspons to the database object.
* RETURNS:
* The cached struct or it's diffed copy.
*/
{
int index;
METHOD *existing_meth = NULL;
METHOD *inserted_meth = NULL;
if (!methodCacheExists(mcache))
messcrash ("methodCacheInsert() - reveived invalid mcache");
if (!methodExists (meth))
messcrash("methodCacheInsert() - received invalid meth");
index = KEYKEY(meth->key);
/* There may already be a method cached at this slot */
if ((existing_meth = array(mcache->entries, index, METHOD*)))
{
if (!methodExists(existing_meth))
messcrash("methodCacheInsert() - found invalid METHOD in cache");
if (!existing_meth->isCached)
messcrash("methodCacheInsert() - Method:%s at slot %d should "
"have been marked as cached!",
existing_meth->name, index);
inserted_meth = existing_meth;
}
else
/* slot not taken yet - add this method to the cache */
{
array (mcache->entries, index, METHOD*) = meth;
meth->isCached = TRUE; /* set flag (just for assertions) */
inserted_meth = meth;
}
if (aceDiff && strlen(aceDiff) > 0)
/* create a copy of the struct by applying the aceDiff-string */
{
METHOD *copy_meth;
copy_meth = methodCopy (meth, aceDiff, mcache->handle);
inserted_meth = copy_meth; /* return copy instead */
/* NOTE, that the new copy will not be inserted into the cache
* as it would be placed at the same index as the original
* struct (which corresponds to the database-obj).
* However, it will be tied into the cache in terms of
* memory allocation, as it'll die if the cache is finalised.
*/
}
return inserted_meth;
} /* methodCacheInsert */
/*************************** end of file *******************************/
|