1 /*
2 Copyright (c) 1991-1999 Thomas T. Wetmore IV
3
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use, copy,
8 modify, merge, publish, distribute, sublicense, and/or sell copies
9 of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 /*=============================================================
25 * keytonod.c -- Cache for lifelines custom btree database
26 * Copyright(c) 1992-94 by T.T. Wetmore IV; all rights reserved
27 * 2.3.4 - 24 Jun 93 2.3.5 - 01 Sep 93
28 * 3.0.0 - 08 May 94 3.0.2 - 23 Dec 94
29 * 3.0.3 - 16 Jul 95
30 *===========================================================*/
31
32 #include "llstdlib.h"
33 #include "table.h"
34 #include "translat.h"
35 #include "gedcom.h"
36 #include "gedcomi.h"
37 #include "cache.h"
38 #include "liflines.h"
39 #include "feedback.h"
40 #include "zstr.h"
41
42 /*********************************************
43 * global variables (no header)
44 *********************************************/
45
46 char badkeylist[100] = "";
47 int listbadkeys = 0;
48
49
50
51 /*===============================
52 * CACHEEL -- Cache element type.
53 *=============================*/
54 /* typedef struct tag_cacheel *CACHEEL; */
55 struct tag_cacheel {
56 CNSTRING c_magic; /* points to cel_magic */
57 NODE c_node; /* root node */
58 CACHEEL c_prev; /* previous el */
59 CACHEEL c_next; /* next el */
60 STRING c_key; /* record key */
61 INT c_lock; /* lock count (includes report locks) */
62 INT c_rptlock; /* report lock count */
63 RECORD c_record;
64 };
65 #define cnode(e) ((e)->c_node)
66 #define cprev(e) ((e)->c_prev)
67 #define cnext(e) ((e)->c_next)
68 #define ckey(e) ((e)->c_key)
69 #define cclock(e) ((e)->c_lock)
70 #define ccrptlock(e) ((e)->c_rptlock)
71 #define crecord(e) ((e)->c_record)
72
73 /*==============================
74 * CACHE -- Internal cache type.
75 *============================*/
76 typedef struct {
77 char c_name[5];
78 TABLE c_data; /* table of keys */
79 CACHEEL c_firstdir; /* first direct */
80 CACHEEL c_lastdir; /* last direct */
81 CACHEEL c_array; /* big array of cacheels, all alloc'd in a block */
82 CACHEEL c_free; /* root of free list */
83 INT c_maxdir; /* max in direct */
84 INT c_sizedir; /* cur in direct */
85 } *CACHE;
86 #define cacname(c) ((c)->c_name)
87 #define cacdata(c) ((c)->c_data)
88 #define cacfirstdir(c) ((c)->c_firstdir)
89 #define caclastdir(c) ((c)->c_lastdir)
90 #define cacarray(e) ((e)->c_array)
91 #define cacfree(e) ((e)->c_free)
92 #define cacmaxdir(c) ((c)->c_maxdir)
93 #define cacsizedir(c) ((c)->c_sizedir)
94
95
96 /*********************************************
97 * local function prototypes
98 *********************************************/
99
100 /* static void add_record_to_direct(CACHE cache, RECORD rec, STRING key); */
101 static void cache_get_lock_counts(CACHE ca, INT * locks);
102 static CACHE create_cache(STRING name, INT dirsize);
103 static void delete_cache(CACHE * pcache);
104 static void ensure_cel_has_record(CACHEEL cel);
105 static ZSTR get_cache_stats(CACHE ca);
106 static CACHEEL get_free_cacheel(CACHE cache);
107 static void init_cel(CACHEEL cel);
108 static CACHEEL key_to_cacheel(CACHE cache, CNSTRING key, STRING tag, INT reportmode);
109 static CACHEEL key_to_even_cacheel(CNSTRING key);
110 static NODE key_typed_to_node(CACHE cache, CNSTRING key, STRING tag);
111 static RECORD key_to_record_impl(CNSTRING key, INT reportmode);
112 static RECORD key_typed_to_record(CACHE cache, CNSTRING key, STRING tag);
113 static CACHEEL key_to_othr_cacheel(CNSTRING key);
114 static CACHEEL key_to_sour_cacheel(CNSTRING key);
115 static CACHEEL node_to_cache(CACHE, NODE);
116 static void put_node_in_cache(CACHE cache, CACHEEL cel, NODE node, STRING key);
117 static void remove_cel_from_cache(CACHE cache, CACHEEL cel, BOOLEAN delcache);
118 static NODE qkey_to_node(CACHE cache, CNSTRING key, STRING tag);
119 static RECORD qkey_typed_to_record(CACHE cache, CNSTRING key, STRING tag);
120 /* static CACHEEL qkey_to_typed_cacheel(STRING key); */
121 static void remove_from_cache(CACHE, CNSTRING);
122
123
124 INT csz_indi = 200; /* cache size for indi */
125 INT csz_fam = 200; /* cache size for fam */
126 INT csz_sour = 200; /* cache size for sour */
127 INT csz_even = 200; /* cache size for even */
128 INT csz_othr = 200; /* cache size for othr */
129
130 /*********************************************
131 * local variables
132 *********************************************/
133
134 static CACHE indicache, famcache, evencache, sourcache, othrcache;
135
136 static CNSTRING cel_magic = "CEL_MAGIC"; /* fixed pointer to identify cel */
137
138 /* keybuf circular list of last 10 keys we looked up in cache
139 * kept for printing debug messages in crash log
140 */
141 static char keybuf[10][32] = { "", "", "", "", "", "", "", "", "", ""};
142 static int keyidx = 0;
143
144 /*********************************************
145 * local function definitions
146 * body of module
147 *********************************************/
148
149 /*================================================
150 * node_to_record -- Find record from node
151 *==============================================*/
152 RECORD
node_to_record(NODE node)153 node_to_record (NODE node)
154 {
155 STRING key = rmvat(nxref(node));
156 return key_to_record(key);
157 }
158 /*================================================
159 * keynum_to_indi -- Convert a numeric key to an indi node
160 * assert if failed (ie, no indi with that number)
161 *==============================================*/
162 NODE
keynum_to_indi(int keynum)163 keynum_to_indi (int keynum)
164 {
165 char keystr[20];
166 sprintf(keystr,"I%d",keynum);
167 return key_to_indi(keystr);
168 }
169 RECORD
keynum_to_irecord(int keynum)170 keynum_to_irecord (int keynum)
171 {
172 char keystr[20];
173 sprintf(keystr,"I%d",keynum);
174 return key_to_irecord(keystr);
175 }
176 /*=========================================================
177 * qkeynum_to_indi -- Convert a numeric key to an indi node
178 * report mode - it returns NULL if failed
179 * (ie, no indi with that number)
180 *=======================================================*/
181 NODE
qkeynum_to_indi(int keynum)182 qkeynum_to_indi (int keynum)
183 {
184 char keystr[20];
185 sprintf(keystr,"I%d",keynum);
186 return qkey_to_indi(keystr);
187 }
188 /*================================================
189 * keynum_to_fam -- Convert a numeric key to a fam node
190 * assert if failed (ie, no fam with that number)
191 *==============================================*/
192 NODE
keynum_to_fam(int keynum)193 keynum_to_fam (int keynum)
194 {
195 char keystr[20];
196 sprintf(keystr,"F%d",keynum);
197 return key_to_fam(keystr);
198 }
199 RECORD
keynum_to_frecord(int keynum)200 keynum_to_frecord (int keynum)
201 {
202 char keystr[20];
203 sprintf(keystr,"F%d",keynum);
204 return key_to_frecord(keystr);
205 }
206 /*======================================================
207 * qkeynum_to_frecord -- Convert a numeric key to a fam record
208 * report mode - it returns NULL if failed
209 * (ie, no fam with that number)
210 *====================================================*/
211 RECORD
qkeynum_to_frecord(int keynum)212 qkeynum_to_frecord (int keynum)
213 {
214 char keystr[20];
215 sprintf(keystr,"F%d",keynum);
216 return qkey_to_frecord(keystr);
217 }
218 /*================================================
219 * keynum_to_sour -- Convert a numeric key to a sour node
220 * assert if failed (ie, no sour with that number)
221 *==============================================*/
222 NODE
keynum_to_sour(int keynum)223 keynum_to_sour (int keynum)
224 {
225 return nztop(keynum_to_srecord(keynum));
226 }
227 RECORD
keynum_to_srecord(int keynum)228 keynum_to_srecord (int keynum)
229 {
230 char keystr[20];
231 sprintf(keystr,"S%d",keynum);
232 return key_to_srecord(keystr);
233 }
234 /*================================================
235 * keynum_to_even -- Convert a numeric key to a even node
236 * assert if failed (ie, no sour with that number)
237 *==============================================*/
238 NODE
keynum_to_even(int keynum)239 keynum_to_even (int keynum)
240 {
241 return nztop(keynum_to_erecord(keynum));
242 }
243 RECORD
keynum_to_erecord(int keynum)244 keynum_to_erecord (int keynum)
245 {
246 char keystr[MAXKEYWIDTH+1];
247 sprintf(keystr,"E%d",keynum);
248 return key_to_erecord(keystr);
249 }
250 /*================================================
251 * keynum_to_othr -- Convert a numeric key to an other node
252 * assert if failed (ie, no sour with that number)
253 *==============================================*/
254 NODE
keynum_to_othr(int keynum)255 keynum_to_othr (int keynum)
256 {
257 char keystr[20];
258 sprintf(keystr,"X%d",keynum);
259 return key_to_othr(keystr);
260 }
261 RECORD
keynum_to_orecord(int keynum)262 keynum_to_orecord (int keynum)
263 {
264 char keystr[20];
265 sprintf(keystr,"X%d",keynum);
266 return key_to_orecord(keystr);
267 }
268 /*=====================================
269 * keynum_to_node -- Convert keynum to node
270 *===================================*/
271 NODE
keynum_to_node(char ntype,int keynum)272 keynum_to_node (char ntype, int keynum)
273 {
274 switch(ntype) {
275 case 'I': return keynum_to_indi(keynum);
276 case 'F': return keynum_to_fam(keynum);
277 case 'S': return keynum_to_sour(keynum);
278 case 'E': return keynum_to_even(keynum);
279 case 'X': return keynum_to_othr(keynum);
280 }
281 ASSERT(0);
282 return 0;
283 }
284 RECORD
keynum_to_record(char ntype,int keynum)285 keynum_to_record (char ntype, int keynum)
286 {
287 switch(ntype) {
288 case 'I': return keynum_to_irecord(keynum);
289 case 'F': return keynum_to_frecord(keynum);
290 case 'S': return keynum_to_srecord(keynum);
291 case 'E': return keynum_to_erecord(keynum);
292 case 'X': return keynum_to_orecord(keynum);
293 }
294 ASSERT(0);
295 return 0;
296 }
297 /*=====================================
298 * key_to_type -- Convert key to node
299 * TO DO - should become obsoleted by key_to_record
300 *===================================*/
301 NODE
key_to_type(CNSTRING key,INT reportmode)302 key_to_type (CNSTRING key, INT reportmode)
303 {
304 RECORD rec = key_to_record_impl(key, reportmode);
305 NODE node = nztop(rec);
306 release_record(rec); /* avoiding leaking reference */
307 return node;
308 }
309 /*=====================================
310 * qkey_to_type -- Convert key to node
311 * quiet -- that is, returns NULL if record not in database
312 *===================================*/
313 NODE
qkey_to_type(CNSTRING key)314 qkey_to_type (CNSTRING key)
315 {
316 return key_to_type(key, TRUE);
317 }
318 /*=====================================
319 * key_to_record_impl -- Convert key (any type) to RECORD
320 * returns addref'd record
321 *===================================*/
322 static RECORD
key_to_record_impl(CNSTRING key,INT reportmode)323 key_to_record_impl (CNSTRING key, INT reportmode)
324 {
325 switch(key[0])
326 {
327 case 'I': return reportmode ? qkey_to_irecord(key) : key_to_irecord(key);
328 case 'F': return reportmode ? qkey_to_frecord(key) : key_to_frecord(key);
329 case 'S': return reportmode ? qkey_to_srecord(key) : key_to_srecord(key);
330 case 'E': return reportmode ? qkey_to_erecord(key) : key_to_erecord(key);
331 }
332 return reportmode ? qkey_to_orecord(key) : key_to_orecord(key);
333 }
334 /*=====================================
335 * key_to_record -- Convert key (any type) to RECORD
336 * ASSERTS if record not found in database
337 * returns addref'd record
338 *===================================*/
339 RECORD
key_to_record(CNSTRING key)340 key_to_record (CNSTRING key)
341 {
342 return key_to_record_impl(key, FALSE);
343 }
344 /*=====================================
345 * qkey_to_record -- Convert key (any type) to RECORD
346 * quiet -- that is, returns NULL if record not in database
347 * returns addref'd record
348 *===================================*/
349 RECORD
qkey_to_record(CNSTRING key)350 qkey_to_record (CNSTRING key)
351 {
352 return key_to_record_impl(key, TRUE);
353 }
354 /*=====================================
355 * key_to_??? -- Convert key to person
356 * (asserts if failure)
357 * 5 symmetric versions
358 * TO DO - should become obsoleted by key_to_???0
359 *===================================*/
360 NODE
key_to_indi(CNSTRING key)361 key_to_indi (CNSTRING key)
362 {
363 return key_typed_to_node(indicache, key, "INDI");
364 }
key_to_fam(CNSTRING key)365 NODE key_to_fam (CNSTRING key)
366 {
367 return key_typed_to_node(famcache, key, "FAM");
368 }
key_to_even(CNSTRING key)369 NODE key_to_even (CNSTRING key)
370 {
371 return key_typed_to_node(evencache, key, "EVEN");
372 }
key_to_sour(CNSTRING key)373 NODE key_to_sour (CNSTRING key)
374 {
375 return key_typed_to_node(sourcache, key, "SOUR");
376 }
key_to_othr(CNSTRING key)377 NODE key_to_othr (CNSTRING key)
378 {
379 return key_typed_to_node(othrcache, key, NULL);
380 }
381 /*=====================================
382 * key_to_???0 -- Convert key to person
383 * (asserts if failure)
384 * 5 symmetric versions
385 * returns addref'd record
386 *===================================*/
key_to_irecord(CNSTRING key)387 RECORD key_to_irecord (CNSTRING key)
388 {
389 return key_typed_to_record(indicache, key, "INDI");
390 }
key_to_frecord(CNSTRING key)391 RECORD key_to_frecord (CNSTRING key)
392 {
393 return key_typed_to_record(famcache, key, "FAM");
394 }
key_to_erecord(CNSTRING key)395 RECORD key_to_erecord (CNSTRING key)
396 {
397 return key_typed_to_record(evencache, key, "EVEN");
398 }
key_to_srecord(CNSTRING key)399 RECORD key_to_srecord (CNSTRING key)
400 {
401 return key_typed_to_record(sourcache, key, "SOUR");
402 }
key_to_orecord(CNSTRING key)403 RECORD key_to_orecord (CNSTRING key)
404 {
405 return key_typed_to_record(othrcache, key, NULL);
406 }
407 /*========================================
408 * qkey_to_??? -- Convert key to node type
409 * report mode (returns NULL if failure)
410 * 5 symmetric versions
411 * TO DO - should become obsoleted by key_to_???0
412 *======================================*/
qkey_to_indi(CNSTRING key)413 NODE qkey_to_indi (CNSTRING key)
414 {
415 return qkey_to_node(indicache, key, "INDI");
416 }
qkey_to_fam(CNSTRING key)417 NODE qkey_to_fam (CNSTRING key)
418 {
419 return qkey_to_node(famcache, key, "FAM");
420 }
qkey_to_even(CNSTRING key)421 NODE qkey_to_even (CNSTRING key)
422 {
423 return qkey_to_node(evencache, key, "EVEN");
424 }
qkey_to_sour(CNSTRING key)425 NODE qkey_to_sour (CNSTRING key)
426 {
427 return qkey_to_node(sourcache, key, "SOUR");
428 }
qkey_to_othr(CNSTRING key)429 NODE qkey_to_othr (CNSTRING key)
430 {
431 return qkey_to_node(othrcache, key, NULL);
432 }
433 /*========================================
434 * qkey_to_???0 -- Convert key to node type
435 * report mode (returns NULL if failure)
436 * 5 symmetric versions
437 * All return addref'd records
438 *======================================*/
qkey_to_irecord(CNSTRING key)439 RECORD qkey_to_irecord (CNSTRING key)
440 {
441 return qkey_typed_to_record(indicache, key, "INDI");
442 }
qkey_to_frecord(CNSTRING key)443 RECORD qkey_to_frecord (CNSTRING key)
444 {
445 return qkey_typed_to_record(famcache, key, "FAM");
446 }
qkey_to_erecord(CNSTRING key)447 RECORD qkey_to_erecord (CNSTRING key)
448 {
449 return qkey_typed_to_record(evencache, key, "EVEN");
450 }
qkey_to_srecord(CNSTRING key)451 RECORD qkey_to_srecord (CNSTRING key)
452 {
453 return qkey_typed_to_record(sourcache, key, "SOUR");
454 }
qkey_to_orecord(CNSTRING key)455 RECORD qkey_to_orecord (CNSTRING key)
456 {
457 return qkey_typed_to_record(othrcache, key, NULL);
458 }
459 /*=====================================================
460 * key_to_unknown_cacheel -- Convert any key to cacheel
461 *===================================================*/
462 CACHEEL
key_to_unknown_cacheel(STRING key)463 key_to_unknown_cacheel (STRING key)
464 {
465 switch(key[0]) {
466 case 'I': return key_to_indi_cacheel(key);
467 case 'F': return key_to_fam_cacheel(key);
468 case 'S': return key_to_sour_cacheel(key);
469 case 'E': return key_to_even_cacheel(key);
470 default: return key_to_othr_cacheel(key);
471 }
472 }
473 /*=====================================================
474 * key_to_indi_cacheel -- Convert key to person cacheel
475 *===================================================*/
476 CACHEEL
key_to_indi_cacheel(STRING key)477 key_to_indi_cacheel (STRING key)
478 {
479 return key_to_cacheel(indicache, key, "INDI", FALSE);
480 }
481 /*====================================================
482 * key_to_fam_cacheel -- Convert key to family_cacheel
483 *==================================================*/
484 CACHEEL
key_to_fam_cacheel(STRING key)485 key_to_fam_cacheel (STRING key)
486 {
487 return key_to_cacheel(famcache, key, "FAM", FALSE);
488 }
489 /*=====================================================
490 * key_to_sour_cacheel -- Convert key to source_cacheel
491 *===================================================*/
492 static CACHEEL
key_to_sour_cacheel(CNSTRING key)493 key_to_sour_cacheel (CNSTRING key)
494 {
495 return key_to_cacheel(sourcache, key, "SOUR", FALSE);
496 }
497 /*====================================================
498 * key_to_even_cacheel -- Convert key to event_cacheel
499 *==================================================*/
500 static CACHEEL
key_to_even_cacheel(CNSTRING key)501 key_to_even_cacheel (CNSTRING key)
502 {
503 return key_to_cacheel(evencache, key, "EVEN", FALSE);
504 }
505 /*====================================================
506 * key_to_othr_cacheel -- Convert key to other_cacheel
507 *==================================================*/
508 static CACHEEL
key_to_othr_cacheel(CNSTRING key)509 key_to_othr_cacheel (CNSTRING key)
510 {
511 return key_to_cacheel(othrcache, key, NULL, FALSE);
512 }
513 /*======================================
514 * init_caches -- Create and init caches
515 *====================================*/
516 void
init_caches(void)517 init_caches (void)
518 {
519 indicache = create_cache("INDI", csz_indi);
520 famcache = create_cache("FAM", csz_fam);
521 evencache = create_cache("EVEN", csz_even);
522 sourcache = create_cache("SOUR", csz_sour);
523 othrcache = create_cache("OTHR", csz_othr);
524 }
525 /*======================================
526 * free_caches -- Release cache memory
527 * Created: 2003-02-02 (Perry Rapp)
528 *====================================*/
529 void
free_caches(void)530 free_caches (void)
531 {
532 delete_cache(&indicache);
533 delete_cache(&famcache);
534 delete_cache(&evencache);
535 delete_cache(&sourcache);
536 delete_cache(&othrcache);
537 }
538 /*=============================
539 * create_cache -- Create cache
540 *===========================*/
541 static CACHE
create_cache(STRING name,INT dirsize)542 create_cache (STRING name, INT dirsize)
543 {
544 CACHE cache;
545 INT i;
546 if (dirsize < 1) dirsize = 1;
547 cache = (CACHE) stdalloc(sizeof(*cache));
548 memset(cache, 0, sizeof(*cache));
549 llstrncpy(cacname(cache), name, sizeof(cacname(cache)), uu8);
550 /*
551 It would be nice to set the table hash size larger for large
552 caches, but right now (2003-10-08), tables do not expose a
553 method to set their hash size.
554 */
555 cacdata(cache) = create_table_vptr(); /* pointers to cache elements, owned by cacarray */
556 cacfirstdir(cache) = caclastdir(cache) = NULL;
557 cacsizedir(cache) = 0;
558 cacmaxdir(cache) = dirsize;
559 /* Allocate all the cache elements in a big block */
560 cacarray(cache) = (CACHEEL) stdalloc(cacmaxdir(cache) * sizeof(cacarray(cache)[0]));
561 /* Link all the elements together on the free list */
562 for (i=0; i<cacmaxdir(cache); ++i) {
563 CACHEEL cel = &cacarray(cache)[i];
564 CACHEEL celnext = cacfree(cache);
565 init_cel(cel);
566 if (celnext) {
567 cnext(cel) = celnext;
568 cprev(celnext) = cel;
569 }
570 cacfree(cache) = cel;
571 }
572 return cache;
573 }
574 /*=============================
575 * delete_cache -- Delete cache entirely
576 *===========================*/
577 static void
delete_cache(CACHE * pcache)578 delete_cache (CACHE * pcache)
579 {
580 INT num=0;
581 CACHE cache = *pcache;
582 CACHEEL frst=0;
583 if (!cache) return;
584 /* Loop through all cache elements, freeing each */
585 while ((frst = cacfirstdir(cache)) != 0) {
586 BOOLEAN delcache = TRUE;
587 remove_cel_from_cache(cache, frst, delcache);
588 }
589 /* TODO: Need to delete cache elements on free list */
590 num = get_table_count(cacdata(cache));
591 ASSERT(num == 0);
592 destroy_table(cacdata(cache));
593 stdfree(cacarray(cache));
594 stdfree(cache);
595 *pcache = 0;
596 }
597 /*=============================
598 * init_cel -- Initialize new cacheel
599 *===========================*/
600 static void
init_cel(CACHEEL cel)601 init_cel (CACHEEL cel)
602 {
603 memset(cel, 0, sizeof(*cel));
604 cel->c_magic = cel_magic;
605 }
606 /*=================================================
607 * remove_direct -- Unlink CACHEEL from direct list
608 *===============================================*/
609 static void
remove_direct(CACHE cache,CACHEEL cel)610 remove_direct (CACHE cache, CACHEEL cel)
611 {
612 CACHEEL prev = cprev(cel);
613 CACHEEL next = cnext(cel);
614 ASSERT(cache);
615 ASSERT(cel);
616 if (prev) cnext(prev) = next;
617 if (next) cprev(next) = prev;
618 if (!prev) cacfirstdir(cache) = next;
619 if (!next) caclastdir(cache) = prev;
620 cacsizedir(cache)--;
621 }
622 /*===========================================================
623 * first_direct -- Make unlinked CACHEEL first in direct list
624 *=========================================================*/
625 static void
first_direct(CACHE cache,CACHEEL cel)626 first_direct (CACHE cache, CACHEEL cel)
627 {
628 CACHEEL frst = cacfirstdir(cache);
629 ASSERT(cache);
630 ASSERT(cel);
631 cacsizedir(cache)++;
632 cprev(cel) = NULL;
633 cnext(cel) = frst;
634 if (frst) cprev(frst) = cel;
635 if (!frst) caclastdir(cache) = cel;
636 cacfirstdir(cache) = cel;
637 }
638 /*============================================================
639 * direct_to_first -- Make direct CACHEEL first in direct list
640 *==========================================================*/
641 static void
direct_to_first(CACHE cache,CACHEEL cel)642 direct_to_first (CACHE cache, CACHEEL cel)
643 {
644 ASSERT(cache);
645 ASSERT(cel);
646 if (cel == cacfirstdir(cache)) return;
647 remove_direct(cache, cel);
648 first_direct(cache, cel);
649 }
650 /*========================================================
651 * add_to_direct -- Add new CACHEEL to direct part of cache
652 * reportmode: if True, then return NULL rather than aborting
653 * if there is no record. Also return NULL for deleted
654 * records (of length less than 6???)
655 * cache: [IN] which cache to which to add
656 * key: [IN] key of record to be added
657 * reportmode: [IN] if non-zero, failures should be silent
658 * Only called if record is not already in cache (caller's responsibility)
659 *======================================================*/
660 static CACHEEL
add_to_direct(CACHE cache,CNSTRING key,INT reportmode)661 add_to_direct (CACHE cache, CNSTRING key, INT reportmode)
662 {
663 STRING rawrec=0;
664 INT len=0;
665 CACHEEL cel=0;
666 RECORD rec=0;
667 int i, j;
668
669 ASSERT(cache);
670 ASSERT(key);
671 rec = NULL;
672 if ((rawrec = retrieve_raw_record(key, &len)))
673 /* 2003-11-22, we should use string_to_node here */
674 rec = string_to_record(rawrec, key, len);
675 if (!rec)
676 {
677 ZSTR zstr=zs_newn(256);
678 if(listbadkeys) {
679 if(strlen(badkeylist) < 80 - strlen(key) - 2) {
680 if (badkeylist[0])
681 strcat(badkeylist, ",");
682 strcat(badkeylist, key);
683 }
684 return(NULL);
685 }
686 if (reportmode) return(NULL);
687 crashlogn(_("Database error caused by reference to nonexisting key <%s>."), (char *)key);
688 crashlogn(_("It might be possible to fix this with btedit."));
689 zs_sets(zstr, _("Neighboring keys include:"));
690 for(i = 0; i < 10; i++)
691 {
692 j = keyidx + i;
693 if(j >= 10) j -= 10;
694 if (keybuf[j][0]) {
695 zs_appc(zstr, ' ');
696 zs_apps(zstr, keybuf[j]);
697 }
698 }
699 crashlogn(zs_str(zstr));
700 zs_free(&zstr);
701 /* deliberately fall through to let ASSERT(rec) fail */
702 }
703 ASSERT(rec);
704 /* record was just loaded, nztop should not need to load it */
705 cel = node_to_cache(cache, nztop(rec));
706 ASSERT(!crecord(cel));
707 /* node_to_cache did a first_direct call, so record in cache */
708 record_set_cel(rec, cel);
709 /* our new rec above has one reference, which is held by cel */
710 crecord(cel) = rec;
711 stdfree(rawrec);
712 ASSERT(cel->c_magic == cel_magic);
713 return cel;
714 }
715 /*======================================================
716 * key_to_cacheel -- Return CACHEEL corresponding to key
717 *====================================================*/
718 static CACHEEL
key_to_cacheel(CACHE cache,CNSTRING key,STRING tag,INT reportmode)719 key_to_cacheel (CACHE cache, CNSTRING key, STRING tag, INT reportmode)
720 {
721 CACHEEL cel;
722
723 strncpy(keybuf[keyidx], (key ? (char *)key : "NULL"), 31);
724 keybuf[keyidx][31] = '\0';
725 keyidx++;
726 if(keyidx >= 10) keyidx = 0;
727 if ((cel = (CACHEEL) valueof_ptr(cacdata(cache), key))) {
728 ASSERT(cnode(cel));
729 ASSERT(cel->c_magic == cel_magic);
730 direct_to_first(cache, cel);
731 if (tag) {
732 ASSERT(eqstr(tag, ntag(cnode(cel))));
733 ASSERT(crecord(cel));
734 ASSERT(eqstr(key, nzkey(crecord(cel))));
735 }
736 return cel;
737 }
738 cel = add_to_direct(cache, key, reportmode);
739 if (cel && tag) {
740 ASSERT(eqstr(tag, ntag(cnode(cel))));
741 ASSERT(crecord(cel));
742 ASSERT(eqstr(key, nzkey(crecord(cel))));
743 }
744 return cel;
745 }
746 /*===============================================================
747 * key_to_node -- Return tree from key; add to cache if not there
748 * asserts if failure
749 * TO DO - should become obsoleted by key_typed_to_record
750 *=============================================================*/
751 static NODE
key_typed_to_node(CACHE cache,CNSTRING key,STRING tag)752 key_typed_to_node (CACHE cache, CNSTRING key, STRING tag)
753 {
754 CACHEEL cel;
755 ASSERT(cache);
756 ASSERT(key);
757 if (!(cel = key_to_cacheel(cache, key, tag, FALSE)))
758 return NULL;
759 return cnode(cel);
760 }
761 /*===============================================================
762 * key_typed_to_record -- Return record from key; add to cache if not there
763 * asserts if failure
764 * returns addref'd record
765 *=============================================================*/
766 static RECORD
key_typed_to_record(CACHE cache,CNSTRING key,STRING tag)767 key_typed_to_record (CACHE cache, CNSTRING key, STRING tag)
768 {
769 CACHEEL cel;
770 ASSERT(cache);
771 ASSERT(key);
772 if (!(cel = key_to_cacheel(cache, key, tag, FALSE)))
773 return NULL;
774 return get_record_for_cel(cel);
775 }
776 /*===================================
777 * get_record_for_cel -- get or create new record from cacheel
778 * returns addref'd record
779 *=================================*/
780 RECORD
get_record_for_cel(CACHEEL cel)781 get_record_for_cel (CACHEEL cel)
782 {
783 RECORD rec=0;
784 NODE node=0;
785 STRING key=0;
786
787 ASSERT(cel);
788 if (crecord(cel)) {
789 rec = crecord(cel);
790 addref_record(rec);
791 return rec;
792 }
793 ASSERT(cnode(cel));
794 node = cnode(cel);
795 ASSERT(nxref(node));
796
797 key = ckey(cel);
798
799 rec = make_new_record_with_info(key, cel);
800 record_set_cel(rec, cel);
801 crecord(cel) = rec;
802 key = node_to_key(node);
803
804 set_record_key_info(rec, key);
805 addref_record(rec);
806 return rec;
807 }
808 /*===============================================================
809 * qkey_to_node -- Return tree from key; add to cache if not there
810 * report mode - returns NULL if failure
811 * TO DO - should become obsoleted by qkey_typed_to_record
812 *=============================================================*/
813 static NODE
qkey_to_node(CACHE cache,CNSTRING key,STRING tag)814 qkey_to_node (CACHE cache, CNSTRING key, STRING tag)
815 {
816 CACHEEL cel;
817 ASSERT(cache);
818 if (!key) return NULL;
819 if (!(cel = key_to_cacheel(cache, key, tag, TRUE)))
820 return NULL;
821 return cnode(cel);
822 }
823 /*===============================================================
824 * qkey_typed_to_record -- Return record from key; add to cache if not there
825 * report mode - returns NULL if failure
826 * returns addref'd record
827 *=============================================================*/
828 static RECORD
qkey_typed_to_record(CACHE cache,CNSTRING key,STRING tag)829 qkey_typed_to_record (CACHE cache, CNSTRING key, STRING tag)
830 {
831 CACHEEL cel=0;
832 RECORD rec=0;
833
834 ASSERT(cache);
835 ASSERT(key);
836 if (!(cel = key_to_cacheel(cache, key, tag, TRUE)))
837 return NULL;
838 rec = get_record_for_cel(cel);
839 return rec;
840 }
841 /*======================================
842 * lock_cache -- Lock CACHEEL into direct cache
843 *====================================*/
844 void
lock_cache(CACHEEL cel)845 lock_cache (CACHEEL cel)
846 {
847 ASSERT(cnode(cel)); /* must be in direct */
848 ++cclock(cel);
849 ASSERT(cclock(cel)>0);
850 }
851 /*======================================
852 * lockrpt_cache -- Lock CACHEEL into direct cache (for report program)
853 *====================================*/
854 void
lockrpt_cache(CACHEEL cel)855 lockrpt_cache (CACHEEL cel)
856 {
857 ASSERT(cnode(cel)); /* must be in direct */
858 /* put real lock on to actually lock it */
859 ++cclock(cel);
860 /* put report lock on, so we can free orphaned report locks */
861 ++ccrptlock(cel);
862 ASSERT(cclock(cel)>0);
863 }
864 /*======================================
865 * cel_rptlocks -- return report lock count for specified cache element
866 *====================================*/
867 INT
cel_rptlocks(CACHEEL cel)868 cel_rptlocks (CACHEEL cel)
869 {
870 return ccrptlock(cel);
871 }
872 /*======================================
873 * lock_record_in_cache -- Load record into cache & lock it
874 *====================================*/
875 void
lock_record_in_cache(RECORD rec)876 lock_record_in_cache (RECORD rec)
877 {
878 NODE node=0;
879 CACHEEL cel=0;
880 ASSERT(rec);
881 node = nztop(rec); /* force record to be loaded in cache */
882 cel = nzcel(rec);
883 ++cclock(cel);
884 ASSERT(cclock(cel) > 0);
885 }
886 /*==========================================
887 * unlock_cache -- Unlock CACHEEL from direct cache
888 *========================================*/
889 void
unlock_cache(CACHEEL cel)890 unlock_cache (CACHEEL cel)
891 {
892 ASSERT(cclock(cel) > 0);
893 ASSERT(cnode(cel));
894 --cclock(cel);
895 }
896 /*==========================================
897 * unlockrpt_cache -- Unlock CACHEEL from direct cache (report program call)
898 *========================================*/
899 void
unlockrpt_cache(CACHEEL cel)900 unlockrpt_cache (CACHEEL cel)
901 {
902 ASSERT(cclock(cel) > 0);
903 ASSERT(ccrptlock(cel) > 0);
904 ASSERT(cnode(cel));
905 --cclock(cel);
906 --ccrptlock(cel);
907 }
908 /*======================================
909 * unlock_record_from_cache -- Remove lock on record
910 *====================================*/
911 void
unlock_record_from_cache(RECORD rec)912 unlock_record_from_cache (RECORD rec)
913 {
914 CACHEEL cel=0;
915 ASSERT(rec);
916 cel = nzcel(rec);
917 ASSERT(cel);
918 ASSERT(cclock(cel) > 0);
919 --cclock(cel);
920 }
921 /*=========================================
922 * cache_get_lock_counts -- Fill in lock counts
923 * does not include report locks (but, this isn't
924 * called during reports anyway)
925 *=======================================*/
926 static void
cache_get_lock_counts(CACHE ca,INT * locks)927 cache_get_lock_counts (CACHE ca, INT * locks)
928 {
929 CACHEEL cel;
930 for (cel = cacfirstdir(ca); cel; cel = cnext(cel)) {
931 if (cclock(cel) && locks) ++(*locks);
932 }
933 }
934 /*=========================================
935 * get_cache_stats -- Calculate cache stats
936 * returns static buffer
937 *=======================================*/
938 static ZSTR
get_cache_stats(CACHE ca)939 get_cache_stats (CACHE ca)
940 {
941 ZSTR zstr = zs_new();
942 INT lo=0;
943 cache_get_lock_counts(ca, &lo);
944 zs_appf(zstr
945 , "d:%d/%d (l:%d)"
946 , cacsizedir(ca), cacmaxdir(ca), lo
947 );
948 return zstr;
949 }
950 /*=========================================
951 * get_cache_stats_indi -- Return indi cache stats
952 *=======================================*/
953 ZSTR
get_cache_stats_indi(void)954 get_cache_stats_indi (void)
955 {
956 return get_cache_stats(indicache);
957 }
958 /*=========================================
959 * get_cache_stats_fam -- Return fam cache stats
960 *=======================================*/
961 ZSTR
get_cache_stats_fam(void)962 get_cache_stats_fam (void)
963 {
964 return get_cache_stats(famcache);
965 }
966 /*============================================
967 * ensure_cel_has_record -- Make sure cache element has record
968 * (node_to_cache, which creates cels, doesn't create records)
969 *==========================================*/
970 static void
ensure_cel_has_record(CACHEEL cel)971 ensure_cel_has_record (CACHEEL cel)
972 {
973 RECORD rec = get_record_for_cel(cel); /* addref'd */
974 release_record(rec);
975 }
976 /*============================================
977 * add_new_indi_to_cache -- Add person to person cache
978 *==========================================*/
979 void
add_new_indi_to_cache(RECORD rec)980 add_new_indi_to_cache (RECORD rec)
981 {
982 CACHEEL cel=0;
983 NODE root = is_record_temp(rec);
984 cel = node_to_cache(indicache, root);
985 ASSERT(!crecord(cel));
986 record_set_cel(rec, cel);
987 crecord(cel) = rec;
988 addref_record(rec); /* cel holds reference */
989 }
990 /*===========================================
991 * fam_to_cache -- Add family to family cache
992 *=========================================*/
993 void
fam_to_cache(NODE node)994 fam_to_cache (NODE node)
995 {
996 CACHEEL cel = node_to_cache(famcache, node);
997 ensure_cel_has_record(cel);
998 }
999 /*==========================================
1000 * even_to_cache -- Add event to event cache
1001 *========================================*/
1002 void
even_to_cache(NODE node)1003 even_to_cache (NODE node)
1004 {
1005 CACHEEL cel = node_to_cache(evencache, node);
1006 ensure_cel_has_record(cel);
1007 }
1008 /*============================================
1009 * sour_to_cache -- Add source to source cache
1010 *==========================================*/
1011 void
sour_to_cache(NODE node)1012 sour_to_cache (NODE node)
1013 {
1014 CACHEEL cel = node_to_cache(sourcache, node);
1015 ensure_cel_has_record(cel);
1016 }
1017 /*===========================================
1018 * othr_to_cache -- Add other record to cache
1019 *=========================================*/
1020 void
othr_to_cache(NODE node)1021 othr_to_cache (NODE node)
1022 {
1023 CACHEEL cel = node_to_cache(othrcache, node);
1024 ensure_cel_has_record(cel);
1025 }
1026 /*========================================
1027 * node_to_cache -- Add node tree to cache
1028 * This is a high-level entry point, which validates
1029 * and delegates the work
1030 * node tree must be valid, and of the correct type
1031 * (INDI node trees may only be added to INDI cache, etc)
1032 * This puts node into cache (first_direct)
1033 *======================================*/
1034 static CACHEEL
node_to_cache(CACHE cache,NODE top)1035 node_to_cache (CACHE cache, NODE top)
1036 {
1037 STRING key=0;
1038 CACHEEL cel=0;
1039 ASSERT(cache);
1040 ASSERT(top);
1041 ASSERT(!nparent(top)); /* should be a root */
1042 ASSERT(!nsibling(top)); /* should be a root */
1043 if (nestr(cacname(cache), "OTHR")) {
1044 /* only INDI records in INDI cache, etc */
1045 if (!eqstr(cacname(cache), ntag(top))) {
1046 crashlog(_("Bad cache entry <%s> != <%s>"), cacname(cache), ntag(top));
1047 ASSERT(0);
1048 }
1049 }
1050 key = node_to_key(top);
1051 ASSERT(key);
1052 /* ASSERT that record is not in cache */
1053 /* We're not supposed to be called if record in cache */
1054 ASSERT(!valueof_ptr(cacdata(cache), key));
1055 cel = get_free_cacheel(cache);
1056 put_node_in_cache(cache, cel, top, key);
1057 return cel;
1058 }
1059 /*=======================================================
1060 * get_free_cacheel -- Remove and return entry from free list
1061 *=====================================================*/
1062 static CACHEEL
get_free_cacheel(CACHE cache)1063 get_free_cacheel (CACHE cache)
1064 {
1065 CACHEEL cel=0, celnext=0;
1066
1067 /* If free list is empty, move least recently used entry to free list */
1068 if (!cacfree(cache)) {
1069 /* find least recently used by unlocked entry */
1070 for (cel = caclastdir(cache); cel && cclock(cel); cel = cprev(cel)) {
1071 }
1072 if (!cel) {
1073 crashlog(_("Cache [%s] overflowed its max size (%d)"), cacname(cache), cacmaxdir(cache));
1074 ASSERT(0);
1075 }
1076 remove_from_cache(cache, ckey(cel));
1077 }
1078
1079 cel = cacfree(cache);
1080 ASSERT(cel);
1081
1082 /* remove entry from free list */
1083 celnext = cnext(cel);
1084 cacfree(cache) = celnext;
1085 if (celnext)
1086 cprev(celnext) = 0;
1087 /* reinitialize entry */
1088 init_cel(cel);
1089
1090 return cel;
1091 }
1092 /*=======================================================
1093 * set_all_nodetree_to_cel -- clear all the cel pointers in a node tree
1094 *=====================================================*/
1095 static void
set_all_nodetree_to_cel(NODE node,CACHEEL cel)1096 set_all_nodetree_to_cel (NODE node, CACHEEL cel)
1097 {
1098 BOOLEAN travdone = FALSE;
1099 /* Now set all nodes in tree to point to cache record */
1100 while (!travdone) {
1101 node->n_cel = cel;
1102 /* go to bottom of tree */
1103 while (nchild(node)) {
1104 node = nchild(node);
1105 node->n_cel = cel;
1106 }
1107 /* find next node in traversal/ascent */
1108 while (!nsibling(node)) {
1109 if (!nparent(node)) {
1110 travdone=TRUE;
1111 break;
1112 }
1113 node = nparent(node);
1114 }
1115 node = nsibling(node);
1116 }
1117 }
1118 /*=======================================================
1119 * put_node_in_cache -- Low-level work of loading node into cacheel supplied
1120 *=====================================================*/
1121 static void
put_node_in_cache(CACHE cache,CACHEEL cel,NODE node,STRING key)1122 put_node_in_cache (CACHE cache, CACHEEL cel, NODE node, STRING key)
1123 {
1124 BOOLEAN travdone = FALSE;
1125 ASSERT(cache);
1126 ASSERT(node);
1127 ASSERT(cacsizedir(cache) < cacmaxdir(cache));
1128 init_cel(cel);
1129 insert_table_ptr(cacdata(cache), key, cel);
1130 cnode(cel) = node;
1131 ckey(cel) = strsave(key);
1132 cclock(cel) = FALSE;
1133 first_direct(cache, cel);
1134 /* Now set all nodes in tree to point to cache record */
1135 while (!travdone) {
1136 node->n_cel = cel;
1137 /* go to bottom of tree */
1138 while (nchild(node)) {
1139 node = nchild(node);
1140 node->n_cel = cel;
1141 }
1142 /* find next node in traversal/ascent */
1143 while (!nsibling(node)) {
1144 if (!nparent(node)) {
1145 travdone=TRUE;
1146 break;
1147 }
1148 node = nparent(node);
1149 }
1150 node = nsibling(node);
1151 }
1152 }
1153 /*==============================================
1154 * remove_indi_cache -- Remove person from cache
1155 *============================================*/
1156 void
remove_indi_cache(STRING key)1157 remove_indi_cache (STRING key)
1158 {
1159 remove_from_cache(indicache, key);
1160 }
1161 /*=============================================
1162 * remove_fam_cache -- Remove family from cache
1163 *===========================================*/
1164 void
remove_fam_cache(STRING key)1165 remove_fam_cache (STRING key)
1166 {
1167 remove_from_cache(famcache, key);
1168 }
1169 /*=============================================
1170 * remove_from_cache_by_key -- Remove record from cache
1171 *===========================================*/
1172 void
remove_from_cache_by_key(CNSTRING key)1173 remove_from_cache_by_key (CNSTRING key)
1174 {
1175 switch(key[0]) {
1176 case 'I': remove_from_cache(indicache, key); break;
1177 case 'F': remove_from_cache(famcache, key); break;
1178 case 'S': remove_from_cache(sourcache, key); break;
1179 case 'E': remove_from_cache(evencache, key); break;
1180 case 'X': remove_from_cache(othrcache, key); break;
1181 default: ASSERT(0); break;
1182 }
1183 }
1184 /*=============================================
1185 * remove_from_cache -- Move cache entry to free list
1186 *===========================================*/
1187 static void
remove_from_cache(CACHE cache,CNSTRING key)1188 remove_from_cache (CACHE cache, CNSTRING key)
1189 {
1190 BOOLEAN delcache = FALSE;
1191 CACHEEL cel=0;
1192
1193 if (!key || *key == 0 || !cache)
1194 return;
1195 /* If it has a key, it is in the cache */
1196 cel = valueof_ptr(cacdata(cache), key);
1197 remove_cel_from_cache(cache, cel, delcache);
1198 }
1199 /*=============================================
1200 * remove_from_cache -- Move cache entry to free list
1201 * Requires non-null input
1202 *===========================================*/
1203 static void
remove_cel_from_cache(CACHE cache,CACHEEL cel,BOOLEAN delcache)1204 remove_cel_from_cache (CACHE cache, CACHEEL cel, BOOLEAN delcache)
1205 {
1206 CACHEEL celnext=0;
1207 STRING key = ckey(cel);
1208
1209 /* caller ensured cache && key are non-null */
1210 ASSERT(cel);
1211
1212 if (cclock(cel)) {
1213 /*
1214 not supposed to remove locked elements!
1215 Construct informational message and cause exception
1216 */
1217 char msg[1024] = "";
1218 NODE node = cnode(cel);
1219 if (delcache) {
1220 llstrapps(msg, sizeof(msg), uu8
1221 , _("Locked cache element found when deleting cache"));
1222 } else {
1223 llstrapps(msg, sizeof(msg), uu8
1224 , _("Locked cache element found when releasing cache element"));
1225 }
1226 if (node && nxref(node)) {
1227 llstrappf(msg, sizeof(msg), uu8, _(" (node %s)"), nxref(node));
1228 }
1229 FATAL2(msg);
1230 }
1231 ASSERT(!cclock(cel));
1232 ASSERT(cnode(cel));
1233 remove_direct(cache, cel);
1234
1235 /* Clear all node tree info */
1236 if (1) {
1237 NODE node = cnode(cel);
1238 if (node)
1239 set_all_nodetree_to_cel(node, 0);
1240 cnode(cel) = 0;
1241 free_nodes(node);
1242 }
1243
1244 celnext = cacfree(cache);
1245 cnext(cel) = celnext;
1246 if (celnext)
1247 cprev(celnext) = cel;
1248 cprev(cel) = 0;
1249 ckey(cel) = 0;
1250 if (crecord(cel)) {
1251 /* cel holds the original reference to the record */
1252 RECORD rec = crecord(cel);
1253 record_remove_cel(rec, cel);
1254 release_record(rec);
1255 crecord(cel) = 0;
1256 }
1257 cacfree(cache) = cel;
1258 delete_table_element(cacdata(cache), key);
1259 stdfree(key); /* alloc'd when assigned to ckey(cel) */
1260 }
1261 /*================================================================
1262 * value_to_xref -- Converts a string to a record key, if possible
1263 *==============================================================*/
1264 STRING
value_to_xref(STRING val)1265 value_to_xref (STRING val)
1266 {
1267 INT c;
1268
1269 if (!val || (*val != '@') || (strlen(val) < 4) ||
1270 (val[strlen(val)-1] != '@')) return NULL;
1271 val = rmvat(val);
1272 if ((c = *val) != 'I' && c != 'F' && c != 'S' && c != 'E' &&
1273 c != 'X') return NULL;
1274 if (!isnumeric(val + 1)) return NULL;
1275 return val;
1276 }
1277 /*===================================================
1278 * indi_to_cacheel -- Convert person to cache element
1279 *=================================================*/
1280 CACHEEL
indi_to_cacheel(RECORD indi)1281 indi_to_cacheel (RECORD indi)
1282 {
1283 CACHEEL cel=0;
1284 if (!indi || !nztop(indi)) return NULL;
1285 cel = nzcel(indi);
1286 if (cel) return cel;
1287 /*
1288 This is not efficient, rereading the record
1289 But we can't just steal the record given us
1290 without some transfer of memory ownership
1291 */
1292 cel = key_to_indi_cacheel(rmvat(nxref(nztop(indi))));
1293 ASSERT(cel);
1294 return cel;
1295 }
1296 /*===================================================
1297 * indi_to_cacheel_old -- Convert person to cache element
1298 * should be obsoleted by indi_to_cacheel
1299 *=================================================*/
1300 CACHEEL
indi_to_cacheel_old(NODE indi)1301 indi_to_cacheel_old (NODE indi)
1302 {
1303 CACHEEL cel;
1304 if (!indi) return NULL;
1305 #ifdef DEBUG
1306 llwprintf("indi_to_cacheel_old: %s\n", nxref(indi));
1307 #endif
1308 cel = key_to_indi_cacheel(rmvat(nxref(indi)));
1309 ASSERT(cel);
1310 return cel;
1311 }
1312 /*==================================================
1313 * fam_to_cacheel -- Convert family to cache element
1314 *================================================*/
1315 CACHEEL
fam_to_cacheel(RECORD frec)1316 fam_to_cacheel (RECORD frec)
1317 {
1318 CACHEEL cel;
1319 if (!frec) return NULL;
1320 cel = key_to_fam_cacheel(rmvat(nxref(nztop(frec))));
1321 ASSERT(cel);
1322 return cel;
1323 }
1324 /*==================================================
1325 * fam_to_cacheel_old -- Convert family to cache element
1326 *================================================*/
1327 CACHEEL
fam_to_cacheel_old(NODE fam)1328 fam_to_cacheel_old (NODE fam)
1329 {
1330 CACHEEL cel;
1331 if (!fam) return NULL;
1332 cel = key_to_fam_cacheel(rmvat(nxref(fam)));
1333 ASSERT(cel);
1334 return cel;
1335 }
1336 /*===================================================
1337 * sour_to_cacheel -- Convert source to cache element
1338 *=================================================*/
1339 CACHEEL
sour_to_cacheel(NODE node)1340 sour_to_cacheel (NODE node)
1341 {
1342 CACHEEL cel;
1343 if (!node) return NULL;
1344 cel = key_to_sour_cacheel(rmvat(nxref(node)));
1345 ASSERT(cel);
1346 return cel;
1347 }
1348 /*==================================================
1349 * even_to_cacheel -- Convert event to cache element
1350 *================================================*/
1351 CACHEEL
even_to_cacheel(NODE even)1352 even_to_cacheel (NODE even)
1353 {
1354 CACHEEL cel;
1355 if (!even) return NULL;
1356 cel = key_to_even_cacheel(rmvat(nxref(even)));
1357 ASSERT(cel);
1358 return cel;
1359 }
1360 /*==================================================
1361 * othr_to_cacheel -- Convert other to cache element
1362 *================================================*/
1363 CACHEEL
othr_to_cacheel(NODE othr)1364 othr_to_cacheel (NODE othr)
1365 {
1366 CACHEEL cel;
1367 if (!othr) return NULL;
1368 cel = key_to_othr_cacheel(rmvat(nxref(othr)));
1369 ASSERT(cel);
1370 return cel;
1371 }
1372 /*==================================================
1373 * record_to_cacheel -- Convert any record to cache element
1374 *================================================*/
1375 CACHEEL
record_to_cacheel(RECORD rec)1376 record_to_cacheel (RECORD rec)
1377 {
1378 STRING key = rmvat(nxref(nztop(rec)));
1379 switch(key[0]) {
1380 case 'I': return indi_to_cacheel(rec);
1381 case 'F': return fam_to_cacheel(rec);
1382 case 'S': return sour_to_cacheel(nztop(rec));
1383 case 'E': return even_to_cacheel(nztop(rec));
1384 case 'X': return othr_to_cacheel(nztop(rec));
1385 }
1386 ASSERT(0); return NULL;
1387 }
1388 /*==================================================
1389 * node_to_cacheel_old -- Convert any node to cache element
1390 *================================================*/
1391 CACHEEL
node_to_cacheel_old(NODE node)1392 node_to_cacheel_old (NODE node)
1393 {
1394 STRING key = rmvat(nxref(node));
1395 switch(key[0]) {
1396 case 'I': return indi_to_cacheel_old(node);
1397 case 'F': return fam_to_cacheel_old(node);
1398 case 'S': return sour_to_cacheel(node);
1399 case 'E': return even_to_cacheel(node);
1400 case 'X': return othr_to_cacheel(node);
1401 }
1402 ASSERT(0); return NULL;
1403 }
1404 /*==============================================
1405 * key_of_record -- Return display key of record
1406 * returns static buffer
1407 *============================================*/
1408 STRING
key_of_record(NODE node)1409 key_of_record (NODE node)
1410 {
1411 NODE refn;
1412 ASSERT(node);
1413 refn = REFN(node);
1414 if (refn && nval(refn)) {
1415 return nval(refn);
1416 }
1417 return rmvat(nxref(node)) + 1;
1418 }
1419 /*==============================================
1420 * qkey_to_???_cacheel -- Convert key to cacheel
1421 * (report mode - returns NULL if failure)
1422 * 5 symmetric versions
1423 *============================================*/
qkey_to_indi_cacheel(STRING key)1424 CACHEEL qkey_to_indi_cacheel (STRING key)
1425 {
1426 return key_to_cacheel(indicache, key, "INDI", TRUE);
1427 }
qkey_to_fam_cacheel(STRING key)1428 CACHEEL qkey_to_fam_cacheel (STRING key)
1429 {
1430 return key_to_cacheel(famcache, key, "FAM", TRUE);
1431 }
qkey_to_even_cacheel(STRING key)1432 CACHEEL qkey_to_even_cacheel (STRING key)
1433 {
1434 return key_to_cacheel(evencache, key, "EVEN", TRUE);
1435 }
qkey_to_sour_cacheel(STRING key)1436 CACHEEL qkey_to_sour_cacheel (STRING key)
1437 {
1438 return key_to_cacheel(sourcache, key, "SOUR", TRUE);
1439 }
qkey_to_othr_cacheel(STRING key)1440 CACHEEL qkey_to_othr_cacheel (STRING key)
1441 {
1442 return key_to_cacheel(othrcache, key, NULL, TRUE);
1443 }
1444 /*==============================================
1445 * qkey_to_typed_cacheel -- Lookup/load key
1446 *============================================*/
1447 /* unused
1448 static CACHEEL
1449 qkey_to_typed_cacheel (STRING key)
1450 {
1451 char ntype;
1452 ASSERT(key);
1453 ASSERT(key[0]);
1454 ntype = key[0];
1455 switch(ntype) {
1456 case 'I': return qkey_to_indi_cacheel(key);
1457 case 'F': return qkey_to_fam_cacheel(key);
1458 case 'S': return qkey_to_even_cacheel(key);
1459 case 'E': return qkey_to_sour_cacheel(key);
1460 case 'X': return qkey_to_othr_cacheel(key);
1461 }
1462 ASSERT(0);
1463 }
1464 unused */
1465 /*==============================================
1466 * cacheel_to_key -- Return key of record inside of cache element
1467 * handle NULL input
1468 *============================================*/
1469 CNSTRING
cacheel_to_key(CACHEEL cel)1470 cacheel_to_key (CACHEEL cel)
1471 {
1472 CNSTRING key = cel ? ckey(cel) : 0;
1473 return key;
1474 }
1475 /*==============================================
1476 * cacheel_to_node -- Return root node of record inside of cache element
1477 * loads cache element if needed
1478 * handle NULL input
1479 *============================================*/
1480 NODE
cacheel_to_node(CACHEEL cel)1481 cacheel_to_node (CACHEEL cel)
1482 {
1483 if (!cel) return NULL;
1484 if (!cnode(cel)) {
1485 CACHEEL cel2 = key_to_indi_cacheel(ckey(cel));
1486 ASSERT(cel2 == cel);
1487 ASSERT(cnode(cel));
1488 }
1489 return cnode(cel);
1490 }
1491 /*==============================================
1492 * is_cel_loaded -- If cache element is loaded, return root
1493 * handle NULL input
1494 *============================================*/
1495 NODE
is_cel_loaded(CACHEEL cel)1496 is_cel_loaded (CACHEEL cel)
1497 {
1498 if (!cel) return NULL;
1499 return cnode(cel);
1500 }
1501 /*==============================================
1502 * cel_remove_record -- Our record informing us it is destructing
1503 * Requires non-null inputs
1504 *============================================*/
1505 void
cel_remove_record(CACHEEL cel,RECORD rec)1506 cel_remove_record (CACHEEL cel, RECORD rec)
1507 {
1508 ASSERT(cel);
1509 ASSERT(cel->c_magic == cel_magic);
1510 ASSERT(rec);
1511 if (crecord(cel) == rec) {
1512 crecord(cel) = 0;
1513 }
1514 }
1515 /*=======================================================
1516 * set_all_nodetree_to_root_cel -- Propagate cel from root to all descendants
1517 *=====================================================*/
1518 void
set_all_nodetree_to_root_cel(NODE root)1519 set_all_nodetree_to_root_cel (NODE root)
1520 {
1521 set_all_nodetree_to_cel(root, root->n_cel);
1522 }
1523 /*=======================================================
1524 * free_all_rprtlocks_in_cache -- Remove any rptlocks on any
1525 * elements in this cache, and return number removed
1526 *=====================================================*/
1527 static int
free_all_rprtlocks_in_cache(CACHE cache)1528 free_all_rprtlocks_in_cache (CACHE cache)
1529 {
1530 INT ct=0;
1531 CACHEEL cel=0;
1532
1533 for (cel = caclastdir(cache); cel; cel = cprev(cel)) {
1534 if (ccrptlock(cel)) {
1535 INT delta = ccrptlock(cel);
1536 ccrptlock(cel) = 0;
1537 ASSERT(cclock(cel) >= delta);
1538 cclock(cel) -= delta;
1539 ++ct;
1540 }
1541 }
1542 return ct;
1543 }
1544 /*=======================================================
1545 * free_all_rprtlocks -- Remove any rptlocks on any
1546 * elements in all caches, and return number removed
1547 *=====================================================*/
1548 int
free_all_rprtlocks(void)1549 free_all_rprtlocks (void)
1550 {
1551 int ct=0;
1552 ct += free_all_rprtlocks_in_cache(indicache);
1553 ct += free_all_rprtlocks_in_cache(famcache);
1554 ct += free_all_rprtlocks_in_cache(sourcache);
1555 ct += free_all_rprtlocks_in_cache(sourcache);
1556 ct += free_all_rprtlocks_in_cache(othrcache);
1557 return ct;
1558 }
1559