simple-cache.c 55.8 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.81 1999/06/03 22:11:13 ceder Exp $
3
 * Copyright (C) 1991-1999  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.81 1999/06/03 22:11:13 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
65
#include <time.h>
#include <setjmp.h>

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

/*
 * 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.
 */

David Byers's avatar
David Byers committed
106
static Small_conf      ** small_conf_arr;
107
108
static Cache_node_mcb	* pers_mcb;
static Cache_node_mcb 	* conf_mcb;
109
static Conf_no		  next_free_num = 1;
Per Cederqvist's avatar
Per Cederqvist committed
110

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

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


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

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

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

static Conf_no highest_conf_no;
static Text_no highest_text_no;

BUGDECL;

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
210
211
/* 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)
{
212
213
    extern int putw(int, FILE *);

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

356
    return get_cache_node(text_mcb, text_no);
Per Cederqvist's avatar
Per Cederqvist committed
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
386
387
}

	
/*
 * 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);
388
389
390
391
392

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

393
394
    LOGACC(lt_get_conf_type, conf_no);

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

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

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

void
mark_person_as_changed(Pers_no	pers_no)
{
415
416
417
418
    Cache_node *node;

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

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

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

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

    node = get_conf_node (conf_no);

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

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

    conf_c = (Conference *) node->ptr;

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

    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
461
462
463
464
465
}

void
mark_text_as_changed( Text_no text_no )
{
466
467
468
469
    Cache_node *node;

    node = get_text_node (text_no);

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

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



/*
 * Person-related calls
 */


extern Success
cached_create_person( Pers_no person )
{
491
492
    Cache_node *node;

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

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

507
508
509
510
511
    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");
512

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

    LOGACC(lt_create_pers, person);

Per Cederqvist's avatar
Per Cederqvist committed
520
521
522
523
524
525
526
    return OK;
}


extern Person *
cached_get_person_stat( Pers_no	person )
{
527
528
    Cache_node *node;

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

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

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

545
546
    node = get_pers_node (person);

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

554
555
    LOGACC(lt_pers_stat, person);

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

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

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

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


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


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


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

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

    return s;
}


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

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

David Byers's avatar
David Byers committed
635
    if ( next_free_num >= param.max_conf )
Per Cederqvist's avatar
Per Cederqvist committed
636
    {
637
        err_stat = next_free_num;
Per Cederqvist's avatar
Per Cederqvist committed
638
639
640
641
642
643
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
	return 0;
    }
    
    conf_no = next_free_num++;

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

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

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

    LOGACC(lt_create_conf, conf_no);

Per Cederqvist's avatar
Per Cederqvist committed
666
667
668
669
670
671
672
    return conf_no;
}


extern Success
cached_delete_conf( Conf_no	conf )
{
673
674
    Cache_node *node;

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

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

689
690
    node = get_conf_node (conf);

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

698
    if ( node->lock_cnt > 0 )
David Byers's avatar
David Byers committed
699
	kom_log("WNG: cached_delete_conf(%d): lock_cnt === %d\n",
700
	    conf, node->lock_cnt);
Per Cederqvist's avatar
Per Cederqvist committed
701

David Byers's avatar
David Byers committed
702
703
704
    free_small_conf(small_conf_arr[conf]);
    small_conf_arr[conf] = NULL;

705
706
707
    free_conference(node->ptr);
    node->ptr = NULL;
    node->s.exists = 0;
Per Cederqvist's avatar
Per Cederqvist committed
708

709
710
    LOGACC(lt_delete_conf, conf);

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

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

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

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

736
737
738
    node = get_pers_node (pers);

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

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

750
751
    LOGACC(lt_delete_pers, pers);

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

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

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

    node = get_text_node (text);

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

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


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

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


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

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

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

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

825
826
    LOGACC(lt_conf_stat, conf_no);

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

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

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

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

/*
 * Return TRUE if conf_no exists.
 */
Bool
cached_conf_exists(Conf_no conf_no)
{
855
856
857
    if (conf_no == 0 || conf_no >= next_free_num )
	return FALSE;

David Byers's avatar
David Byers committed
858
    return small_conf_arr[conf_no] != NULL ? TRUE : FALSE;
Per Cederqvist's avatar
Per Cederqvist committed
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
}

    
/*
 * Calls to handle texts
 */

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

875
    TRACE2("cached_get_text %lu\n", text);
Per Cederqvist's avatar
Per Cederqvist committed
876
877
878
879
880

    if ( (t_stat = cached_get_text_stat (text)) == NULL )
	return EMPTY_STRING;
    else
    {
881
	LOGACC(lt_text_mass, text);
Per Cederqvist's avatar
Per Cederqvist committed
882
883
884
885
886
	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
887
	    != (size_t)the_string.len )
Per Cederqvist's avatar
Per Cederqvist committed
888
	{
David Byers's avatar
David Byers committed
889
	    kom_log("WARNING: cached_get_text: premature end on text %lu\n",
Per Cederqvist's avatar
Per Cederqvist committed
890
891
892
893
894
895
896
897
898
899
900
901
		text);
	    return EMPTY_STRING;
	}
		    
	return the_string;
    }
}


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

904
    TRACE2("cached_get_text_stat(%lu);  next_text_num == ", text);
905
    TRACE2("%lu\n", (unsigned long)next_text_num);
Per Cederqvist's avatar
Per Cederqvist committed
906
907
908

    if ( text == 0 )
    {
909
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
910
911
912
	kom_errno = KOM_TEXT_ZERO;
	return NULL;
    }
913
914
915
916

    node = get_text_node (text);

    if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
