simple-cache.c 50.3 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: simple-cache.c,v 0.63 1997/09/13 15:32:40 byers Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996  Lysator Academic Computer Association.
Linus Tolke Y's avatar
Linus Tolke Y committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 1, or (at your option) 
 * any later version.
 * 
 * LysKOM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
Per Cederqvist's avatar
Per Cederqvist committed
25 26 27 28 29 30 31 32 33 34 35
/*
 * This module contains some simple simulations of the routines in
 * cache.c.
 *
 * Extracted from ram-cache.c and rewritten by ceder.
 *
 * New database format with texts in their own file by Inge Wallin.
 *
 * New save algorithm by ceder.
 */

36
static char *rcsid = "$Id: simple-cache.c,v 0.63 1997/09/13 15:32:40 byers Exp $";
37 38
#include "rcs.h"
USE(rcsid);
Per Cederqvist's avatar
Per Cederqvist committed
39

Per Cederqvist's avatar
Per Cederqvist committed
40 41
#include <errno.h>
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
42
#include <sys/types.h>
43 44 45
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
46 47 48
#ifdef HAVE_STRING_H
#  include <string.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
49 50 51 52
#ifndef SEEK_END
#  include <fcntl.h>
#endif
#ifndef SEEK_END
Per Cederqvist's avatar
Per Cederqvist committed
53 54 55
#  define SEEK_SET 0
#  define SEEK_END 2
#endif
Per Cederqvist's avatar
Per Cederqvist committed
56 57
#include <time.h>
#include <setjmp.h>
58 59 60
#ifdef HAVE_STDARG_H
#  include <stdarg.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
61

62
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
63 64
#include "exp.h"
#include "misc-types.h"
65
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79
#include "kom-types.h"
#include "tmp-limits.h"
#include "cache-node.h"
#include "cache.h"
#include "parser.h"
#include "ram-parse.h"
#include "ram-output.h"
#include "server/smalloc.h"
#include "kom-memory.h"
#include "lyskomd.h"
#include "debug.h"
#include "kom-errno.h"
#include "log.h"
#include "com.h"
80
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
81 82
#include "connections.h"
#include "send-async.h"
83
#include "param.h"
Per Cederqvist's avatar
Per Cederqvist committed
84
#include "config.h"
David Byers's avatar
David Byers committed
85
#include "admin.h"
Per Cederqvist's avatar
Per Cederqvist committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

/*
 * Possible improvements: +++
 *  When there are consecutive items in file A that shall be copied
 *  to file B, copy them in one transfer (up to a certain limit).
 *
 *  In pre_sync: compute size of, and allocate disk space for file B.
 */

/*
 * All functions that can fail sets kom_errno to a suitable value
 * if they fail.
 */

static Small_conf	* small_conf_arr[ MAX_CONF ];
101 102
static Cache_node_mcb	* pers_mcb;
static Cache_node_mcb 	* conf_mcb;
Per Cederqvist's avatar
Per Cederqvist committed
103 104
static int		  next_free_num = 1;

105 106
static Cache_node_mcb 	* text_mcb;
static int		  next_text_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
107 108 109 110 111 112 113

/*
 * The elements in the following lists with same index refers to the same
 * conference.
 */
static int    no_of_match_info;
EXPORT Matching_info *match_table = NULL;
Per Cederqvist's avatar
Per Cederqvist committed
114
EXPORT Conf_no       *conf_table  = NULL; /* Used in conference.c. */
Per Cederqvist's avatar
Per Cederqvist committed
115 116 117 118 119 120 121 122 123 124


static FILE	*text_file= NULL;
static FILE	*file_a = NULL;	/* Current file. */
static FILE	*file_b = NULL;	/* File under construction. */

/*
 * Four state variables for the background save.
 */
static enum {
125
    sync_idle,
Per Cederqvist's avatar
Per Cederqvist committed
126 127 128 129 130 131 132 133
    sync_save_conf,
    sync_save_pers,
    sync_save_text,
    sync_error,
    sync_wait,
    sync_ready
} sync_state;

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
/* The state machine sync_state works like this:
 *
 *  Old state              action           new state
 *  none               sync_part called     sync_idle
 *                     for the first time
 *  sync_idle	       SYNC_INTERVAL        sync_save_conf
 *  sync_save_conf     all confs saved      sync_save_pers
 *  sync_save_pers     all persons saved    sync_save_text
 *  sync_save_text     all texts saved      sync_ready
 *  sync_ready         sync_part called     sync_idle
 *  any                error occurs         sync_error
 *  sync_error         sync_part called     sync_wait
 *  sync_wait          SYNC_RETRY_INTERVAL  sync_save_conf
 */

Per Cederqvist's avatar
Per Cederqvist committed
149 150 151 152 153 154 155
static long sync_next;

static Conf_no highest_conf_no;
static Text_no highest_text_no;

BUGDECL;

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
/* Define LOGACCESSES if you want to be able to log all accesses to
   the data base. */

#ifdef LOGACCESSES
typedef enum {
    lt_restart,
    lt_text_stat,
    lt_text_mass,
    lt_conf_stat,
    lt_pers_stat,
    
    lt_text_def,
    lt_conf_def,
    lt_pers_def,

    lt_create_text,
    lt_garb_text,
    lt_delete_text,
    lt_create_conf,
    lt_delete_conf,
    lt_create_pers,
    lt_delete_pers,

    lt_lock_conf,
    lt_unlock_conf,
    lt_lock_pers,
    lt_unlock_pers,

    lt_get_highest,		/* Get highest Local_text_no for a conf. */
    lt_get_conf_type
    /* Note: mark_*_as_changed is not logged. */
} Log_type;

static FILE *logfile = NULL;
static int syncing_or_saving = 0;
static int garb_running = 0;

static void log_access(Log_type t,
		       int id)
{
196 197
    extern int putw(int, FILE *);

198 199 200 201 202 203 204 205 206 207 208
    if (garb_running + syncing_or_saving == 0)
    {
	putc(t, logfile);
	putw(id, logfile);
    }
}
#define LOGACC(a,b) {if (logfile) log_access(a, b);}
#else
#define LOGACC(a,b)
#endif

Per Cederqvist's avatar
Per Cederqvist committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222

/* Macros */

#define TRACE2(format, arg) if ( buglevel > 2 ) printf(format, arg)
#define TRACE1(format) if ( buglevel > 2 ) printf(format)
#define TRACESTR(str)  if ( buglevel > 2 ) s_puts(str)


static Person *
read_person(FILE *fp,
	    long pos,
	    long size)
{
    Person *p;
David Byers's avatar
David Byers committed
223
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
224 225 226

    p = alloc_person();
    fseek(fp, pos+1, SEEK_SET);	/* Skip '+' */
David Byers's avatar
David Byers committed
227
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    if ( fparse_person(fp, p) != OK )
    {
	free_person(p);
	return NULL;
    }
    else
	return p;
}



static Conference *
read_conference(FILE *fp,
		long pos,
		long size)
{
    Conference *c;
David Byers's avatar
David Byers committed
245
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
246 247 248

    c = alloc_conference();
    fseek(fp, pos+1, SEEK_SET);	/* Skip '+' */
David Byers's avatar
David Byers committed
249
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    if ( fparse_conference(fp, c) != OK )
    {
	free_conference(c);
	return NULL;
    }
    else
	return c;
}
	

static Text_stat *
read_text_stat(FILE *fp,
	       long pos,
	       long size)
{
    Text_stat *t;
David Byers's avatar
David Byers committed
266
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
267 268 269

    t = alloc_text_stat();
    fseek(fp, pos+1, SEEK_SET);	/* Skip '+' */
David Byers's avatar
David Byers committed
270
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
271 272 273 274 275 276 277 278 279 280
    if ( fparse_text_stat(fp, t) != OK )
    {
	free_text_stat(t);
	return NULL;
    }
    else
	return t;
}

static void
281
pers_set_mru(Pers_no pers_no)
Per Cederqvist's avatar
Per Cederqvist committed
282
{
283
    set_mru(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
284 285 286
}

static void
287
text_set_mru(Text_no text_no)
Per Cederqvist's avatar
Per Cederqvist committed
288
{
289
    set_mru(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
290 291 292
}

static void
293
conf_set_mru(Conf_no conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
294
{
295 296
    set_mru(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
297

298 299 300
static Cache_node *
get_pers_node(Pers_no pers_no)
{
301 302 303
    if ( pers_no >= next_free_num )
	return NULL;

304
    return get_cache_node(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
305 306 307
}

static void
308
unlink_text_lru (Cache_node *node)
Per Cederqvist's avatar
Per Cederqvist committed
309
{
310
    unlink_lru (node, &text_mcb->lru, &text_mcb->mru);
Per Cederqvist's avatar
Per Cederqvist committed
311 312
}

313 314 315 316 317
static void
unlink_conf_lru (Cache_node *node)
{
    unlink_lru (node, &conf_mcb->lru, &conf_mcb->mru);
}
Per Cederqvist's avatar
Per Cederqvist committed
318 319

static void
320
unlink_pers_lru (Cache_node *node)
Per Cederqvist's avatar
Per Cederqvist committed
321
{
322 323
    unlink_lru (node, &pers_mcb->lru, &pers_mcb->mru);
}
Per Cederqvist's avatar
Per Cederqvist committed
324

325 326 327
static Cache_node *
get_conf_node(Conf_no conf_no)
{
328 329 330
    if ( conf_no >= next_free_num )
	return NULL;

331 332
    return get_cache_node(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
333

334 335 336
static Cache_node *
get_text_node(Text_no text_no)
{
337 338 339
    if ( text_no >= next_text_num )
	return NULL;

340
    return get_cache_node(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
}

	
/*
 * Name caching routines
 */

/*
 * change_name changes the cached conference name. It is only called when
 * a conference name is changed or a conference is deleted.
 */
void
cached_change_name( Conf_no name_num,
		    String new_name )
{
    if ( name_num < 1 || name_num >= next_free_num )
	restart_kom("cached_change_name(%d, ----): next_free_num==%d",
		    name_num, next_free_num);

    s_clear( &small_conf_arr[name_num]->name );
    s_strcpy( &small_conf_arr[name_num]->name, new_name);
    build_matching_info();
}


extern Conf_type
cached_get_conf_type (Conf_no conf_no)
{
    if ( conf_no < 1 || conf_no >= next_free_num )
	restart_kom("cached_get_conf_type(%d): next_free_num==%d",
		    conf_no, next_free_num);
372 373 374 375 376

    if ( small_conf_arr [ conf_no ] == NULL )
	restart_kom("cached_get_conf_type(%d): conference does not exist.\n",
		    conf_no);

377 378
    LOGACC(lt_get_conf_type, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
379 380 381
    return small_conf_arr [ conf_no ]->type;
}

382 383 384 385 386 387 388 389 390
/*
 * Return number of conferences present.  (Actually, return a number
 * at least as large as the number of conferences present).
 */
extern Conf_no
cached_no_of_existing_conferences(void)
{
    return next_free_num;	/* This is too large, but who cares? */
}
Per Cederqvist's avatar
Per Cederqvist committed
391 392 393 394 395 396 397 398

/*
 * Various function calls to tell the cache that something is changed.
 */

void
mark_person_as_changed(Pers_no	pers_no)
{
399 400 401 402
    Cache_node *node;

    node = get_pers_node(pers_no);
    
Per Cederqvist's avatar
Per Cederqvist committed
403
    TRACE2("Person %d is changed\n", pers_no);
404
    if ( node == NULL || node->s.exists == 0)
Per Cederqvist's avatar
Per Cederqvist committed
405 406
	restart_kom("mark_person_as_changed(%d): nonexistent.\n", pers_no);

407
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
408 409 410
    pers_set_mru( pers_no );
}

411 412 413 414 415 416 417 418 419 420 421
/*
 * Mark the conference as dirty, so that it will be written to
 * the disk.
 *
 * Also update all fields in the Small_conf except then name, so that
 * they are always current.
 *
 * NOTE: You must call cached_change_name when the name changes.
 *       It is not necessary to call cached_change_name after
 *       cached_create_conf.
 */
Per Cederqvist's avatar
Per Cederqvist committed
422 423 424 425

void
mark_conference_as_changed(Conf_no	conf_no)
{
426
    Cache_node *node;
427
    Conference *conf_c;
428 429 430

    node = get_conf_node (conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
431
    TRACE2("Conf.  %d is changed\n", conf_no);
432
    if ( node == NULL || node->s.exists == 0)
Per Cederqvist's avatar
Per Cederqvist committed
433 434
	restart_kom("mark_conference_as_changed(%d): nonexistent.\n", conf_no);

435
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
436
    conf_set_mru( conf_no );
437 438 439

    conf_c = (Conference *) node->ptr;

Per Cederqvist's avatar
Per Cederqvist committed
440
    small_conf_arr[ conf_no ]->highest_local_no
441 442 443 444
	= (conf_c->texts.first_local_no - 1 + conf_c->texts.no_of_texts );

    small_conf_arr[ conf_no ]->nice = conf_c->nice;
    small_conf_arr[ conf_no ]->type = conf_c->type;
Per Cederqvist's avatar
Per Cederqvist committed
445 446 447 448 449
}

void
mark_text_as_changed( Text_no text_no )
{
450 451 452 453
    Cache_node *node;

    node = get_text_node (text_no);

454
    TRACE2("Text %lu is changed.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
455
    if ( text_no < 1 || text_no >= next_text_num
456
	|| node == NULL || node->s.exists == 0)
Per Cederqvist's avatar
Per Cederqvist committed
457
    {
458
	restart_kom("mark_text_as_changed(%lu): nonexistent.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
459 460
    }

461 462
    node->s.dirty = 1;
    text_set_mru (text_no);
Per Cederqvist's avatar
Per Cederqvist committed
463 464 465 466 467 468 469 470 471 472 473 474
}    



/*
 * Person-related calls
 */


extern Success
cached_create_person( Pers_no person )
{
475 476
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
477 478 479 480 481 482 483 484
    TRACE2("Person %d is being created.\n", person);

    if ( person < 1 || person >= next_free_num )
    {
	restart_kom("cached_create_person(%d): next_free_num == %d.\n",
		    person, next_free_num);
    }

485
    if ( get_pers_node(person) != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
486 487 488 489 490
    {
	restart_kom("cached_create_person(%d): Person existed.\n",
		    person);
    }

491 492 493 494 495
    create_cache_node (pers_mcb, person);
    node = get_pers_node (person);

    if ( node == NULL )
	restart_kom("cached_create_person(): couldn't get cache_node.\n");
496

497 498 499
    node->ptr = alloc_person();
    node->s.dirty = 1;
    node->s.exists = 1;
Per Cederqvist's avatar
Per Cederqvist committed
500
    pers_set_mru( person );
501 502 503

    LOGACC(lt_create_pers, person);

Per Cederqvist's avatar
Per Cederqvist committed
504 505 506 507 508 509 510
    return OK;
}


extern Person *
cached_get_person_stat( Pers_no	person )
{
511 512
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
513 514 515 516
    TRACE2("cached_get_person_stat %d\n", person);

    if ( person == 0 )
    {
517
        err_stat = 0;
Per Cederqvist's avatar
Per Cederqvist committed
518 519 520
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
521

522 523
    if ( person >= next_free_num )
    {
524
        err_stat = person;
525 526 527 528
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

529 530
    node = get_pers_node (person);

531
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
532
    {
533
        err_stat = person;
Per Cederqvist's avatar
Per Cederqvist committed
534 535 536 537
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

538 539
    LOGACC(lt_pers_stat, person);

540
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
541 542
    {
	pers_set_mru( person );
543
	++pers_mcb->hits;
544
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
545 546
    }

547
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
548
    {
549
	node->ptr = copy_person (node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
550
	pers_set_mru (person);
551
	++pers_mcb->hits;
552
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
553 554
    }

555
    node->ptr = read_person(file_a, node->pos, node->size);
Per Cederqvist's avatar
Per Cederqvist committed
556

557
    ++pers_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
558
    pers_set_mru (person);
559
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
560 561 562 563 564 565
}


/*
 * Conference-related calls
 */
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581


static int no_of_allocated_small_confs = 0;

static void
free_small_conf (Small_conf *sc)
{
    if ( sc != NULL )
    {
	--no_of_allocated_small_confs;
	s_clear ( &sc->name );
	sfree (sc);
    }
}


582 583 584 585 586 587 588 589 590
static void
init_small_conf(Small_conf *sc)
{
    sc->name = EMPTY_STRING;
    init_conf_type(&sc->type);
    sc->highest_local_no = 0;
    sc->nice = param.default_nice;
}

591 592 593 594 595
static Small_conf *
alloc_small_conf(void)
{
    Small_conf *s;
    s = smalloc(sizeof(Small_conf));
596
    init_small_conf(s);
597 598 599 600 601 602
    ++no_of_allocated_small_confs;

    return s;
}


603 604 605 606 607 608
/*
 * Create a conference.
 *
 * Set up a Conference and cache the name in the small_conf_array.
 */
extern Conf_no
Per Cederqvist's avatar
Per Cederqvist committed
609 610 611 612
cached_create_conf (String  name)
{
    Conference * conf_c;
    Conf_no	 conf_no;
613
    Cache_node  *node;
Per Cederqvist's avatar
Per Cederqvist committed
614 615 616 617 618 619 620

    TRACE1("cached_create_conf( ");
    TRACESTR(name);
    TRACE1(" )\n");

    if ( next_free_num >= MAX_CONF )
    {
621
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
622 623 624 625 626 627
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;

628 629 630 631 632 633 634 635 636
    create_cache_node (conf_mcb, conf_no);
    node = get_conf_node (conf_no);

    if ( node == NULL )
	restart_kom("cached_create_conf(): failed to allocate cache_node.\n");
    
    node->s.exists = 1;
    node->s.dirty = 1;
    node->ptr = conf_c = alloc_conference();
Per Cederqvist's avatar
Per Cederqvist committed
637 638
    conf_set_mru(conf_no);    

639
    zero_init_cache_node (pers_mcb, conf_no);
Per Cederqvist's avatar
Per Cederqvist committed
640 641 642 643 644 645
    small_conf_arr[ conf_no ] = alloc_small_conf();

    conf_c->name = EMPTY_STRING;
    s_strcpy(&conf_c->name, name);
    cached_change_name( conf_no, name);

646
    TRACE2("Created conference number %d\n", conf_no);
647 648 649

    LOGACC(lt_create_conf, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
650 651 652 653 654 655 656
    return conf_no;
}


extern Success
cached_delete_conf( Conf_no	conf )
{
657 658
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
659 660
    if ( conf == 0 )
    {
661
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
662 663 664
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
665

666 667
    if ( conf >= next_free_num )
    {
668
        err_stat = conf;
669 670 671 672
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

673 674
    node = get_conf_node (conf);

675
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
676
    {
677
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
678 679 680 681
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

682 683 684
    if ( node->lock_cnt > 0 )
	log("WNG: cached_delete_conf(%d): lock_cnt === %d\n",
	    conf, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
685

686
    s_clear( &small_conf_arr[conf]->name );
687 688 689
    free_conference(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
690

691 692
    LOGACC(lt_delete_conf, conf);

693
    build_matching_info();
Per Cederqvist's avatar
Per Cederqvist committed
694 695 696 697 698 699
    return OK;
}

Success
cached_delete_person(Pers_no pers)
{
700 701
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
702 703
    if ( pers == 0 )
    {
704
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
705 706 707
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
708

709 710 711
    if ( pers >= next_free_num )
    {
	log("cached_delete_person(%lu): next_free_num == %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
712
	    (unsigned long)pers, (unsigned long)next_free_num);
713
        err_stat = pers;
714 715 716 717
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

718 719 720
    node = get_pers_node (pers);

    if ( pers >= next_free_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
721
    {
Per Cederqvist's avatar
Per Cederqvist committed
722
	log("cached_delete_person(): attempt to delete void person.\n");
723
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
724 725 726 727
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

728
    if ( node->lock_cnt > 0 )
729
	log("cached_delete_pers(%lu): lock_cnt === %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
730
	    (unsigned long)pers, (unsigned long)node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
731

732 733
    LOGACC(lt_delete_pers, pers);

734 735 736
    free_person (node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
737 738 739 740 741 742
    return OK;
}

Success
cached_delete_text(Text_no text)
{
743 744
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
745 746
    if ( text == 0 )
    {
747
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
748 749 750
	kom_errno = KOM_TEXT_ZERO;
	return FAILURE;
    }
751 752 753 754 755

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL
	|| node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
756
    {
757
	log("cached_delete_text(): attempt to delete void text %lu.\n", text);
758
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
759 760 761 762
	kom_errno = KOM_NO_SUCH_TEXT;
	return FAILURE;
    }

763
    if ( node->lock_cnt > 0 )
764
	log("cached_delete_text(%lu): lock_cnt === %d\n",
765
	    text, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
766 767


768 769 770
    free_text_stat(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
771

772 773 774
#ifdef LOGACCESSES
    if (garb_running)
    {
775
	LOGACC(lt_garb_text, text);
776 777
    }
    else
778
	LOGACC(lt_delete_text, text);
779
#endif
Per Cederqvist's avatar
Per Cederqvist committed
780 781 782 783 784
    return OK;
}


extern Conference *
785
cached_get_conf_stat (Conf_no   conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
786
{
787 788
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
789 790 791 792
    TRACE2("cached_get_conf_stat %d\n", conf_no);

    if ( conf_no == 0 )
    {
793
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
794 795 796
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
797 798 799 800

    node = get_conf_node (conf_no);

    if ( conf_no >= next_free_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
801
    {
802
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
803 804 805 806
	kom_errno = KOM_UNDEF_CONF;
	return NULL;
    }

807 808
    LOGACC(lt_conf_stat, conf_no);

809
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
810
    {
811
	conf_set_mru (conf_no);
812
	++conf_mcb->hits;
813
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
814 815
    }

816
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
817
    {
818
	node->ptr = copy_conference (node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
819
	conf_set_mru (conf_no);
820
	++conf_mcb->hits;
821
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
822 823
    }

824
    node->ptr = read_conference(file_a, node->pos, node->size);
825
    ++conf_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
826 827

    conf_set_mru (conf_no);
828
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
829 830 831 832 833 834 835 836
}

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
837 838 839 840 841 842 843
    Cache_node *node;

    if (conf_no == 0 || conf_no >= next_free_num )
	return FALSE;

    node = get_conf_node (conf_no);

844 845 846 847
    if (node != NULL && node->s.exists != 0)
      return TRUE;
    else
      return FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
}

    
/*
 * Calls to handle texts
 */

/*
 * +++ Should return Success.
 */
extern String
cached_get_text( Text_no text )
{
    String  the_string;
    Text_stat *t_stat;

864
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
865 866 867 868 869

    if ( (t_stat = cached_get_text_stat (text)) == NULL )
	return EMPTY_STRING;
    else
    {
870
	LOGACC(lt_text_mass, text);
Per Cederqvist's avatar
Per Cederqvist committed
871 872 873 874 875 876 877
	the_string.string = tmp_alloc( t_stat->no_of_chars );
	the_string.len = t_stat->no_of_chars;
	fseek(text_file, t_stat->file_pos, SEEK_SET);

	if ( fread(the_string.string, sizeof(char), the_string.len, text_file)
	    != the_string.len )
	{
878
	    log("WARNING: cached_get_text: premature end on text %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
879 880 881 882 883 884 885 886 887 888 889 890
		text);
	    return EMPTY_STRING;
	}
		    
	return the_string;
    }
}


extern Text_stat *	/* NULL on error */
cached_get_text_stat(	Text_no		text )
{
891 892
    Cache_node *node;

893
    TRACE2("cached_get_text_stat(%lu);  next_text_num == ", text);
Per Cederqvist's avatar
Per Cederqvist committed
894 895 896 897
    TRACE2("%d\n", next_text_num);

    if ( text == 0 )
    {
898
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
899 900 901
	kom_errno = KOM_TEXT_ZERO;
	return NULL;
    }
902 903 904 905

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
906 907
    {
	TRACE1("cached_get_text_stat: no such text.\n");
908
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
909 910 911 912
	kom_errno = KOM_NO_SUCH_TEXT;
	return NULL;
    }

913 914
    LOGACC(lt_text_stat, text);

915
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
916 917 918
    {
	TRACE1("Found in ptr.\n");
	text_set_mru( text );
919
	++text_mcb->hits;
920
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
921 922
    }

923
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
924 925
    {
	TRACE1("Found in snap_shot\n");
926
	node->ptr = copy_text_stat(node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
927
	text_set_mru (text);
928
	++text_mcb->hits;
929
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
930 931 932
    }

    TRACE1("Found in file A.\n");
933
    node->ptr = read_text_stat(file_a, node->pos, node->size);
Per Cederqvist's avatar
Per Cederqvist committed
934 935

    text_set_mru (text);
936
    ++text_mcb->misses;
937
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
938 939 940 941 942 943
}



/*
 * The text is set up with an empty misc-field. The misc field is
944
 * then initialized by create_text.
Per Cederqvist's avatar
Per Cederqvist committed
945 946 947
 */

extern Text_no
948
cached_create_text(const String message)
Per Cederqvist's avatar
Per Cederqvist committed
949 950
{
    Text_no tno;
951
    Cache_node *node;
952
    long file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
953 954 955

    tno = next_text_num++;

956
    TRACE2("cached_create_text (len=%lu)\n", message.len);
Per Cederqvist's avatar
Per Cederqvist committed
957 958 959

    if ( tno >= MAX_TEXT )
    {
960
        err_stat = tno;
Per Cederqvist's avatar
Per Cederqvist committed
961 962 963 964 965 966
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	next_text_num = MAX_TEXT;
	
	return 0;
    }

967 968 969 970 971 972 973 974 975 976 977 978
    if (fseek(text_file, 0, SEEK_END) != 0) 
    {
	log("ERROR: cannot seek to end of text_file: %s\n", strerror(errno));
	clearerr(text_file);
	return 0;
    }

    file_pos = ftell(text_file);

    if (fwrite(message.string, 1, message.len, text_file) != message.len)
    {
	if (errno != ENOSPC)
979
	    log("WARNING: cached_create_text: Couldn't write text %lu: %s\n",
980
		tno, strerror(errno));
981
        err_stat = 0;
982 983 984 985 986 987 988 989
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fflush(text_file) != 0)
    {
	if (errno != ENOSPC)
990
	    log("WARNING: cached_create_text: Couldn't fflush text %lu: %s\n",
991
		tno, strerror(errno));
992
        err_stat = 0;
993 994 995 996 997 998 999 1000
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fsync(fileno(text_file)) != 0)
    {
	if (errno != ENOSPC)
1001
	    log("WARNING: cached_create_text: Couldn't fsync text %lu: %s\n",
1002
		tno, strerror(errno));
1003
        err_stat = 0;
1004 1005 1006 1007 1008
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

1009 1010
    create_cache_node(text_mcb, tno);
    node = get_text_node (tno);
Per Cederqvist's avatar
Per Cederqvist committed
1011

1012
    if ( node == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
1013
	restart_kom("cached_create_text(): couldn't create cache-node.\n");
1014 1015 1016 1017 1018 1019 1020 1021 1022
    
    node->s.exists = 1;
    node->s.dirty = 1;
    node->ptr = alloc_text_stat();
    ((Text_stat *)node->ptr)->no_of_misc = 0;
    ((Text_stat *)node->ptr)->misc_items = NULL;
    ((Text_stat *)node->ptr)->no_of_marks = 0;
    ((Text_stat *)node->ptr)->no_of_lines = 0;
    ((Text_stat *)node->ptr)->no_of_chars = 0;
1023
    ((Text_stat *)node->ptr)->file_pos = file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
1024 1025 1026 1027

    text_set_mru( tno );


1028
    LOGACC(lt_create_text, tno);
1029
    TRACE2("cached_create_text -> %lu\n", tno);
Per Cederqvist's avatar
Per Cederqvist committed
1030 1031 1032 1033 1034
    
    return tno;
}


1035
EXPORT Text_no
Per Cederqvist's avatar
Per Cederqvist committed
1036 1037
traverse_text(Text_no seed)
{
1038 1039
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1040 1041
    seed++;
    
1042
    while ( seed < next_text_num )
Per Cederqvist's avatar
Per Cederqvist committed
1043
    {
1044 1045 1046 1047
	node = get_text_node (seed);
	if ( node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1048 1049 1050 1051 1052 1053 1054 1055 1056
	seed+