simple-cache.c 55 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
Per Cederqvist's avatar
Per Cederqvist committed
2
 * $Id: simple-cache.c,v 0.73 1999/04/03 22:16:37 ceder 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
/*
 * 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.
David Byers's avatar
David Byers committed
34
 * Attempt at newer algorithm by byers (FASTSAVE)
Per Cederqvist's avatar
Per Cederqvist committed
35 36
 */

David Byers's avatar
David Byers committed
37 38 39 40 41

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

42
static const char *
Per Cederqvist's avatar
Per Cederqvist committed
43
rcsid = "$Id: simple-cache.c,v 0.73 1999/04/03 22:16:37 ceder Exp $";
44 45
#include "rcs.h"
USE(rcsid);
Per Cederqvist's avatar
Per Cederqvist committed
46

Per Cederqvist's avatar
Per Cederqvist committed
47 48
#include <errno.h>
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
49
#include <sys/types.h>
50 51 52
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
53 54 55
#ifdef HAVE_STRING_H
#  include <string.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
56 57 58 59
#ifndef SEEK_END
#  include <fcntl.h>
#endif
#ifndef SEEK_END
Per Cederqvist's avatar
Per Cederqvist committed
60 61 62
#  define SEEK_SET 0
#  define SEEK_END 2
#endif
Per Cederqvist's avatar
Per Cederqvist committed
63 64
#include <time.h>
#include <setjmp.h>
65 66 67
#ifdef HAVE_STDARG_H
#  include <stdarg.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
68

69
#include "ldifftime.h"
Per Cederqvist's avatar
Per Cederqvist committed
70 71
#include "exp.h"
#include "misc-types.h"
72
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86
#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"
87
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
88 89
#include "connections.h"
#include "send-async.h"
90
#include "param.h"
David Byers's avatar
David Byers committed
91
#include "kom-config.h"
David Byers's avatar
David Byers committed
92
#include "admin.h"
93
#include "unused.h"
94
#include "local-to-global.h"
Per Cederqvist's avatar
Per Cederqvist committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

/*
 * 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 ];
110 111
static Cache_node_mcb	* pers_mcb;
static Cache_node_mcb 	* conf_mcb;
112
static Conf_no		  next_free_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
113

114
static Cache_node_mcb 	* text_mcb;
115
static Text_no		  next_text_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
116 117 118 119 120 121 122

/*
 * 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
123
EXPORT Conf_no       *conf_table  = NULL; /* Used in conference.c. */
Per Cederqvist's avatar
Per Cederqvist committed
124 125 126 127 128


static FILE	*text_file= NULL;
static FILE	*file_a = NULL;	/* Current file. */
static FILE	*file_b = NULL;	/* File under construction. */
David Byers's avatar
David Byers committed
129 130 131
#ifdef FASTSAVE
static FILE     *file_b_r = NULL; /* Read from file under construction */
#endif
Per Cederqvist's avatar
Per Cederqvist committed
132 133 134 135 136

/*
 * Four state variables for the background save.
 */
static enum {
137
    sync_idle,
Per Cederqvist's avatar
Per Cederqvist committed
138 139 140 141 142 143 144 145
    sync_save_conf,
    sync_save_pers,
    sync_save_text,
    sync_error,
    sync_wait,
    sync_ready
} sync_state;

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
/* 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
 */

David Byers's avatar
David Byers committed
161
#ifndef FASTSAVE
162 163 164 165 166
/* sync_next should be split in next_text_to_sync and
   next_conf_to_sync to avoid warnings about the different sizes of
   Conf_no and Text_no.  Since that is indeed done if FASTSAVE is set,
   don't bother doing it in the old code that will anyhow soon be
   replaced. */
167
static unsigned long sync_next;
David Byers's avatar
David Byers committed
168
#endif
Per Cederqvist's avatar
Per Cederqvist committed
169 170 171 172 173 174

static Conf_no highest_conf_no;
static Text_no highest_text_no;

BUGDECL;

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
/* 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)
{
215 216
    extern int putw(int, FILE *);

217 218 219 220 221 222 223 224 225 226 227
    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
228 229 230 231 232 233 234 235 236 237 238

/* 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,
239
	    long UNUSED(size))	/* FIXME: should sanity-check the size */
Per Cederqvist's avatar
Per Cederqvist committed
240 241
{
    Person *p;
David Byers's avatar
David Byers committed
242
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
243 244

    p = alloc_person();
245
    fseek(fp, pos+1, SEEK_SET);	/* Skip 'P' */
David Byers's avatar
David Byers committed
246
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260
    if ( fparse_person(fp, p) != OK )
    {
	free_person(p);
	return NULL;
    }
    else
	return p;
}



static Conference *
read_conference(FILE *fp,
		long pos,
261
		long UNUSED(size)) /* FIXME: should sanity-check the size */
Per Cederqvist's avatar
Per Cederqvist committed
262 263
{
    Conference *c;
David Byers's avatar
David Byers committed
264
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
265 266

    c = alloc_conference();
267
    fseek(fp, pos+1, SEEK_SET);	/* Skip 'C' */
David Byers's avatar
David Byers committed
268
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
269 270 271 272 273 274 275 276 277 278 279 280 281
    if ( fparse_conference(fp, c) != OK )
    {
	free_conference(c);
	return NULL;
    }
    else
	return c;
}
	

static Text_stat *
read_text_stat(FILE *fp,
	       long pos,
282
	       long UNUSED(size)) /* FIXME: should sanity-check the size */
Per Cederqvist's avatar
Per Cederqvist committed
283 284
{
    Text_stat *t;
David Byers's avatar
David Byers committed
285
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
286 287

    t = alloc_text_stat();
288
    fseek(fp, pos+1, SEEK_SET);	/* Skip 'T' */
David Byers's avatar
David Byers committed
289
    dummy = fparse_long(fp);
Per Cederqvist's avatar
Per Cederqvist committed
290 291 292 293 294 295 296 297 298 299
    if ( fparse_text_stat(fp, t) != OK )
    {
	free_text_stat(t);
	return NULL;
    }
    else
	return t;
}