Per Cederqvist's avatar
Per Cederqvist committed
917
918
    {
	TRACE1("cached_get_text_stat: no such text.\n");
919
        err_stat = text;
Per Cederqvist's avatar
Per Cederqvist committed
920
921
922
923
	kom_errno = KOM_NO_SUCH_TEXT;
	return NULL;
    }

924
925
    LOGACC(lt_text_stat, text);

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

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

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

    text_set_mru (text);
947
    ++text_mcb->misses;
948
    return node->ptr;
Per Cederqvist's avatar
Per Cederqvist committed
949
950
951
952
953
954
}



/*
 * The text is set up with an empty misc-field. The misc field is
955
 * then initialized by create_text.
Per Cederqvist's avatar
Per Cederqvist committed
956
957
958
 */

extern Text_no
959
cached_create_text(const String message)
Per Cederqvist's avatar
Per Cederqvist committed
960
961
{
    Text_no tno;
962
    Cache_node *node;
963
    long file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
964
965
966

    tno = next_text_num++;

967
    TRACE2("cached_create_text (len=%lu)\n", message.len);
Per Cederqvist's avatar
Per Cederqvist committed
968

David Byers's avatar
David Byers committed
969
    if ( tno >= param.max_text )
Per Cederqvist's avatar
Per Cederqvist committed
970
    {
971
        err_stat = tno;
Per Cederqvist's avatar
Per Cederqvist committed
972
	kom_errno = KOM_INDEX_OUT_OF_RANGE;
David Byers's avatar
David Byers committed
973
	next_text_num = param.max_text;
Per Cederqvist's avatar
Per Cederqvist committed
974
975
976
977
	
	return 0;
    }

978
979
    if (fseek(text_file, 0, SEEK_END) != 0) 
    {
David Byers's avatar
David Byers committed
980
	kom_log("ERROR: cannot seek to end of text_file: %s\n", strerror(errno));
981
982
983
984
985
986
	clearerr(text_file);
	return 0;
    }

    file_pos = ftell(text_file);

David Byers's avatar
David Byers committed
987
988
    if (fwrite(message.string, 1, message.len, text_file)
        != (size_t)message.len)
989
990
    {
	if (errno != ENOSPC)
David Byers's avatar
David Byers committed
991
	    kom_log("WARNING: cached_create_text: Couldn't write text %lu: %s\n",
992
		tno, strerror(errno));
993
        err_stat = 0;
994
995
996
997
998
999
1000
1001
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fflush(text_file) != 0)
    {
	if (errno != ENOSPC)
David Byers's avatar
David Byers committed
1002
	    kom_log("WARNING: cached_create_text: Couldn't fflush text %lu: %s\n",
1003
		tno, strerror(errno));
1004
        err_stat = 0;
1005
1006
1007
1008
1009
1010
1011
1012
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

    if (fsync(fileno(text_file)) != 0)
    {
	if (errno != ENOSPC)
David Byers's avatar
David Byers committed
1013
	    kom_log("WARNING: cached_create_text: Couldn't fsync text %lu: %s\n",
1014
		tno, strerror(errno));
1015
        err_stat = 0;
1016
1017
1018
1019
1020
	kom_errno = KOM_TEMPFAIL;
	clearerr(text_file);
	return 0;
    }

1021
1022
    create_cache_node(text_mcb, tno);
    node = get_text_node (tno);
Per Cederqvist's avatar
Per Cederqvist committed
1023

1024
    if ( node == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
1025
	restart_kom("cached_create_text(): couldn't create cache-node.\n");
1026
1027
1028
1029
1030
1031
1032
1033
1034
    
    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;
1035
    ((Text_stat *)node->ptr)->file_pos = file_pos;
Per Cederqvist's avatar
Per Cederqvist committed
1036
1037
1038
1039

    text_set_mru( tno );


1040
    LOGACC(lt_create_text, tno);
1041
    TRACE2("cached_create_text -> %lu\n", tno);
Per Cederqvist's avatar
Per Cederqvist committed
1042
1043
1044
1045
1046
    
    return tno;
}


1047
EXPORT Text_no
Per Cederqvist's avatar
Per Cederqvist committed
1048
1049
traverse_text(Text_no seed)
{
1050
1051
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1052
1053
    seed++;
    
1054
    while ( seed < next_text_num )
Per Cederqvist's avatar
Per Cederqvist committed
1055
    {
1056
1057
1058
1059
	node = get_text_node (seed);
	if ( node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1060
1061
1062
1063
1064
1065
	seed++;
    }
    
    return (seed >= next_text_num) ? 0 : seed ;
}

1066
#if 0 /* This is not used, but should work OK. */
Per Cederqvist's avatar
Per Cederqvist committed
1067
1068
1069
Pers_no
traverse_person(Pers_no seed)
{
1070
1071
    Cache_node *node;

Per Cederqvist's avatar
Per Cederqvist committed
1072
1073
    seed++;

1074
    while ( seed < next_free_num )
Per Cederqvist's avatar
Per Cederqvist committed
1075
    {
1076
1077
1078
1079
	node = get_pers_node (seed);
	if (node != NULL && node->s.exists != 0 )
	    break;

Per Cederqvist's avatar
Per Cederqvist committed
1080
1081
1082
1083
1084
	seed++;
    }

    return (seed >= next_free_num) ? 0 : seed ;
}
1085
#endif
Per Cederqvist's avatar
Per Cederqvist committed
1086
1087
1088
1089

Conf_no
traverse_conference(Conf_no seed)
{
Per Cederqvist's avatar