Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / mbk / mbk_cache.c
1 #include MUT_H
2 #include AVT_H
3 #include "mbk_cache.h"
4
5 mbkcache *FILE_CACHE = NULL ;
6 int FILE_CACHE_INDEX = 0 ;
7 HeapAlloc FILE_CACHE_HEAP ;
8 ht *FILE_CACHE_HT = NULL ;
9 int MBK_MAX_CACHE = 128 ;
10
11 /*****************************************************************************\
12 mbk_cache_create()
13 Fonction utilisateur.
14 Crée un nouveau cache.
15 \*****************************************************************************/
16
17 mbkcache* mbk_cache_create( char (*isactive)( void *root, void *elem ),
18 unsigned long int (*load )( void *root, void *elem ),
19 unsigned long int (*release )( void *root, void *elem ),
20 unsigned long int cachesize
21 )
22 {
23 mbkcache *cache;
24
25 cache = mbk_cache_alloc();
26
27 cache->CACHESIZE = cachesize;
28 cache->INFOS = addht( CACHE_ALLOC_BLOCLIST );
29 cache->FN_ISACTIVE = isactive;
30 cache->FN_LOAD = load;
31 cache->FN_RELEASE = release;
32
33 return cache;
34 }
35
36 /*****************************************************************************\
37 mbk_cache_refresh()
38 Fonction utilisateur.
39 Charge en mémoire un élément si il n'est pas déjà présent. Libère d'autres
40 éléments si c'est nécessaire.
41 \*****************************************************************************/
42
43 void mbk_cache_refresh( mbkcache *cache, void *root, void *elem )
44 {
45 mbkcachelist *incache;
46
47 if( !cache || mbk_cache_call_iscative( cache, root, elem ) == 0 )
48 return;
49
50 avt_logenterfunction(LOGMBKCACHE,2, "mbk_cache_refresh()" );
51 incache = mbk_cache_getmbkcachelist( cache, elem );
52
53 if( incache ) {
54 avt_log(LOGMBKCACHE,2,"element already loaded\n");
55 // L'élément est présent dans le cache, on le met en tête des éléments les
56 // derniers accédés.
57 if( incache != cache->FIRST )
58 mbk_cache_makeitfirst( cache, incache );
59 }
60 else {
61
62 // L'élément n'est pas dans le cache. On fait du ménage si necéssaire, puis
63 // on lit le nouvel élément.
64
65 // si le cache est limité en nb d'éléments, on réserve un éléments pour
66 // celui qui va être lu.
67 if( cache->MAXELEM )
68 cache->CURELEM++;
69
70 mbk_cache_update_memory( cache, root );
71
72 if( cache->MAXELEM )
73 cache->CURELEM--;
74
75 if( elem )
76 mbk_cache_add( cache, root, elem );
77 }
78
79 avt_logexitfunction(LOGMBKCACHE,2);
80 }
81
82 /*****************************************************************************\
83 mbk_cache_release()
84 Fonction utilisateur.
85 Force la libération d'un élément du cache.
86 \*****************************************************************************/
87
88 void mbk_cache_release( mbkcache *cache, void *root, void *elem )
89 {
90 mbkcachelist *incache;
91
92 if( !cache || mbk_cache_call_iscative( cache, root, elem ) == 0 )
93 return;
94
95 incache = mbk_cache_getmbkcachelist( cache, elem );
96 if( incache == NULL ) return;
97
98 if( incache->LOCKED == 0 )
99 mbk_cache_remove( cache, incache, root );
100 }
101
102 /*****************************************************************************\
103 mbk_cache_delete()
104 Fonction utilisateur.
105 Efface le cache. Appel mbk_cache_release() pour tous les éléments encore
106 présents dans le cache.
107 \*****************************************************************************/
108
109 extern void mbk_cache_delete( mbkcache *cache, void *root )
110 {
111 while( cache->FIRST )
112 mbk_cache_remove( cache, cache->FIRST, root );
113 mbk_cache_free( cache );
114 }
115
116 /*****************************************************************************\
117 mbk_cache_lock()
118 Fonction utilisateur.
119 Verrouille un élément en mémoire
120 \*****************************************************************************/
121
122 extern void mbk_cache_lock( mbkcache *cache, void *elem )
123 {
124 mbkcachelist *incache;
125
126 incache = mbk_cache_getmbkcachelist( cache, elem );
127 if( incache == NULL ) return;
128
129 incache->LOCKED++;
130 }
131
132 /*****************************************************************************\
133 mbk_cache_unlock()
134 Fonction utilisateur.
135 Deverrouille un élément en mémoire
136 \*****************************************************************************/
137
138 extern void mbk_cache_unlock( mbkcache *cache, void *elem )
139 {
140 mbkcachelist *incache;
141
142 incache = mbk_cache_getmbkcachelist( cache, elem );
143 if( incache == NULL ) return;
144
145 if( incache->LOCKED > 0 )
146 incache->LOCKED--;
147 }
148
149 /*****************************************************************************\
150 mbk_cache_islock()
151 Fonction utilisateur.
152 Informe si l'élément est vérouillé
153 \*****************************************************************************/
154
155 extern char mbk_cache_islock( mbkcache *cache, void *elem )
156 {
157 mbkcachelist *incache;
158
159 incache = mbk_cache_getmbkcachelist( cache, elem );
160 if( incache == NULL ) return NO;
161
162 if( incache->LOCKED > 0 )
163 return YES;
164 return NO;
165 }
166
167 /*****************************************************************************\
168 mbk_cache_update_size()
169 Fonction utilisateur.
170 Informe le cache que la taille d'un ou plusieurs de ses éléments a changée.
171 Libère des éléments si la taille maximum du cache a été dépassée.
172 \*****************************************************************************/
173 void mbk_cache_update_size( mbkcache *cache, void *root, long int size )
174 {
175 cache->CURSIZE = cache->CURSIZE + size ;
176 mbk_cache_update_memory( cache, root );
177 }
178
179 /*****************************************************************************\
180 mbk_cache_list_content()
181 Fonction utilisateur.
182 renvoie la liste chainée des éléments présents dans le cache
183 \*****************************************************************************/
184 chain_list* mbk_cache_list_content( mbkcache *cache )
185 {
186 mbkcachelist *scan ;
187 chain_list *list ;
188
189 list = NULL ;
190
191 for( scan = cache->LAST ; scan ; scan = scan->PREV ) {
192 list = addchain( list, scan->DATA );
193 }
194
195 return list ;
196 }
197
198 /*****************************************************************************\
199 mbk_cache_set_limit_element()
200 Fonction utilisateur
201 Limite le nombre d'éléments pouvant être présent à chaque instant dans le
202 cache, en plus du critère de taille de cache.
203 Si 0, le nombre d'élément est illimité, le nombre d'éléments présents dans le
204 cache n'est limité que par la taille du cache.
205 Appelle automatiquement mbk_cache_release() pour tous les éléments en excès dans
206 le cache.
207 \*****************************************************************************/
208 void mbk_cache_set_limit_element( mbkcache *cache,
209 void *root,
210 unsigned int nbelem
211 )
212 {
213 cache->MAXELEM = nbelem ;
214 mbk_cache_update_memory( cache, root );
215 }
216
217 /*****************************************************************************\
218 mbk_cache_update_memory()
219 Fonction interne.
220 Si la taille maximum du cache est atteinte ou dépassée, libère les éléments de
221 la mémoire
222 \*****************************************************************************/
223 void mbk_cache_update_memory( mbkcache *cache, void *root )
224 {
225 mbkcachelist *lastlock;
226 mbkcachelist *testremove;
227
228 lastlock = NULL;
229 while( cache->CURSIZE >= cache->CACHESIZE ||
230 ( cache->MAXELEM > 0 && cache->CURELEM >= cache->MAXELEM ) ) {
231
232 if( lastlock )
233 testremove = lastlock->PREV ;
234 else
235 testremove = cache->LAST ;
236
237 if( !testremove )
238 break ;
239
240 if( mbk_cache_islock( cache, testremove->DATA )==NO )
241 mbk_cache_remove( cache, testremove, root );
242 else
243 lastlock = testremove ;
244
245 if( cache->FIRST == lastlock ) {
246 /* Le cache est saturé d'éléments vérrouillés */
247 if( cache->MAXELEM > 0 && cache->CURELEM > cache->MAXELEM ) {
248 avt_log(LOGMBKCACHE,2,"maximum number of element in cache is excedeed : max=%u current=%u\n", cache->MAXELEM, cache->CURELEM );
249 }
250 break;
251 }
252 }
253 }
254
255 /*****************************************************************************\
256 mbk_cache_add()
257 Fonction interne.
258 Ajoute un élément dans le cache.
259 \*****************************************************************************/
260 void mbk_cache_add( mbkcache *cache, void *root, void *elem )
261 {
262 mbkcachelist *incache;
263
264 avt_logenterfunction(LOGMBKCACHE,2,"mbk_cache_add()" );
265
266 incache = mbk_cache_alloccachelist( cache );
267 cache->CURSIZE = cache->CURSIZE + mbk_cache_call_load( cache, root, elem );
268
269 incache->DATA = elem;
270 incache->PREV = NULL;
271 incache->NEXT = cache->FIRST;
272 incache->LOCKED = 0 ;
273 cache->FIRST = incache;
274 if( !incache->NEXT )
275 cache->LAST = incache;
276 else
277 incache->NEXT->PREV = incache;
278
279 mbk_cache_setmbkcachelist( cache, elem, incache );
280 cache->CURELEM++;
281 avt_logexitfunction(LOGMBKCACHE,2);
282 }
283
284 /*****************************************************************************\
285 mbk_cache_remove()
286 Fonction interne.
287 Libère un élément présent du cache.
288 \*****************************************************************************/
289 void mbk_cache_remove( mbkcache *cache, mbkcachelist *incache, void *root )
290 {
291 avt_logenterfunction(LOGMBKCACHE,2,"mbk_cache_remove()");
292 cache->CURSIZE = cache->CURSIZE - mbk_cache_call_release( cache, root, incache->DATA );
293 mbk_cache_delmbkcachelist( cache, incache->DATA );
294
295 if( incache->PREV )
296 incache->PREV->NEXT = incache->NEXT;
297 else
298 cache->FIRST = incache->NEXT;
299
300 if( incache->NEXT )
301 incache->NEXT->PREV = incache->PREV;
302 else
303 cache->LAST = incache->PREV;
304
305 mbk_cache_freecachelist( cache, incache );
306 cache->CURELEM--;
307 avt_logexitfunction(LOGMBKCACHE,2);
308 }
309
310 /*****************************************************************************\
311 mbk_cache_makeitfirst()
312 Fonction interne.
313 Fait de l'élément incache le premier élément de la liste.
314 \*****************************************************************************/
315
316 void mbk_cache_makeitfirst( mbkcache *cache, mbkcachelist *incache )
317 {
318 if( incache->PREV ) incache->PREV->NEXT = incache->NEXT ;
319
320 if( incache->NEXT )
321 incache->NEXT->PREV = incache->PREV;
322 else
323 cache->LAST = incache->PREV;
324
325 cache->FIRST->PREV = incache;
326 incache->NEXT = cache->FIRST;
327 incache->PREV = NULL;
328
329 cache->FIRST = incache;
330 }
331
332 /*****************************************************************************\
333 Appels des fonctions utilisateur.
334 Fonctions internes.
335 \*****************************************************************************/
336
337 char mbk_cache_call_iscative( mbkcache *cache, void *root, void *elem )
338 {
339 if( !cache->FN_ISACTIVE )
340 return 1;
341
342 return (cache->FN_ISACTIVE)(root, elem);
343 }
344
345 unsigned long int mbk_cache_call_load( mbkcache *cache, void *root, void *elem )
346 {
347 return (cache->FN_LOAD)(root, elem);
348 }
349
350 unsigned long int mbk_cache_call_release( mbkcache *cache, void *root, void *elem )
351 {
352 return (cache->FN_RELEASE)(root, elem);
353 }
354
355 /*****************************************************************************\
356 Accède à un mbkcachelist à partir du data.
357 Fonctions internes.
358 \*****************************************************************************/
359
360 mbkcachelist* mbk_cache_getmbkcachelist( mbkcache *cache, void *data )
361 {
362 mbkcachelist *cachelist;
363
364 cachelist = (mbkcachelist*)gethtitem( cache->INFOS, data );
365 if( cachelist == (mbkcachelist*)EMPTYHT || cachelist == (mbkcachelist*)DELETEHT )
366 return NULL;
367 return cachelist;
368 }
369
370 void mbk_cache_setmbkcachelist( mbkcache *cache, void *data, mbkcachelist *cachelist )
371 {
372 addhtitem( cache->INFOS, data, (long int)cachelist );
373 }
374
375 void mbk_cache_delmbkcachelist( mbkcache *cache, void *data )
376 {
377 delhtitem( cache->INFOS, data );
378 }
379
380 /*****************************************************************************\
381 Fonctions d'allocation.
382 Fonctions internes.
383 \*****************************************************************************/
384
385 void mbk_cache_freecachelist( mbkcache *cache, mbkcachelist *incache )
386 {
387 DelHeapItem( &(cache->HEAPCACHELIST), incache );
388 }
389
390 mbkcachelist* mbk_cache_alloccachelist( mbkcache *cache )
391 {
392 mbkcachelist *elem;
393
394 elem = (mbkcachelist*) AddHeapItem( & (cache->HEAPCACHELIST) );
395
396 elem->NEXT = NULL;
397 elem->PREV = NULL;
398 elem->DATA = NULL;
399 elem->LOCKED = 0;
400
401 return elem;
402 }
403
404 void mbk_cache_free( mbkcache *cache )
405 {
406 DeleteHeap( &( cache->HEAPCACHELIST ) );
407 delht( cache->INFOS );
408 mbkfree( cache );
409 }
410
411 mbkcache* mbk_cache_alloc( void )
412 {
413 mbkcache *cache;
414
415 cache = (mbkcache*)mbkalloc( sizeof( mbkcache ) );
416
417 cache->FIRST = NULL;
418 cache->LAST = NULL;
419 cache->CACHESIZE = 0ul;
420 cache->CURSIZE = 0ul;
421 cache->INFOS = NULL;
422 cache->FN_ISACTIVE = NULL;
423 cache->FN_LOAD = NULL;
424 cache->FN_RELEASE = NULL;
425 cache->MAXELEM = 0;
426 cache->CURELEM = 0;
427 CreateHeap( sizeof( mbkcachelist ),
428 CACHE_ALLOC_BLOCLIST,
429 &(cache->HEAPCACHELIST)
430 );
431
432 return cache;
433 }
434
435 /*****************************************************************************\
436 Fonctions permettant de limiter le nombre maximum de fichiers ouverts.
437 \*****************************************************************************/
438
439 /*****************************************************************************\
440 mbk_cache_set_file()
441 Fonctions utilisateur.
442 Renvoie un index associé au fichier passé en paramètre.
443 \*****************************************************************************/
444 int mbk_cache_set_file( FILE *fd, char *filename, char *extension )
445 {
446 cache_file *elem ;
447
448 if( !FILE_CACHE ) {
449 FILE_CACHE = mbk_cache_create( NULL,
450 (unsigned long int (*)(void*,void*))mbk_cache_file_open,
451 (unsigned long int (*)(void*,void*))mbk_cache_file_close,
452 MBK_MAX_CACHE
453 );
454 CreateHeap( sizeof( cache_file ), 16, &FILE_CACHE_HEAP );
455 FILE_CACHE_HT = addht( 16 );
456 }
457
458 elem = (cache_file*) AddHeapItem( &FILE_CACHE_HEAP );
459 elem->IFILE = ++FILE_CACHE_INDEX ;
460 elem->PFILE = fd ;
461 elem->BASENAME = mbkstrdup( filename );
462 elem->EXTENSION = mbkstrdup( extension );
463 elem->SIZE = mbk_getfileacces( fd );
464 addhtitem( FILE_CACHE_HT, (void*)((long)elem->IFILE), (long)elem );
465
466 mbk_cache_refresh( FILE_CACHE, NULL, elem );
467
468 return elem->IFILE ;
469 }
470
471 /*****************************************************************************\
472 mbk_cache_get_file()
473 Fonctions utilisateur.
474 Renvoie le fichier associé à l'index passé en paramètre
475 \*****************************************************************************/
476 FILE* mbk_cache_get_file( int id )
477 {
478 cache_file *elem ;
479
480 if( !FILE_CACHE )
481 return NULL ;
482
483 elem = (cache_file*)gethtitem( FILE_CACHE_HT, (void*)((long)id));
484 if( (long)elem == EMPTYHT || (long)elem == DELETEHT )
485 return NULL ;
486
487 mbk_cache_refresh( FILE_CACHE, NULL, elem );
488
489 return elem->PFILE ;
490 }
491
492 /*****************************************************************************\
493 mbk_cache_clear_file()
494 Fonctions utilisateur.
495 Libère les informations associées à l'index passé en paramètre. Si le fichier
496 est ouvert, il est fermé.
497 \*****************************************************************************/
498 void mbk_cache_clear_file( int id )
499 {
500 cache_file *elem ;
501
502 if( !FILE_CACHE )
503 return ;
504
505 elem = (cache_file*)gethtitem( FILE_CACHE_HT, (void*)((long)id));
506 if( (long)elem == EMPTYHT || (long)elem == DELETEHT )
507 return ;
508
509 mbk_cache_release( FILE_CACHE, NULL, elem );
510 delhtitem( FILE_CACHE_HT, (void*)elem );
511 mbkfree( elem->BASENAME );
512 mbkfree( elem->EXTENSION );
513 DelHeapItem( &FILE_CACHE_HEAP, elem );
514 }
515
516 /*****************************************************************************\
517 mbk_cache_file_open()
518 Fonction interne.
519 Fonction de refresh : elle est appellée pour ouvrir un fichier.
520 \*****************************************************************************/
521 unsigned long int mbk_cache_file_open( void *root, cache_file *elem )
522 {
523 if( !elem->PFILE ) {
524 elem->PFILE = mbkfopen_ext( elem->BASENAME,
525 elem->EXTENSION,
526 "r",
527 elem->SIZE,
528 1
529 );
530 if( !elem->PFILE ) {
531 avt_errmsg (MBK_ERRMSG, "019", AVT_FATAL,elem->BASENAME );
532 }
533 }
534 root = NULL ;
535 return 1 ;
536 }
537
538 /*****************************************************************************\
539 mbk_cache_file_close()
540 Fonction interne.
541 Fonction de libération : elle est appellée pour fermer un fichier.
542 \*****************************************************************************/
543 unsigned long int mbk_cache_file_close( void *root, cache_file *elem )
544 {
545 if( elem->PFILE ) {
546 fclose( elem->PFILE );
547 elem->PFILE = NULL ;
548 }
549 root = NULL ;
550 return 1 ;
551 }