simple-cache.c 48.9 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: simple-cache.c,v 0.57 1996/07/27 11:18:50 byers Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991, 1992, 1993, 1994, 1995  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.57 1996/07/27 11:18:50 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 459 460
    {
	restart_kom("mark_text_as_changed(%d): nonexistent.\n", text_no);
    }

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 517 518 519
    TRACE2("cached_get_person_stat %d\n", person);

    if ( person == 0 )
    {
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
520

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

527 528
    node = get_pers_node (person);

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

535 536
    LOGACC(lt_pers_stat, person);

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

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

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

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


/*
 * Conference-related calls
 */
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578


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);
    }
}


579 580 581 582 583 584 585 586 587
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;
}

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

    return s;
}


600 601 602 603 604 605
/*
 * 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
606 607 608 609
cached_create_conf (String  name)
{
    Conference * conf_c;
    Conf_no	 conf_no;
610
    Cache_node  *node;
Per Cederqvist's avatar
Per Cederqvist committed
611 612 613 614 615 616 617 618 619 620 621 622 623

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

    if ( next_free_num >= MAX_CONF )
    {
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;

624 625 626 627 628 629 630 631 632
    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
633 634
    conf_set_mru(conf_no);    

635
    zero_init_cache_node (pers_mcb, conf_no);
Per Cederqvist's avatar
Per Cederqvist committed
636 637 638 639 640 641
    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);

642
    TRACE2("Created conference number %d\n", conf_no);
643 644 645

    LOGACC(lt_create_conf, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
646 647 648 649 650 651 652
    return conf_no;
}


extern Success
cached_delete_conf( Conf_no	conf )
{
653 654
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
655 656 657 658 659
    if ( conf == 0 )
    {
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
660

661 662 663 664 665 666
    if ( conf >= next_free_num )
    {
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

667 668
    node = get_conf_node (conf);

669
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
670 671 672 673 674
    {
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

675 676 677
    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
678

679 680 681
    free_conference(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
682

683 684
    LOGACC(lt_delete_conf, conf);

Per Cederqvist's avatar
Per Cederqvist committed
685 686 687 688 689 690
    return OK;
}

Success
cached_delete_person(Pers_no pers)
{
691 692
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
693 694 695 696 697
    if ( pers == 0 )
    {
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
698

699 700 701
    if ( pers >= next_free_num )
    {
	log("cached_delete_person(%lu): next_free_num == %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
702
	    (unsigned long)pers, (unsigned long)next_free_num);
703 704 705 706
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

707 708 709
    node = get_pers_node (pers);

    if ( pers >= next_free_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
710
    {
Per Cederqvist's avatar
Per Cederqvist committed
711
	log("cached_delete_person(): attempt to delete void person.\n");
Per Cederqvist's avatar
Per Cederqvist committed
712 713 714 715
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

716
    if ( node->lock_cnt > 0 )
717
	log("cached_delete_pers(%lu): lock_cnt === %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
718
	    (unsigned long)pers, (unsigned long)node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
719

720 721
    LOGACC(lt_delete_pers, pers);

722 723 724
    free_person (node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
725 726 727 728 729 730
    return OK;
}

Success
cached_delete_text(Text_no text)
{
731 732
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
733 734 735 736 737
    if ( text == 0 )
    {
	kom_errno = KOM_TEXT_ZERO;
	return FAILURE;
    }
738 739 740 741 742

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL
	|| node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
743
    {
Per Cederqvist's avatar
Per Cederqvist committed
744
	log("cached_delete_text(): attempt to delete void text %d.\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
745 746 747 748
	kom_errno = KOM_NO_SUCH_TEXT;
	return FAILURE;
    }

749
    if ( node->lock_cnt > 0 )
Per Cederqvist's avatar
Per Cederqvist committed
750
	log("cached_delete_text(%d): lock_cnt === %d\n",
751
	    text, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
752 753


754 755 756
    free_text_stat(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
757

758 759 760
#ifdef LOGACCESSES
    if (garb_running)
    {
761
	LOGACC(lt_garb_text, text);
762 763
    }
    else
764
	LOGACC(lt_delete_text, text);
765
#endif
Per Cederqvist's avatar
Per Cederqvist committed
766 767 768 769 770
    return OK;
}


extern Conference *
771
cached_get_conf_stat (Conf_no   conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
772
{
773 774
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
775 776 777 778 779 780 781
    TRACE2("cached_get_conf_stat %d\n", conf_no);

    if ( conf_no == 0 )
    {
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
782 783 784 785

    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
786 787 788 789 790
    {
	kom_errno = KOM_UNDEF_CONF;
	return NULL;
    }

791 792
    LOGACC(lt_conf_stat, conf_no);

793
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
794
    {
795
	conf_set_mru (conf_no);
796
	++conf_mcb->hits;
797
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
798 799
    }

800
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
801
    {
802
	node->ptr = copy_conference (node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
803
	conf_set_mru (conf_no);
804
	++conf_mcb->hits;
805
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
806 807
    }

808
    node->ptr = read_conference(file_a, node->pos, node->size);
809
    ++conf_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
810 811

    conf_set_mru (conf_no);
812
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
813 814 815 816 817 818 819 820
}

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
821 822 823 824 825 826 827
    Cache_node *node;

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

    node = get_conf_node (conf_no);

828 829 830 831
    if (node != NULL && node->s.exists != 0)
      return TRUE;
    else
      return FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
}

    
/*
 * Calls to handle texts
 */

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

