simple-cache.c 54.9 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: simple-cache.c,v 0.70 1998/12/20 19:50:16 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
 */

37
static const char *
38
rcsid = "$Id: simple-cache.c,v 0.70 1998/12/20 19:50:16 ceder Exp $";
39 40
#include "rcs.h"
USE(rcsid);
Per Cederqvist's avatar
Per Cederqvist committed
41

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

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

/*
 * 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 ];
105 106
static Cache_node_mcb	* pers_mcb;
static Cache_node_mcb 	* conf_mcb;
107
static Conf_no		  next_free_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
108

109
static Cache_node_mcb 	* text_mcb;
110
static Text_no		  next_text_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
111 112 113 114 115 116 117

/*
 * 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
118
EXPORT Conf_no       *conf_table  = NULL; /* Used in conference.c. */
Per Cederqvist's avatar
Per Cederqvist committed
119 120 121 122 123


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
124 125 126
#ifdef FASTSAVE
static FILE     *file_b_r = NULL; /* Read from file under construction */
#endif
Per Cederqvist's avatar
Per Cederqvist committed
127 128 129 130 131

/*
 * Four state variables for the background save.
 */
static enum {
132
    sync_idle,
Per Cederqvist's avatar
Per Cederqvist committed
133 134 135 136 137 138 139 140
    sync_save_conf,
    sync_save_pers,
    sync_save_text,
    sync_error,
    sync_wait,
    sync_ready
} sync_state;

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
/* 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
156
#ifndef FASTSAVE
157 158 159 160 161
/* 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. */
Per Cederqvist's avatar
Per Cederqvist committed
162
static long sync_next;
David Byers's avatar
David Byers committed
163
#endif
Per Cederqvist's avatar
Per Cederqvist committed
164 165 166 167 168 169

static Conf_no highest_conf_no;
static Text_no highest_text_no;

BUGDECL;

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 196 197 198 199 200 201 202 203 204 205 206 207 208 209
/* 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)
{
210 211
    extern int putw(int, FILE *);

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

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



static Conference *
read_conference(FILE *fp,
		long pos,
256
		long UNUSED(size)) /* FIXME: should sanity-check the size */