static void
300
pers_set_mru(Pers_no pers_no)
Per Cederqvist's avatar
Per Cederqvist committed
301
{
302
    set_mru(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
303 304 305
}

static void
306
text_set_mru(Text_no text_no)
Per Cederqvist's avatar
Per Cederqvist committed
307
{
308
    set_mru(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
309 310 311
}

static void
312
conf_set_mru(Conf_no conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
313
{
314 315
    set_mru(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
316

317 318 319
static Cache_node *
get_pers_node(Pers_no pers_no)
{
320
    if (pers_no >= next_free_num || pers_no < 1)
321 322
	return NULL;

323
    return get_cache_node(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
324 325 326
}

static void
327
unlink_text_lru (Cache_node *node)
Per Cederqvist's avatar
Per Cederqvist committed
328
{
329
    unlink_lru (node, &text_mcb->lru, &text_mcb->mru);
Per Cederqvist's avatar
Per Cederqvist committed
330 331
}

332 333 334 335 336
static void
unlink_conf_lru (Cache_node *node)
{
    unlink_lru (node, &conf_mcb->lru, &conf_mcb->mru);
}
Per Cederqvist's avatar
Per Cederqvist committed
337 338

static void
339
unlink_pers_lru (Cache_node *node)
Per Cederqvist's avatar
Per Cederqvist committed
340
{
341 342
    unlink_lru (node, &pers_mcb->lru, &pers_mcb->mru);
}
Per Cederqvist's avatar
Per Cederqvist committed
343

344 345 346
static Cache_node *
get_conf_node(Conf_no conf_no)
{
347
    if (conf_no >= next_free_num || conf_no < 1)
348 349
	return NULL;

350 351
    return get_cache_node(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
352

353 354 355
static Cache_node *
get_text_node(Text_no text_no)
{
356
    if (text_no >= next_text_num || text_no < 1)
357 358
	return NULL;

359
    return get_cache_node(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
}

	
/*
 * 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);
391 392 393 394 395

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

396 397
    LOGACC(lt_get_conf_type, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
398 399 400
    return small_conf_arr [ conf_no ]->type;
}

401 402 403 404 405 406 407 408 409
/*
 * 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
410 411 412 413 414 415 416 417

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

void
mark_person_as_changed(Pers_no	pers_no)
{
418 419 420 421
    Cache_node *node;

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

426
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
427 428 429
    pers_set_mru( pers_no );
}

430 431 432 433 434 435 436 437 438 439 440
/*
 * 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
441 442 443 444

void
mark_conference_as_changed(Conf_no	conf_no)
{
445
    Cache_node *node;
446
    Conference *conf_c;
447 448 449

    node = get_conf_node (conf_no);

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

454
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
455
    conf_set_mru( conf_no );
456 457 458

    conf_c = (Conference *) node->ptr;

Per Cederqvist's avatar
Per Cederqvist committed
459
    small_conf_arr[ conf_no ]->highest_local_no
460
	= l2g_first_appendable_key(&conf_c->texts) - 1;
461 462 463

    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
464 465 466 467 468
}

void
mark_text_as_changed( Text_no text_no )
{
469 470 471 472
    Cache_node *node;

    node = get_text_node (text_no);

473
    TRACE2("Text %lu is changed.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
474
    if ( text_no < 1 || text_no >= next_text_num
475
	|| node == NULL || node->s.exists == 0)
Per Cederqvist's avatar
Per Cederqvist committed
476
    {
477
	restart_kom("mark_text_as_changed(%lu): nonexistent.\n", text_no);
Per Cederqvist's avatar
Per Cederqvist committed
478 479
    }

480 481
    node->s.dirty = 1;
    text_set_mru (text_no);
Per Cederqvist's avatar
Per Cederqvist committed
482 483 484 485 486 487 488 489 490 491 492 493
}    



/*
 * Person-related calls
 */


extern Success
cached_create_person( Pers_no person )
{
494 495
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
496 497 498 499 500 501 502 503
    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);
    }

504
    if ( get_pers_node(person) != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
505 506 507 508 509
    {
	restart_kom("cached_create_person(%d): Person existed.\n",
		    person);
    }

510 511 512 513 514
    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");
515

516 517 518
    node->ptr = alloc_person();
    node->s.dirty = 1;
    node->s.exists = 1;
Per Cederqvist's avatar
Per Cederqvist committed
519
    pers_set_mru( person );
520 521 522

    LOGACC(lt_create_pers, person);

Per Cederqvist's avatar
Per Cederqvist committed
523 524 525 526 527 528 529
    return OK;
}


extern Person *
cached_get_person_stat( Pers_no	person )
{
530 531
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
532 533 534 535
    TRACE2("cached_get_person_stat %d\n", person);

    if ( person == 0 )
    {
536
        err_stat = 0;
Per Cederqvist's avatar
Per Cederqvist committed
537 538 539
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
540

541 542
    if ( person >= next_free_num )
    {
543
        err_stat = person;
544 545 546 547
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

548 549
    node = get_pers_node (person);

550
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
551
    {
552
        err_stat = person;
Per Cederqvist's avatar
Per Cederqvist committed
553 554 555 556
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

557 558
    LOGACC(lt_pers_stat, person);

559
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
560 561
    {
	pers_set_mru( person );
562
	++pers_mcb->hits;
563
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
564 565
    }

566
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
567
    {
568
	node->ptr = copy_person (node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
569
	pers_set_mru (person);
570
	++pers_mcb->hits;
571
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
572 573
    }

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

576
    ++pers_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
577
    pers_set_mru (person);
578
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
579 580 581 582 583 584
}


/*
 * Conference-related calls
 */
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600


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


601 602 603 604 605 606 607 608 609
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;
}

610 611 612 613 614
static Small_conf *
alloc_small_conf(void)
{
    Small_conf *s;
    s = smalloc(sizeof(Small_conf));
615
    init_small_conf(s);
616 617 618 619 620 621
    ++no_of_allocated_small_confs;

    return s;
}


622 623 624 625 626 627
/*
 * 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
628 629 630 631
cached_create_conf (String  name)
{
    Conference * conf_c;
    Conf_no	 conf_no;
632
    Cache_node  *node;
Per Cederqvist's avatar
Per Cederqvist committed
633 634 635 636 637 638 639

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

    if ( next_free_num >= MAX_CONF )
    {
640
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
641 642 643 644 645 646
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;

647 648 649 650 651 652 653 654 655
    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
656 657
    conf_set_mru(conf_no);    

658
    zero_init_cache_node (pers_mcb, conf_no);
Per Cederqvist's avatar
Per Cederqvist committed
659 660 661 662 663 664
    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);

665
    TRACE2("Created conference number %d\n", conf_no);
666 667 668

    LOGACC(lt_create_conf, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
669 670 671 672 673 674 675
    return conf_no;
}


extern Success
cached_delete_conf( Conf_no	conf )
{
676 677
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
678 679
    if ( conf == 0 )
    {
680
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
681 682 683
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
684

685 686
    if ( conf >= next_free_num )
    {
687
        err_stat = conf;
688 689 690 691
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

692 693
    node = get_conf_node (conf);

694
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
695
    {
696
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
697 698 699 700
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

701 702 703
    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
704

705
    s_clear( &small_conf_arr[conf]->name );
706 707 708
    free_conference(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
709

710 711
    LOGACC(lt_delete_conf, conf);

712
    build_matching_info();
Per Cederqvist's avatar
Per Cederqvist committed
713 714 715 716 717 718
    return OK;
}

Success
cached_delete_person(Pers_no pers)
{
719 720
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
721 722
    if ( pers == 0 )
    {
723
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
724 725 726
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
727

728 729 730
    if ( pers >= next_free_num )
    {
	log("cached_delete_person(%lu): next_free_num == %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
731
	    (unsigned long)pers, (unsigned long)next_free_num);
732
        err_stat = pers;
733 734 735 736
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

737 738 739
    node = get_pers_node (pers);

    if ( pers >= next_free_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
740
    {
Per Cederqvist's avatar
Per Cederqvist committed
741
	log("cached_delete_person(): attempt to delete void person.\n");
742
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
743 744 745 746
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

747
    if ( node->lock_cnt > 0 )
748
	log("cached_delete_pers(%lu): lock_cnt === %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
749
	    (unsigned long)pers, (unsigned long)node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
750

751 752
    LOGACC(lt_delete_pers, pers);

753 754 755
    free_person (node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
756 757 758 759 760 761
    return OK;
}

Success
cached_delete_text(Text_no text)
{
762 763
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
764 765
    if ( text == 0 )
    {
766
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
767 768 769
	kom_errno = KOM_TEXT_ZERO;
	return FAILURE;
    }
770 771 772 773 774

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL
	|| node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
775
    {
776
	log("cached_delete_text(): attempt to delete void text %lu.\n", text);
777
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
778 779 780 781
	kom_errno = KOM_NO_SUCH_TEXT;
	return FAILURE;
    }

782
    if ( node->lock_cnt > 0 )
783
	log("cached_delete_text(%lu): lock_cnt === %d\n",
784
	    text, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
785 786


787 788 789
    free_text_stat(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
790

791 792 793
#ifdef LOGACCESSES
    if (garb_running)
    {
794
	LOGACC(lt_garb_text, text);
795 796
    }
    else
797
	LOGACC(lt_delete_text, text);
798
#endif
Per Cederqvist's avatar
Per Cederqvist committed
799 800 801 802 803
    return OK;
}


extern Conference *
804
cached_get_conf_stat (Conf_no   conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
805
{
806 807
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
808 809 810 811
    TRACE2("cached_get_conf_stat %d\n", conf_no);

    if ( conf_no == 0 )
    {
812
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
813 814 815
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
816 817 818 819

    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
820
    {
821
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
822 823 824 825
	kom_errno = KOM_UNDEF_CONF;
	return NULL;
    }

826 827
    LOGACC(lt_conf_stat, conf_no);

828
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
829
    {
830
	conf_set_mru (conf_no);
831
	++conf_mcb->hits;
832
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
833 834
    }

835
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
836
    {
837
	node->ptr = copy_conference (node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
838
	conf_set_mru (conf_no);
839
	++conf_mcb->hits;
840
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
841 842
    }

843
    node->ptr = read_conference(file_a, node->pos, node->size);
844
    ++conf_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
845 846

    conf_set_mru (conf_no);
847
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
848 849 850 851 852 853 854 855
}

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
856 857 858 859 860
    Cache_node *node;

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

861 862 863 864 865
    /* FIXME: it is probably faster to use
       return small_conf_arr[conf_no] != NULL ? TRUE : FALSE
       but that requires changes to cached_delete_conf.
     */

866 867
    node = get_conf_node (conf_no);

868 869 870 871
    if (node != NULL && node->s.exists != 0)
      return TRUE;
    else
      return FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
}

    
/*
 * Calls to handle texts
 */

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

888
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
889 890 891 892 893

    if ( (t_stat = cached_get_text_stat (text)) == NULL )
	return EMPTY_STRING;
    else
    {
894
	LOGACC(lt_text_mass, text);
Per Cederqvist's avatar
Per Cederqvist committed
895 896 897 898 899
	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)
David Byers's avatar
David Byers committed
900
	    != (size_t)the_string.len )
Per Cederqvist's avatar
Per Cederqvist committed
901
	{
902
	    log("WARNING: cached_get_text: premature end on text %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
903 904 905 906 907 908 909 910 911 912 913 914
		text);
	    return EMPTY_STRING;
	}
		    
	return the_string;
    }
}


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

917
    TRACE2("cached_get_text_stat(%lu);  next_text_num == ", text);
918
    TRACE2("%lu\n", (unsigned long)next_text_num);
Per Cederqvist's avatar
Per Cederqvist committed
919 920 921

    if ( text == 0 )
    {
922
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
923 924 925
	kom_errno = KOM_TEXT_ZERO;
	return NULL;
    }
926 927 928 929

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
930 931
    {
	TRACE1("cached_get_text_stat: no such text.\n");
932
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
933 934 935 936
	kom_errno = KOM_NO_SUCH_TEXT;
	return NULL;
    }

937 938
    LOGACC(lt_text_stat, text);

939
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
940 941 942
    {
	TRACE1("Found in ptr.\n");
	text_set_mru( text );
943
	++text_mcb->hits;
944
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
945 946
    }

947
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
948 949
    {
	TRACE1("Found in snap_shot\n");
950
	node->ptr = copy_text_stat(node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
951
	text_set_mru (text);
952
	++text_mcb->hits;
953
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
954 955 956
    }

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

    text_set_mru (text);
960
    ++text_mcb->misses;
961
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
962 963 964 965 966 967
}



/*
 * The text is set up with an empty misc-field. The misc field is
968
 * then initialized by create_text.
Per Cederqvist's avatar
Per Cederqvist committed
969 970 971
 */

extern Text_no
972
cached_create_text(const String message)
Per Cederqvist's avatar
Per Cederqvist committed
973 974
{
    Text_no tno;
975
    Cache_node *node;
976
    long file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
977 978 979

    tno = next_text_num++;

980
    TRACE2("cached_create_text (len=%lu)\n", message.len);
Per Cederqvist's avatar
Per Cederqvist committed
981 982 983

    if ( tno >= MAX_TEXT )
    {
984
        err_stat = tno;
Per Cederqvist's avatar
Per Cederqvist committed
985 986 987 988 989 990
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	next_text_num = MAX_TEXT;
	
	return 0;
    }

991 992 993 994 995 996 997 998 999
    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);

David Byers's avatar
David Byers committed
1000 1001
    if (fwrite(message.string, 1, message.len, text_file)
        != (size_t)message.len)
1002 1003
    {
	if (errno != ENOSPC)
1004
	    log("WARNING: cached_create_text: Couldn't write text %lu: %s\n",
1005
		tno, strerror(errno));
1006
        err_stat = 0;
1007 1008 1009 1010 1011 1012 1013 1014
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fflush(text_file) != 0)
    {
	if (errno != ENOSPC)
1015
	    log("WARNING: cached_create_text: Couldn't fflush text %lu: %s\n",
1016
		tno, strerror(errno));
1017
        err_stat = 0;