848
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
849 850 851 852 853

    if ( (t_stat = cached_get_text_stat (text)) == NULL )
	return EMPTY_STRING;
    else
    {
854
	LOGACC(lt_text_mass, text);
Per Cederqvist's avatar
Per Cederqvist committed
855 856 857 858 859 860 861
	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 )
	{
Per Cederqvist's avatar
Per Cederqvist committed
862
	    log("WARNING: cached_get_text: premature end on text %d\n",
Per Cederqvist's avatar
Per Cederqvist committed
863 864 865 866 867 868 869 870 871 872 873 874
		text);
	    return EMPTY_STRING;
	}
		    
	return the_string;
    }
}


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

877
    TRACE2("cached_get_text_stat(%lu);  next_text_num == ", text);
Per Cederqvist's avatar
Per Cederqvist committed
878 879 880 881 882 883 884
    TRACE2("%d\n", next_text_num);

    if ( text == 0 )
    {
	kom_errno = KOM_TEXT_ZERO;
	return NULL;
    }
885 886 887 888

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
889 890 891 892 893 894
    {
	TRACE1("cached_get_text_stat: no such text.\n");
	kom_errno = KOM_NO_SUCH_TEXT;
	return NULL;
    }

895 896
    LOGACC(lt_text_stat, text);

897
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
898 899 900
    {
	TRACE1("Found in ptr.\n");
	text_set_mru( text );
901
	++text_mcb->hits;
902
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
903 904
    }

905
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
906 907
    {
	TRACE1("Found in snap_shot\n");
908
	node->ptr = copy_text_stat(node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
909
	text_set_mru (text);
910
	++text_mcb->hits;
911
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
912 913 914
    }

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

    text_set_mru (text);
918
    ++text_mcb->misses;
919
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
920 921 922 923 924 925
}



/*
 * The text is set up with an empty misc-field. The misc field is
926
 * then initialized by create_text.
Per Cederqvist's avatar
Per Cederqvist committed
927 928 929
 */

extern Text_no
930
cached_create_text(const String message)
Per Cederqvist's avatar
Per Cederqvist committed
931 932
{
    Text_no tno;
933
    Cache_node *node;
934
    long file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
935 936 937

    tno = next_text_num++;

938
    TRACE2("cached_create_text (len=%lu)\n", message.len);
Per Cederqvist's avatar
Per Cederqvist committed
939 940 941 942 943 944 945 946 947

    if ( tno >= MAX_TEXT )
    {
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	next_text_num = MAX_TEXT;
	
	return 0;
    }

948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
    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)
	    log("WARNING: cached_create_text: Couldn't write text %d: %s\n",
		tno, strerror(errno));
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fflush(text_file) != 0)
    {
	if (errno != ENOSPC)
	    log("WARNING: cached_create_text: Couldn't fflush text %d: %s\n",
		tno, strerror(errno));
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fsync(fileno(text_file)) != 0)
    {
	if (errno != ENOSPC)
	    log("WARNING: cached_create_text: Couldn't fsync text %d: %s\n",
		tno, strerror(errno));
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

987 988
    create_cache_node(text_mcb, tno);
    node = get_text_node (tno);
Per Cederqvist's avatar
Per Cederqvist committed
989

990
    if ( node == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
991
	restart_kom("cached_create_text(): couldn't create cache-node.\n");
992 993 994 995 996 997 998 999 1000
    
    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;
1001
    ((Text_stat *)node->ptr)->file_pos = file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
1002 1003 1004 1005

    text_set_mru( tno );


1006
    LOGACC(lt_create_text, tno);
1007
    TRACE2("cached_create_text -> %lu\n", tno);
Per Cederqvist's avatar
Per Cederqvist committed
1008 1009 1010 1011 1012
    
    return tno;
}


1013
EXPORT Text_no
Per Cederqvist's avatar
Per Cederqvist committed
1014 1015
traverse_text(Text_no seed)
{
1016 1017
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1018 1019
    seed++;
    
1020
    while ( seed < next_text_num )
Per Cederqvist's avatar
Per Cederqvist committed
1021
    {
1022 1023 1024 1025
	node = get_text_node (seed);
	if ( node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1026 1027 1028 1029 1030 1031 1032 1033 1034
	seed++;
    }
    
    return (seed >= next_text_num) ? 0 : seed ;
}

Pers_no
traverse_person(Pers_no seed)
{
1035 1036
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1037 1038
    seed++;

1039
    while ( seed < next_free_num )
Per Cederqvist's avatar
Per Cederqvist committed
1040
    {
1041 1042 1043 1044
	node = get_pers_node (seed);
	if (node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1045 1046 1047 1048 1049 1050 1051 1052 1053
	seed++;
    }

    return (seed >= next_free_num) ? 0 : seed ;
}

Conf_no
traverse_conference(Conf_no seed)
{
1054 1055
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1056 1057
    seed++;
    
1058
    while ( seed < next_free_num )
Per Cederqvist's avatar
Per Cederqvist committed
1059
    {
1060 1061 1062 1063
	node = get_conf_node (seed);
	if (node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
	seed++;
    }

    return (seed >= next_free_num) ? 0 : seed ;
}

extern Garb_nice
cached_get_garb_nice (Conf_no conf_no)
{
    return small_conf_arr [ conf_no ]->nice;
}

1076 1077 1078 1079 1080
extern String
cached_get_name (Conf_no conf_no)
{
    return small_conf_arr [ conf_no ]->name;
}
Per Cederqvist's avatar
Per Cederqvist committed
1081 1082 1083 1084

extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no)
{
1085 1086
    LOGACC(lt_get_highest, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
1087 1088 1089
    return small_conf_arr[ conf_no ]->highest_local_no;
}

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
extern Small_conf *
cached_get_small_conf_stat (Conf_no conf_no)
{
    TRACE2("cached_get_small_conf_stat %d\n", conf_no);

    if (conf_no == 0)
    {
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
    
    if (conf_no >= next_free_num ||
	small_conf_arr[conf_no] == NULL)
    {
	kom_errno = KOM_UNDEF_CONF;
	return NULL;
    }
    return small_conf_arr[conf_no];
}

Per Cederqvist's avatar
Per Cederqvist committed
1110 1111 1112 1113
/* Lock a person struct in memory. Increase a referenc count. */
void
cached_lock_person(Pers_no pers_no)
{
1114 1115
    Cache_node *node;

1116 1117
    LOGACC(lt_lock_pers, pers_no);

1118 1119 1120
    node = get_pers_node(pers_no);
    
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
1121 1122
	restart_kom("cached_lock_person(%d): nonexistent.\n", pers_no);

1123
    if ( node->ptr == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
1124
    {
1125
	Person *pers_stat_ptr;
Per Cederqvist's avatar
Per Cederqvist committed
1126

1127
	pers_stat_ptr = cached_get_person_stat( pers_no );