1 /* @source enscache ***********************************************************
2 **
3 ** Ensembl Cache functions
4 **
5 ** @author Copyright (C) 1999 Ensembl Developers
6 ** @author Copyright (C) 2006 Michael K. Schuster
7 ** @version $Revision: 1.40 $
8 ** @modified 2009 by Alan Bleasby for incorporation into EMBOSS core
9 ** @modified $Date: 2013/02/17 13:02:40 $ by $Author: mks $
10 ** @@
11 **
12 ** This library is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU Lesser General Public
14 ** License as published by the Free Software Foundation; either
15 ** version 2.1 of the License, or (at your option) any later version.
16 **
17 ** This library is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** Lesser General Public License for more details.
21 **
22 ** You should have received a copy of the GNU Lesser General Public
23 ** License along with this library; if not, write to the Free Software
24 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 ** MA 02110-1301, USA.
26 **
27 ******************************************************************************/
28
29 /* ========================================================================= */
30 /* ============================= include files ============================= */
31 /* ========================================================================= */
32
33 #include "enscache.h"
34 #include "enstable.h"
35
36
37
38
39 /* ========================================================================= */
40 /* =============================== constants =============================== */
41 /* ========================================================================= */
42
43
44
45
46 /* ========================================================================= */
47 /* =========================== global variables ============================ */
48 /* ========================================================================= */
49
50
51
52
53 /* ========================================================================= */
54 /* ============================= private data ============================== */
55 /* ========================================================================= */
56
57 /* @datastatic CachePNode *****************************************************
58 **
59 ** Ensembl Cache Node.
60 **
61 ** @alias CacheSNode
62 ** @alias CacheONode
63 **
64 ** @attr Key [void*] Key data address
65 ** @attr Value [void*] Value data address
66 ** @attr Bytes [size_t] Byte size of this node including key and value data
67 ** @attr Dirty [AjBool] Flag to mark that value data has not been written back
68 ** @attr Padding [ajuint] Padding to alignment boundary
69 ** @@
70 ******************************************************************************/
71
72 typedef struct CacheSNode
73 {
74 void *Key;
75 void *Value;
76 size_t Bytes;
77 AjBool Dirty;
78 ajuint Padding;
79 } CacheONode;
80
81 #define CachePNode CacheONode*
82
83
84
85
86 /* ========================================================================= */
87 /* =========================== private constants =========================== */
88 /* ========================================================================= */
89
90
91
92
93 /* ========================================================================= */
94 /* =========================== private variables =========================== */
95 /* ========================================================================= */
96
97
98
99
100 /* ========================================================================= */
101 /* =========================== private functions =========================== */
102 /* ========================================================================= */
103
104 static CachePNode cacheNodeNew(const EnsPCache cache, void *key, void *value);
105
106 static void cacheNodeDel(const EnsPCache cache, CachePNode *Pnode);
107
108 static AjBool cacheNodeInsert(EnsPCache cache, CachePNode node);
109
110 static AjBool cacheNodeRemove(EnsPCache cache, const CachePNode node);
111
112
113
114
115 /* ========================================================================= */
116 /* ======================= All functions by section ======================== */
117 /* ========================================================================= */
118
119
120
121
122 /* @filesection enscache ******************************************************
123 **
124 ** @nam1rule ens Function belongs to the Ensembl library
125 **
126 ******************************************************************************/
127
128
129
130
131 /* @funcstatic cacheNodeNew ***************************************************
132 **
133 ** Default constructor for an Ensembl Cache Node.
134 **
135 ** The size of the Cache Node will be estimated according to the Ensembl Cache
136 ** type with the function already provided at the Cache initialisation stage.
137 ** This fuction will also reference value data to increment an internal usage
138 ** counter and prevent deletion of value data while in the cache.
139 **
140 ** @param [r] cache [const EnsPCache] Ensembl Cache
141 ** @param [r] key [void*] Key data address
142 ** @param [r] value [void*] Value data address
143 **
144 ** @return [CachePNode] Ensembl Cache Node or NULL
145 **
146 ** @release 6.2.0
147 ** @@
148 ******************************************************************************/
149
cacheNodeNew(const EnsPCache cache,void * key,void * value)150 static CachePNode cacheNodeNew(const EnsPCache cache, void *key, void *value)
151 {
152 ajuint *Puintkey = NULL;
153
154 CachePNode node = NULL;
155
156 if (!cache)
157 return NULL;
158
159 if (!key)
160 return NULL;
161
162 if (!value)
163 return NULL;
164
165 AJNEW0(node);
166
167 /* Add the size of the Ensembl Cache Node itself. */
168
169 node->Bytes = sizeof (CacheONode);
170
171 switch (cache->Type)
172 {
173 case ensECacheTypeNumeric:
174
175 /* Copy AJAX unsigned integer key data. */
176
177 AJNEW0(Puintkey);
178
179 *Puintkey = *((ajuint *) key);
180
181 node->Key = (void *) Puintkey;
182
183 /* Add the size of unsigned integer key data. */
184
185 node->Bytes += sizeof (ajuint);
186
187 break;
188
189 case ensECacheTypeAlphaNumeric:
190
191 /* Copy AJAX String key data. */
192
193 node->Key = (void *) ajStrNewS((AjPStr) key);
194
195 /* Add the size of AJAX String key data. */
196
197 node->Bytes += sizeof (AjOStr);
198
199 node->Bytes += ajStrGetRes((AjPStr) node->Key);
200
201 break;
202
203 default:
204
205 ajWarn("cacheNodeNew got unexpected Cache type %d.\n",
206 cache->Type);
207 }
208
209 /* Reference the value data. */
210
211 if (cache->Freference && value)
212 node->Value = (*cache->Freference) (value);
213
214 /* Calculate the size of the value data. */
215
216 if (cache->Fsize && node->Value)
217 node->Bytes += (*cache->Fsize) (node->Value);
218
219 node->Dirty = ajFalse;
220
221 return node;
222 }
223
224
225
226
227 /* @funcstatic cacheNodeDel ***************************************************
228 **
229 ** Default destructor for an Ensembl Cache Node.
230 **
231 ** @param [r] cache [const EnsPCache] Ensembl Cache
232 ** @param [d] Pnode [CachePNode*] Ensembl Cache Node address
233 **
234 ** @return [void]
235 **
236 ** @release 6.2.0
237 ** @@
238 ******************************************************************************/
239
cacheNodeDel(const EnsPCache cache,CachePNode * Pnode)240 static void cacheNodeDel(const EnsPCache cache, CachePNode *Pnode)
241 {
242 CachePNode pthis = NULL;
243
244 if (!cache)
245 return;
246
247 if (!Pnode)
248 return;
249
250 #if defined(AJ_DEBUG) && AJ_DEBUG >= 1
251 if (ajDebugTest("cacheNodeDel"))
252 {
253 ajDebug("cacheNodeDel\n"
254 " *Pnode %p\n",
255 *Pnode);
256
257 /* cacheNodeTrace(*Pnode, 1); */
258 }
259 #endif /* defined(AJ_DEBUG) && AJ_DEBUG >= 1 */
260
261 if (!(pthis = *Pnode))
262 return;
263
264 /* Delete key data. */
265
266 switch (cache->Type)
267 {
268 case ensECacheTypeNumeric:
269
270 /* Delete AJAX unsigned integer key data. */
271
272 AJFREE(pthis->Key);
273
274 break;
275
276 case ensECacheTypeAlphaNumeric:
277
278 /* Delete AJAX String key data. */
279
280 ajStrDel((AjPStr *) &pthis->Key);
281
282 break;
283
284 default:
285
286 ajWarn("cacheNodeDel got unexpected Cache type %d.\n",
287 cache->Type);
288 }
289
290 /* Delete value data. */
291
292 if (cache->Fdelete && pthis->Value)
293 (*cache->Fdelete) (&pthis->Value);
294
295 ajMemFree((void **) Pnode);
296
297 return;
298 }
299
300
301
302
303 /* @funcstatic cacheNodeInsert ************************************************
304 **
305 ** Insert an Ensembl Cache Node into an Ensembl Cache.
306 **
307 ** @param [u] cache [EnsPCache] Ensembl Cache
308 ** @param [u] node [CachePNode] Ensembl Cache Node
309 **
310 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
311 **
312 ** @release 6.2.0
313 ** @@
314 ******************************************************************************/
315
cacheNodeInsert(EnsPCache cache,CachePNode node)316 static AjBool cacheNodeInsert(EnsPCache cache, CachePNode node)
317 {
318 CachePNode old = NULL;
319
320 if (!cache)
321 return ajFalse;
322
323 if (!node)
324 return ajFalse;
325
326 if (cache->MaxSize && (node->Bytes > cache->MaxSize))
327 return ajFalse;
328
329 /* Insert the node into the AJAX List. */
330
331 ajListPushAppend(cache->List, (void *) node);
332
333 /* Insert the node into the AJAX Table. */
334
335 ajTablePut(cache->Table, node->Key, (void *) node);
336
337 /* Update the cache statistics. */
338
339 cache->Bytes += node->Bytes;
340
341 cache->Count++;
342
343 cache->Stored++;
344
345 /* If the cache is too big, remove the top node(s). */
346
347 while ((cache->MaxBytes && (cache->Bytes > cache->MaxBytes)) ||
348 (cache->MaxCount && (cache->Count > cache->MaxCount)))
349 {
350 /* Remove the top node from the AJAX List. */
351
352 ajListPop(cache->List, (void **) &old);
353
354 /* Remove the node also from the AJAX Table. */
355
356 ajTableRemove(cache->Table, old->Key);
357
358 /* Update the cache statistics. */
359
360 cache->Bytes -= old->Bytes;
361
362 cache->Count--;
363
364 cache->Dropped++;
365
366 /* Write changes of value data to disk if any. */
367
368 if (cache->Fwrite && old->Value && old->Dirty)
369 (*cache->Fwrite) (old->Value);
370
371 /* Both, key and value data are deleted via cacheNodeDel. */
372
373 cacheNodeDel(cache, &old);
374 }
375
376 return ajTrue;
377 }
378
379
380
381
382 /* @funcstatic cacheNodeRemove ************************************************
383 **
384 ** Remove an Ensembl Cache Node from an Ensembl Cache.
385 **
386 ** @param [u] cache [EnsPCache] Ensembl Cache
387 ** @param [r] node [const CachePNode] Ensembl Cache Node
388 **
389 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
390 **
391 ** @release 6.2.0
392 ** @@
393 ******************************************************************************/
394
cacheNodeRemove(EnsPCache cache,const CachePNode node)395 static AjBool cacheNodeRemove(EnsPCache cache, const CachePNode node)
396 {
397 AjIList iter = NULL;
398
399 CachePNode lnode = NULL;
400
401 if (!cache)
402 return ajFalse;
403
404 if (!node)
405 return ajFalse;
406
407 /* Remove the node from the AJAX List. */
408
409 iter = ajListIterNew(cache->List);
410
411 while (!ajListIterDone(iter))
412 {
413 lnode = (CachePNode) ajListIterGet(iter);
414
415 if (lnode == node)
416 {
417 ajListIterRemove(iter);
418
419 break;
420 }
421 }
422
423 ajListIterDel(&iter);
424
425 /* Remove the node from the AJAX Table. */
426
427 ajTableRemove(cache->Table, node->Key);
428
429 /* Update the cache statistics. */
430
431 cache->Bytes -= node->Bytes;
432
433 cache->Count--;
434
435 cache->Removed++;
436
437 return ajTrue;
438 }
439
440
441
442
443 /* @datasection [EnsPCache] Ensembl Cache *************************************
444 **
445 ** @nam2rule Cache Functions for manipulating Ensembl Cache objects
446 ** @cc Bio::EnsEMBL::Utils::Cache
447 ** @cc CVS Revision: 1.3
448 ** @cc CVS Tag: branch-ensembl-68
449 **
450 ******************************************************************************/
451
452
453
454
455 /* @section constructors ******************************************************
456 **
457 ** @fdata [EnsPCache]
458 **
459 ** @nam3rule New Constructor
460 **
461 ** @argrule New type [const EnsECacheType] Ensembl Cache type
462 ** @argrule New maxbytes [size_t] Maximum number of bytes held in the cache
463 ** @argrule New maxcount [ajuint] Maximum number of objects to be cached
464 ** @argrule New maxsize [size_t] Maximum size of an object to be cached
465 ** @argrule New Freference [void* function] Object-specific referencing
466 ** function
467 ** @argrule New Fdelete [void function] Object-specific deletion function
468 ** @argrule New Fsize [size_t function] Object-specific memory sizing function
469 ** @argrule New Fread [void* function] Object-specific reading function
470 ** @argrule New Fwrite [AjBool function] Object-specific writing function
471 ** @argrule New synchron [AjBool] ajTrue: Immediately write-back value data
472 ** @argrule New label [const char*] Cache label for statistics output
473 **
474 ** @valrule * [EnsPCache] Ensembl Cache or NULL
475 **
476 ** @fcategory new
477 ******************************************************************************/
478
479
480
481
482 /* @func ensCacheNew **********************************************************
483 **
484 ** Default constructor for an Ensembl Cache.
485 **
486 ** @param [r] type [const EnsECacheType] Ensembl Cache type
487 ** (ensECacheTypeNumeric or ensECacheTypeAlphaNumeric)
488 ** @param [r] maxbytes [size_t] Maximum number of bytes held in the cache
489 ** @param [r] maxcount [ajuint] Maximum number of objects to be cached
490 ** @param [r] maxsize [size_t] Maximum size of an object to be cached
491 ** @param [f] Freference [void* function] Object-specific referencing function
492 ** @param [f] Fdelete [void function] Object-specific deletion function
493 ** @param [f] Fsize [size_t function] Object-specific memory sizing function
494 ** @param [f] Fread [void* function] Object-specific reading function
495 ** @param [f] Fwrite [AjBool function] Object-specific writing function
496 ** @param [r] synchron [AjBool] ajTrue: Immediately write-back value data
497 ** ajFalse: Write-back value data later
498 ** @param [r] label [const char*] Cache label for statistics output
499 **
500 ** @return [EnsPCache] Ensembl Cache or NULL
501 **
502 ** @release 6.2.0
503 ** @@
504 ** The maximum size parameter should prevent the cache from purging too many
505 ** objects when very large objects are inserted. If not set it defaults to
506 ** a tenth of the maximum cache size.
507 **
508 ** Object-specific functions are required to reference objects held in the
509 ** cache or delete objects once purged from the cache, as well as memory sizing
510 ** functions and object-specific read and write back functions.
511 ******************************************************************************/
512
ensCacheNew(const EnsECacheType type,size_t maxbytes,ajuint maxcount,size_t maxsize,void * (* Freference)(void * value),void (* Fdelete)(void ** Pvalue),size_t (* Fsize)(const void * value),void * (* Fread)(const void * key),AjBool (* Fwrite)(const void * value),AjBool synchron,const char * label)513 EnsPCache ensCacheNew(const EnsECacheType type,
514 size_t maxbytes,
515 ajuint maxcount,
516 size_t maxsize,
517 void* (*Freference) (void *value),
518 void (*Fdelete) (void **Pvalue),
519 size_t (*Fsize) (const void *value),
520 void* (*Fread) (const void *key),
521 AjBool (*Fwrite) (const void *value),
522 AjBool synchron,
523 const char *label)
524 {
525 AjBool debug = AJFALSE;
526
527 EnsPCache cache = NULL;
528
529 debug = ajDebugTest("ensCacheNew");
530
531 if (debug)
532 ajDebug("ensCacheNew\n"
533 " type %d\n"
534 " maxbytes %Lu\n"
535 " maxcount %u\n"
536 " maxsize %Lu\n"
537 " Freference %p\n"
538 " Fdelete %p\n"
539 " Fsize %p\n"
540 " Fread %p\n"
541 " Fwrite %p\n"
542 " synchron '%B'\n"
543 " label '%s'\n",
544 type,
545 maxbytes,
546 maxcount,
547 maxsize,
548 Freference,
549 Fdelete,
550 Fsize,
551 Fread,
552 Fwrite,
553 synchron,
554 label);
555 /* FIXME: size_t can be shorter than ajulong */
556
557 if ((type < ensECacheTypeNumeric) || (type > ensECacheTypeAlphaNumeric))
558 ajFatal("ensCacheNew requires a valid type.\n");
559
560 if ((!maxbytes) && (!maxcount))
561 ajFatal("ensCacheNew requires either a "
562 "maximum bytes or maximum count limit.\n");
563
564 if (!maxsize)
565 maxsize = maxbytes ? maxbytes / 10 + 1 : 0;
566
567 if (maxbytes && (!maxsize))
568 ajFatal("ensCacheNew requires a maximum size limit, "
569 "when a maximum bytes limit is set.");
570
571 /* TODO: Find and set a sensible value here! */
572 /* FIXME: size_t can be shorter than ajulong */
573 if (debug)
574 ajDebug("ensCacheNew maxbytes %Lu, maxcount %u, maxsize %Lu.\n",
575 maxbytes, maxcount, maxsize);
576
577 if (maxbytes && (maxbytes < 1000))
578 ajFatal("ensCacheNew cannot set a maximum bytes limit (%Lu) under "
579 "1000, as each Cache Node requires %Lu bytes alone.",
580 maxbytes, sizeof (CacheONode));
581
582 /* TODO: Find and set a sensible value here! */
583
584 if (maxsize && (maxsize < 3))
585 ajFatal("ensCacheNew cannot set a maximum size limit (%Lu) under "
586 "3 bytes. maximum bytes %Lu maximum count %u.",
587 maxsize, maxbytes, maxcount);
588
589 /*
590 ** Pointers to functions for automatic reading of data not yet in the
591 ** cache and writing of data modified in cache are not mandatory.
592 ** If not specified the cache will simply lack this functionality.
593 ** However, the specification of a function deleting stale cache entries
594 ** and a function calculating the size of value data are required.
595 */
596
597 if (!Freference)
598 ajFatal("ensCacheNew requires a referencing function.");
599
600 if (!Fdelete)
601 ajFatal("ensCacheNew requires a deletion function.");
602
603 if (maxsize && (!Fsize))
604 ajFatal("ensCacheNew requires a memory sizing function "
605 "when a maximum size limit has been defined.");
606
607 if (!label)
608 ajFatal("ensCacheNew requires a label.");
609
610 AJNEW0(cache);
611
612 cache->Label = ajStrNewC(label);
613 cache->List = ajListNew();
614
615 switch (type)
616 {
617 case ensECacheTypeNumeric:
618
619 cache->Table = ajTableuintNew(0U);
620
621 break;
622
623 case ensECacheTypeAlphaNumeric:
624
625 cache->Table = ajTablestrNew(0U);
626
627 break;
628
629 default:
630
631 ajWarn("ensCacheNew got unexpected Cache type %d.\n",
632 cache->Type);
633 }
634
635 /*
636 ** Since the AJAX Table does not use real key or value data,
637 ** both, keydel and valdel need setting to NULL.
638 */
639
640 ajTableSetDestroy(
641 cache->Table,
642 (void (*)(void **)) NULL,
643 (void (*)(void **)) NULL);
644
645 cache->Freference = Freference;
646 cache->Fdelete = Fdelete;
647 cache->Fsize = Fsize;
648 cache->Fread = Fread;
649 cache->Fwrite = Fwrite;
650 cache->Type = type;
651 cache->Synchron = synchron;
652 cache->MaxBytes = maxbytes;
653 cache->MaxCount = maxcount;
654 cache->MaxSize = maxsize;
655 cache->Bytes = 0;
656 cache->Count = 0;
657 cache->Dropped = 0;
658 cache->Removed = 0;
659 cache->Stored = 0;
660 cache->Hit = 0;
661 cache->Miss = 0;
662
663 return cache;
664 }
665
666
667
668
669 /* @section destructors *******************************************************
670 **
671 ** Destruction destroys all internal data structures and frees the memory
672 ** allocated for an Ensembl Cache object.
673 **
674 ** @fdata [EnsPCache]
675 **
676 ** @nam3rule Del Destroy (free) an Ensembl Cache
677 **
678 ** @argrule * Pcache [EnsPCache*] Ensembl Cache address
679 **
680 ** @valrule * [void]
681 **
682 ** @fcategory delete
683 ******************************************************************************/
684
685
686
687
688 /* @func ensCacheDel **********************************************************
689 **
690 ** Default destructor for an Ensembl Cache.
691 **
692 ** @param [u] Pcache [EnsPCache*] Ensembl Cache address
693 **
694 ** @return [void]
695 **
696 ** @release 6.2.0
697 ** @@
698 ** Value data in Cache Nodes that have not been synchronised are written-back.
699 ** Cache flags are reset for value data before the value data is deleted.
700 ** After deletion of all Cache Nodes a summary statistics is printed and the
701 ** Ensembl Cache is destroyed.
702 ******************************************************************************/
703
ensCacheDel(EnsPCache * Pcache)704 void ensCacheDel(EnsPCache *Pcache)
705 {
706 AjBool debug = AJFALSE;
707
708 EnsPCache pthis = NULL;
709
710 if (!Pcache)
711 return;
712
713 #if defined(AJ_DEBUG) && AJ_DEBUG >= 1
714 debug = ajDebugTest("ensCacheDel");
715
716 if (debug)
717 ajDebug("ensCacheDel\n"
718 " *Pcache %p\n",
719 *Pcache);
720 #endif /* defined(AJ_DEBUG) && AJ_DEBUG >= 1 */
721
722 if (!(pthis = *Pcache))
723 return;
724
725 ensCacheClear(pthis);
726
727 if (debug)
728 ensCacheTrace(pthis, 1);
729
730 ajStrDel(&pthis->Label);
731
732 ajListFree(&pthis->List);
733
734 ajTableFree(&pthis->Table);
735
736 ajMemFree((void **) Pcache);
737
738 return;
739 }
740
741
742
743
744 /* @section clear *************************************************************
745 **
746 ** Clear an Ensembl Cache.
747 **
748 ** @fdata [EnsPCache]
749 **
750 ** @nam3rule Clear Clear an Ensembl Cache
751 **
752 ** @argrule * cache [EnsPCache] Ensembl Cache
753 **
754 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
755 **
756 ** @fcategory modify
757 ******************************************************************************/
758
759
760
761
762 /* @func ensCacheClear ********************************************************
763 **
764 ** Clear an Ensembl Cache.
765 **
766 ** @param [u] cache [EnsPCache] Ensembl Cache
767 **
768 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
769 **
770 ** @release 6.5.0
771 ** @@
772 ** Value data in Cache Node objects that have not been synchronised are
773 ** written-back. Cache flags are reset for value data before the value data
774 ** is deleted.
775 ******************************************************************************/
776
ensCacheClear(EnsPCache cache)777 AjBool ensCacheClear(EnsPCache cache)
778 {
779 CachePNode node = NULL;
780
781 if (!cache)
782 return ajFalse;
783
784 /* Remove Cache Node objects from the AJAX List. */
785
786 while (ajListPop(cache->List, (void **) &node))
787 {
788 /* Remove the same Cache Node object from the AJAX Table. */
789
790 (void) ajTableRemove(cache->Table, node->Key);
791
792 /* Update the cache statistics. */
793
794 cache->Count--;
795
796 cache->Bytes -= node->Bytes;
797
798 /* Write changes of value data to disk if any. */
799
800 if (cache->Fwrite && node->Value && node->Dirty)
801 (*cache->Fwrite) (node->Value);
802
803 /* Both, key and value data are deleted via cacheNodeDel. */
804
805 cacheNodeDel(cache, &node);
806 }
807
808 return ajTrue;
809 }
810
811
812
813
814 /* @section debugging *********************************************************
815 **
816 ** Functions for reporting of an Ensembl Cache object.
817 **
818 ** @fdata [EnsPCache]
819 **
820 ** @nam3rule Trace Report Ensembl Cache members to debug file.
821 **
822 ** @argrule Trace cache [const EnsPCache] Ensembl Cache
823 ** @argrule Trace level [ajuint] Indentation level
824 **
825 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
826 **
827 ** @fcategory misc
828 ******************************************************************************/
829
830
831
832
833 /* @func ensCacheTrace ********************************************************
834 **
835 ** Writes debug messages to trace the contents of a cache.
836 **
837 ** @param [r] cache [const EnsPCache] Ensembl Cache
838 ** @param [r] level [ajuint] Indentation level
839 **
840 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
841 **
842 ** @release 6.2.0
843 ** @@
844 ******************************************************************************/
845
ensCacheTrace(const EnsPCache cache,ajuint level)846 AjBool ensCacheTrace(const EnsPCache cache, ajuint level)
847 {
848 double ratio = 0.0;
849
850 AjPStr indent = NULL;
851
852 if (!cache)
853 return ajFalse;
854
855 indent = ajStrNew();
856
857 ajStrAppendCountK(&indent, ' ', level * 2);
858
859 if (cache->Hit || cache->Miss)
860 ratio = (double) cache->Hit /
861 ((double) cache->Hit + (double) cache->Miss);
862
863 ajDebug("%SensCache trace %p\n"
864 "%S Label '%S'\n"
865 "%S List %p length: %Lu\n"
866 "%S Table %p length: %Lu\n"
867 "%S Type %d\n"
868 "%S Synchron '%B'\n"
869 "%S MaxBytes %Lu\n" /* FIXME: size_t can be shorter than ajulong */
870 "%S MaxCount %u\n"
871 "%S MaxSize %Lu\n" /* FIXME: size_t can be shorter than ajulong */
872 "%S Bytes %Lu\n" /* FIXME: size_t can be shorter than ajulong */
873 "%S Count %u\n"
874 "%S Dropped %u\n"
875 "%S Removed %u\n"
876 "%S Stored %u\n"
877 "%S Hit %u\n"
878 "%S Miss %u\n"
879 "%S Hit/(Hit + Miss) %f\n",
880 indent, cache,
881 indent, cache->Label,
882 indent, cache->List, ajListGetLength(cache->List),
883 indent, cache->Table, ajTableGetLength(cache->Table),
884 indent, cache->Type,
885 indent, cache->Synchron,
886 indent, cache->MaxBytes,
887 indent, cache->MaxCount,
888 indent, cache->MaxSize,
889 indent, cache->Bytes,
890 indent, cache->Count,
891 indent, cache->Dropped,
892 indent, cache->Removed,
893 indent, cache->Stored,
894 indent, cache->Hit,
895 indent, cache->Miss,
896 indent, ratio);
897
898 ajStrDel(&indent);
899
900 return ajTrue;
901 }
902
903
904
905
906 /* @section modify ************************************************************
907 **
908 ** Update cache object values
909 **
910 ** @fdata [EnsPCache]
911 **
912 ** @nam3rule Fetch Fetch value data from an Ensembl Cache
913 ** @nam3rule Remove Remove value data from an Ensembl Cache
914 ** @nam3rule Store Insert a value into an Ensembl Cache
915 ** @nam3rule Synchronise Synchronise an Ensembl Cache
916 **
917 ** @argrule Fetch cache [EnsPCache] Ensembl Cache
918 ** @argrule Fetch key [void*] Key data address
919 ** @argrule Fetch Pvalue [void**] Value data address address
920 ** @argrule Remove cache [EnsPCache] Ensembl Cache
921 ** @argrule Remove key [const void*] Key data address
922 ** @argrule Store cache [EnsPCache] Ensembl Cache
923 ** @argrule Store key [void*] Key data address
924 ** @argrule Store Pvalue [void**] Value data address adress
925 ** @argrule Synchronise cache [EnsPCache] Ensembl Cache
926 **
927 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
928 **
929 ** @fcategory modify
930 ******************************************************************************/
931
932
933
934
935 /* @func ensCacheFetch ********************************************************
936 **
937 ** Fetch a value from an Ensembl Cache via a key. If the value is not already
938 ** in the cache it will be read by the function provided at the Cache
939 ** initialisation stage.
940 **
941 ** The caller is responsible for deleting the returned object.
942 **
943 ** @param [u] cache [EnsPCache] Ensembl Cache
944 ** @param [r] key [void*] Key data address
945 ** @param [wP] Pvalue [void**] Value data address address
946 **
947 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
948 **
949 ** @release 6.2.0
950 ** @@
951 ******************************************************************************/
952
ensCacheFetch(EnsPCache cache,void * key,void ** Pvalue)953 AjBool ensCacheFetch(EnsPCache cache, void *key, void **Pvalue)
954 {
955 AjIList iter = NULL;
956
957 CachePNode lnode = NULL;
958 CachePNode tnode = NULL;
959
960 if (!cache)
961 return ajFalse;
962
963 if (!key)
964 return ajFalse;
965
966 if (!Pvalue)
967 return ajFalse;
968
969 *Pvalue = NULL;
970
971 tnode = (CachePNode) ajTableFetchmodV(cache->Table, key);
972
973 if (tnode)
974 {
975 cache->Hit++;
976
977 /* Move the Cache Node to the end of the AJAX List. */
978
979 iter = ajListIterNew(cache->List);
980
981 while (!ajListIterDone(iter))
982 {
983 lnode = (CachePNode) ajListIterGet(iter);
984
985 if (lnode == tnode)
986 {
987 ajListIterRemove(iter);
988
989 ajListPushAppend(cache->List, (void *) lnode);
990
991 break;
992 }
993 }
994
995 ajListIterDel(&iter);
996
997 /*
998 ** Reference the object when returned by the cache so that external
999 ** code has to delete it irrespectively whether it was read from the
1000 ** cache or instantiated by the cache->Fread function.
1001 */
1002
1003 if (cache->Freference && tnode->Value)
1004 *Pvalue = (*cache->Freference) (tnode->Value);
1005 }
1006 else
1007 {
1008 cache->Miss++;
1009
1010 if (cache->Fread)
1011 {
1012 *Pvalue = (*cache->Fread) (key);
1013
1014 if (*Pvalue)
1015 {
1016 tnode = cacheNodeNew(cache, key, *Pvalue);
1017
1018 if (!cacheNodeInsert(cache, tnode))
1019 cacheNodeDel(cache, &tnode);
1020 }
1021 }
1022 }
1023
1024 return ajTrue;
1025 }
1026
1027
1028
1029
1030 /* @func ensCacheRemove *******************************************************
1031 **
1032 ** Remove value data from an Ensembl Cache via key data.
1033 **
1034 ** @param [u] cache [EnsPCache] Ensembl Cache
1035 ** @param [r] key [const void*] Key data address
1036 **
1037 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1038 **
1039 ** @release 6.2.0
1040 ** @@
1041 ******************************************************************************/
1042
ensCacheRemove(EnsPCache cache,const void * key)1043 AjBool ensCacheRemove(EnsPCache cache, const void *key)
1044 {
1045 CachePNode node = NULL;
1046
1047 if (!cache)
1048 return ajFalse;
1049
1050 if (!key)
1051 return ajFalse;
1052
1053 node = (CachePNode) ajTableFetchmodV(cache->Table, key);
1054
1055 if (node)
1056 {
1057 cacheNodeRemove(cache, node);
1058
1059 /* Both, key and value data are deleted via cacheNodeDel. */
1060
1061 cacheNodeDel(cache, &node);
1062 }
1063
1064 return ajTrue;
1065 }
1066
1067
1068
1069
1070 /* @func ensCacheStore ********************************************************
1071 **
1072 ** Insert value data into an Ensembl Cache under key data.
1073 **
1074 ** @param [u] cache [EnsPCache] Ensembl Cache
1075 ** @param [u] key [void*] Key data address
1076 ** @param [w] Pvalue [void**] Value data address address
1077 **
1078 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1079 **
1080 ** @release 6.2.0
1081 ** @@
1082 ******************************************************************************/
1083
ensCacheStore(EnsPCache cache,void * key,void ** Pvalue)1084 AjBool ensCacheStore(EnsPCache cache, void *key, void **Pvalue)
1085 {
1086 CachePNode node = NULL;
1087
1088 if (!cache)
1089 return ajFalse;
1090
1091 if (!key)
1092 return ajFalse;
1093
1094 if (!Pvalue)
1095 return ajFalse;
1096
1097 /* Is a node already cached under this key? */
1098
1099 node = (CachePNode) ajTableFetchmodV(cache->Table, key);
1100
1101 if (node)
1102 {
1103 /*
1104 ** Delete the Object passed in and increase the reference counter
1105 ** of the cached Object before assigning it.
1106 */
1107
1108 (*cache->Fdelete) (Pvalue);
1109
1110 *Pvalue = (*cache->Freference) (node->Value);
1111 }
1112 else
1113 {
1114 node = cacheNodeNew(cache, key, *Pvalue);
1115
1116 if (cacheNodeInsert(cache, node))
1117 {
1118 if (cache->Synchron)
1119 {
1120 if (cache->Fwrite && node->Value)
1121 (*cache->Fwrite) (node->Value);
1122
1123 node->Dirty = ajFalse;
1124 }
1125 else
1126 node->Dirty = ajTrue;
1127 }
1128 else
1129 {
1130 if (cache->Fwrite && node->Value)
1131 (*cache->Fwrite) (node->Value);
1132
1133 cacheNodeDel(cache, &node);
1134 }
1135 }
1136
1137 return ajTrue;
1138 }
1139
1140
1141
1142
1143 /* @func ensCacheSynchronise **************************************************
1144 **
1145 ** Synchronise an Ensembl Cache by writing-back all value data that have not
1146 ** been written before.
1147 **
1148 ** @param [u] cache [EnsPCache] Ensembl Cache
1149 **
1150 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1151 **
1152 ** @release 6.2.0
1153 ** @@
1154 ******************************************************************************/
1155
ensCacheSynchronise(EnsPCache cache)1156 AjBool ensCacheSynchronise(EnsPCache cache)
1157 {
1158 AjIList iter = NULL;
1159
1160 CachePNode node = NULL;
1161
1162 if (!cache)
1163 return ajFalse;
1164
1165 iter = ajListIterNew(cache->List);
1166
1167 while (!ajListIterDone(iter))
1168 {
1169 node = (CachePNode) ajListIterGet(iter);
1170
1171 if (cache->Fwrite && node->Value && node->Dirty)
1172 {
1173 (*cache->Fwrite) (node->Value);
1174
1175 node->Dirty = ajFalse;
1176 }
1177 }
1178
1179 ajListIterDel(&iter);
1180
1181 return ajTrue;
1182 }
1183