Per Cederqvist's avatar
Per Cederqvist committed
257 258
{
    Conference *c;
David Byers's avatar
David Byers committed
259
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
260 261 262

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

static Text_stat *
read_text_stat(FILE *fp,
	       long pos,
277
	       long UNUSED(size)) /* FIXME: should sanity-check the size */
Per Cederqvist's avatar
Per Cederqvist committed
278 279
{
    Text_stat *t;
David Byers's avatar
David Byers committed
280
    long dummy;
Per Cederqvist's avatar
Per Cederqvist committed
281 282 283

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

static void
295
pers_set_mru(Pers_no pers_no)
Per Cederqvist's avatar
Per Cederqvist committed
296
{
297
    set_mru(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
298 299 300
}

static void
301
text_set_mru(Text_no text_no)
Per Cederqvist's avatar
Per Cederqvist committed
302
{
303
    set_mru(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
304 305 306
}

static void
307
conf_set_mru(Conf_no conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
308
{
309 310
    set_mru(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
311

312 313 314
static Cache_node *
get_pers_node(Pers_no pers_no)
{
315
    if (pers_no >= next_free_num || pers_no < 1)
316 317
	return NULL;

318
    return get_cache_node(pers_mcb, pers_no);
Per Cederqvist's avatar
Per Cederqvist committed
319 320 321
}

static void
322
unlink_text_lru (Cache_node *node)
Per Cederqvist's avatar
Per Cederqvist committed
323
{
324
    unlink_lru (node, &text_mcb->lru, &text_mcb->mru);
Per Cederqvist's avatar
Per Cederqvist committed
325 326
}

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

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

339 340 341
static Cache_node *
get_conf_node(Conf_no conf_no)
{
342
    if (conf_no >= next_free_num || conf_no < 1)
343 344
	return NULL;

345 346
    return get_cache_node(conf_mcb, conf_no);
}
Per Cederqvist's avatar
Per Cederqvist committed
347

348 349 350
static Cache_node *
get_text_node(Text_no text_no)
{
351
    if (text_no >= next_text_num || text_no < 1)
352 353
	return NULL;

354
    return get_cache_node(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
355 356 357 358 359 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
}

	
/*
 * 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);
386 387 388 389 390

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

391 392
    LOGACC(lt_get_conf_type, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
393 394 395
    return small_conf_arr [ conf_no ]->type;
}

396 397 398 399 400 401 402 403 404
/*
 * 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
405 406 407 408 409 410 411 412

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

void
mark_person_as_changed(Pers_no	pers_no)
{
413 414 415 416
    Cache_node *node;

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

421
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
422 423 424
    pers_set_mru( pers_no );
}

425 426 427 428 429 430 431 432 433 434 435
/*
 * 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
436 437 438 439

void
mark_conference_as_changed(Conf_no	conf_no)
{
440
    Cache_node *node;
441
    Conference *conf_c;
442 443 444

    node = get_conf_node (conf_no);

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

449
    node->s.dirty = 1;
Per Cederqvist's avatar
Per Cederqvist committed
450
    conf_set_mru( conf_no );
451 452 453

    conf_c = (Conference *) node->ptr;

Per Cederqvist's avatar
Per Cederqvist committed
454
    small_conf_arr[ conf_no ]->highest_local_no
455
	= l2g_first_appendable_key(&conf_c->texts) - 1;
456 457 458

    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
459 460 461 462 463
}

void
mark_text_as_changed( Text_no text_no )
{
464 465 466 467
    Cache_node *node;

    node = get_text_node (text_no);

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

475 476
    node->s.dirty = 1;
    text_set_mru (text_no);
Per Cederqvist's avatar
Per Cederqvist committed
477 478 479 480 481 482 483 484 485 486 487 488
}    



/*
 * Person-related calls
 */


extern Success
cached_create_person( Pers_no person )
{
489 490
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
491 492 493 494 495 496 497 498
    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);
    }

499
    if ( get_pers_node(person) != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
500 501 502 503 504
    {
	restart_kom("cached_create_person(%d): Person existed.\n",
		    person);
    }

505 506 507 508 509
    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");
510

511 512 513
    node->ptr = alloc_person();
    node->s.dirty = 1;
    node->s.exists = 1;
Per Cederqvist's avatar
Per Cederqvist committed
514
    pers_set_mru( person );
515 516 517

    LOGACC(lt_create_pers, person);

Per Cederqvist's avatar
Per Cederqvist committed
518 519 520 521 522 523 524
    return OK;
}


extern Person *
cached_get_person_stat( Pers_no	person )
{
525 526
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
527 528 529 530
    TRACE2("cached_get_person_stat %d\n", person);

    if ( person == 0 )
    {
531
        err_stat = 0;
Per Cederqvist's avatar
Per Cederqvist committed
532 533 534
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
535

536 537
    if ( person >= next_free_num )
    {
538
        err_stat = person;
539 540 541 542
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

543 544
    node = get_pers_node (person);

545
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
546
    {
547
        err_stat = person;
Per Cederqvist's avatar
Per Cederqvist committed
548 549 550 551
	kom_errno = KOM_UNDEF_PERS;
	return NULL;
    }

552 553
    LOGACC(lt_pers_stat, person);

554
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
555 556
    {
	pers_set_mru( person );
557
	++pers_mcb->hits;
558
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
559 560
    }

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

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

571
    ++pers_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
572
    pers_set_mru (person);
573
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
574 575 576 577 578 579
}


/*
 * Conference-related calls
 */
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595


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


596 597 598 599 600 601 602 603 604
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;
}

605 606 607 608 609
static Small_conf *
alloc_small_conf(void)
{
    Small_conf *s;
    s = smalloc(sizeof(Small_conf));
610
    init_small_conf(s);
611 612 613 614 615 616
    ++no_of_allocated_small_confs;

    return s;
}


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

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

    if ( next_free_num >= MAX_CONF )
    {
635
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
636 637 638 639 640 641
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;

642 643 644 645 646 647 648 649 650
    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
651 652
    conf_set_mru(conf_no);    

653
    zero_init_cache_node (pers_mcb, conf_no);
Per Cederqvist's avatar
Per Cederqvist committed
654 655 656 657 658 659
    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);

660
    TRACE2("Created conference number %d\n", conf_no);
661 662 663

    LOGACC(lt_create_conf, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
664 665 666 667 668 669 670
    return conf_no;
}


extern Success
cached_delete_conf( Conf_no	conf )
{
671 672
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
673 674
    if ( conf == 0 )
    {
675
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
676 677 678
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
679

680 681
    if ( conf >= next_free_num )
    {
682
        err_stat = conf;
683 684 685 686
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

687 688
    node = get_conf_node (conf);

689
    if ( node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
690
    {
691
        err_stat = conf;
Per Cederqvist's avatar
Per Cederqvist committed
692 693 694 695
	kom_errno = KOM_UNDEF_CONF;
	return FAILURE;
    }

696 697 698
    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
699

700
    s_clear( &small_conf_arr[conf]->name );
701 702 703
    free_conference(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
704

705 706
    LOGACC(lt_delete_conf, conf);

707
    build_matching_info();
Per Cederqvist's avatar
Per Cederqvist committed
708 709 710 711 712 713
    return OK;
}

Success
cached_delete_person(Pers_no pers)
{
714 715
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
716 717
    if ( pers == 0 )
    {
718
        err_stat = pers;
Per Cederqvist's avatar
Per Cederqvist committed
719 720 721
	kom_errno = KOM_CONF_ZERO;
	return FAILURE;
    }
722

723 724 725
    if ( pers >= next_free_num )
    {
	log("cached_delete_person(%lu): next_free_num == %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
726
	    (unsigned long)pers, (unsigned long)next_free_num);
727
        err_stat = pers;
728 729 730 731
	kom_errno = KOM_UNDEF_PERS;
	return FAILURE;
    }

732 733 734
    node = get_pers_node (pers);

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

742
    if ( node->lock_cnt > 0 )
743
	log("cached_delete_pers(%lu): lock_cnt === %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
744
	    (unsigned long)pers, (unsigned long)node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
745

746 747
    LOGACC(lt_delete_pers, pers);

748 749 750
    free_person (node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
751 752 753 754 755 756
    return OK;
}

Success
cached_delete_text(Text_no text)
{
757 758
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
759 760
    if ( text == 0 )
    {
761
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
762 763 764
	kom_errno = KOM_TEXT_ZERO;
	return FAILURE;
    }
765 766 767 768 769

    node = get_text_node (text);

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

777
    if ( node->lock_cnt > 0 )
778
	log("cached_delete_text(%lu): lock_cnt === %d\n",
779
	    text, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
780 781


782 783 784
    free_text_stat(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
785

786 787 788
#ifdef LOGACCESSES
    if (garb_running)
    {
789
	LOGACC(lt_garb_text, text);
790 791
    }
    else
792
	LOGACC(lt_delete_text, text);
793
#endif
Per Cederqvist's avatar
Per Cederqvist committed
794 795 796 797 798
    return OK;
}


extern Conference *
799
cached_get_conf_stat (Conf_no   conf_no)
Per Cederqvist's avatar
Per Cederqvist committed
800
{
801 802
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
803 804 805 806
    TRACE2("cached_get_conf_stat %d\n", conf_no);

    if ( conf_no == 0 )
    {
807
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
808 809 810
	kom_errno = KOM_CONF_ZERO;
	return NULL;
    }
811 812 813 814

    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
815
    {
816
        err_stat = conf_no;
Per Cederqvist's avatar
Per Cederqvist committed
817 818 819 820
	kom_errno = KOM_UNDEF_CONF;
	return NULL;
    }

821 822
    LOGACC(lt_conf_stat, conf_no);

823
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
824
    {
825
	conf_set_mru (conf_no);
826
	++conf_mcb->hits;
827
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
828 829
    }

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

838
    node->ptr = read_conference(file_a, node->pos, node->size);
839
    ++conf_mcb->misses;
Per Cederqvist's avatar
Per Cederqvist committed
840 841

    conf_set_mru (conf_no);
842
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
843 844 845 846 847 848 849 850
}

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
851 852 853 854 855
    Cache_node *node;

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

856 857 858 859 860
    /* FIXME: it is probably faster to use
       return small_conf_arr[conf_no] != NULL ? TRUE : FALSE
       but that requires changes to cached_delete_conf.
     */

861 862
    node = get_conf_node (conf_no);

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

    
/*
 * Calls to handle texts
 */

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

883
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
884 885 886 887 888

    if ( (t_stat = cached_get_text_stat (text)) == NULL )
	return EMPTY_STRING;
    else
    {
889
	LOGACC(lt_text_mass, text);
Per Cederqvist's avatar
Per Cederqvist committed
890 891 892 893 894 895 896
	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 )
	{
897
	    log("WARNING: cached_get_text: premature end on text %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
898 899 900 901 902 903 904 905 906 907 908 909
		text);
	    return EMPTY_STRING;
	}
		    
	return the_string;
    }
}


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

912
    TRACE2("cached_get_text_stat(%lu);  next_text_num == ", text);
913
    TRACE2("%lu\n", (unsigned long)next_text_num);
Per Cederqvist's avatar
Per Cederqvist committed
914 915 916

    if ( text == 0 )
    {
917
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
918 919 920
	kom_errno = KOM_TEXT_ZERO;
	return NULL;
    }
921 922 923 924

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
925 926
    {
	TRACE1("cached_get_text_stat: no such text.\n");
927
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
928 929 930 931
	kom_errno = KOM_NO_SUCH_TEXT;
	return NULL;
    }

932 933
    LOGACC(lt_text_stat, text);

934
    if ( node->ptr != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
935 936 937
    {
	TRACE1("Found in ptr.\n");
	text_set_mru( text );
938
	++text_mcb->hits;
939
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
940 941
    }

942
    if ( node->snap_shot != NULL )
Per Cederqvist's avatar
Per Cederqvist committed
943 944
    {
	TRACE1("Found in snap_shot\n");
945
	node->ptr = copy_text_stat(node->snap_shot);
Per Cederqvist's avatar
Per Cederqvist committed
946
	text_set_mru (text);
947
	++text_mcb->hits;
948
	return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
949 950 951
    }

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

    text_set_mru (text);
955
    ++text_mcb->misses;
956
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
957 958 959 960 961 962
}



/*
 * The text is set up with an empty misc-field. The misc field is
963
 * then initialized by create_text.
Per Cederqvist's avatar
Per Cederqvist committed
964 965 966
 */

extern Text_no
967
cached_create_text(const String message)
Per Cederqvist's avatar
Per Cederqvist committed
968 969
{
    Text_no tno;
970
    Cache_node *node;
971
    long file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
972 973 974

    tno = next_text_num++;

975
    TRACE2("cached_create_text (len=%lu)\n", message.len);
Per Cederqvist's avatar
Per Cederqvist committed
976 977 978

    if ( tno >= MAX_TEXT )
    {
979
        err_stat = tno;
Per Cederqvist's avatar
Per Cederqvist committed
980 981 982 983 984 985
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	next_text_num = MAX_TEXT;
	
	return 0;
    }

986 987 988 989 990 991 992 993 994 995 996 997
    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)
998
	    log("WARNING: cached_create_text: Couldn't write text %lu: %s\n",
999
		tno, strerror(errno));
1000
        err_stat = 0;
1001 1002 1003 1004 1005 1006 1007 1008
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fflush(text_file) != 0)
    {
	if (errno != ENOSPC)
1009
	    log("WARNING: cached_create_text: Couldn't fflush text %lu: %s\n",
1010
		tno, strerror(errno));
1011
        err_stat = 0;
1012 1013 1014 1015 1016 1017 1018 1019
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fsync(fileno(text_file)) != 0)
    {
	if (errno != ENOSPC)
1020
	    log("WARNING: cached_create_text: Couldn't fsync text %lu: %s\n",
1021
		tno, strerror(errno));
1022
        err_stat = 0;
1023 1024 1025 1026 1027
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }