Select Git revision
hmac-sha1.c
Forked from
Nettle / nettle
Source project has a limited visibility.
-
Niels Möller authored
config.h. Rev: src/nettle/ChangeLog:1.195 Rev: src/nettle/aes-decrypt-table.c:1.4 Rev: src/nettle/aes-decrypt.c:1.5 Rev: src/nettle/aes-encrypt-table.c:1.4 Rev: src/nettle/aes-encrypt.c:1.5 Rev: src/nettle/aes-meta.c:1.3 Rev: src/nettle/aes-set-decrypt-key.c:1.2 Rev: src/nettle/aes-set-encrypt-key.c:1.2 Rev: src/nettle/aes.c:1.12 Rev: src/nettle/aesdata.c:1.2 Rev: src/nettle/arcfour-meta.c:1.2 Rev: src/nettle/arcfour.c:1.3 Rev: src/nettle/base16-decode.c:1.2 Rev: src/nettle/base16-encode.c:1.2 Rev: src/nettle/base16-meta.c:1.3 Rev: src/nettle/base64-decode.c:1.5 Rev: src/nettle/base64-encode.c:1.3 Rev: src/nettle/base64-meta.c:1.4 Rev: src/nettle/bignum-random.c:1.3 Rev: src/nettle/bignum.c:1.7 Rev: src/nettle/blowfish.c:1.4 Rev: src/nettle/buffer-init.c:1.3 Rev: src/nettle/buffer.c:1.8 Rev: src/nettle/cast128-meta.c:1.3 Rev: src/nettle/cast128.c:1.4 Rev: src/nettle/cbc.c:1.6 Rev: src/nettle/des-compat.c:1.10 Rev: src/nettle/des.c:1.7 Rev: src/nettle/des3.c:1.2 Rev: src/nettle/dsa-keygen.c:1.6 Rev: src/nettle/dsa-sign.c:1.7 Rev: src/nettle/dsa-verify.c:1.4 Rev: src/nettle/dsa.c:1.5 Rev: src/nettle/examples/io.c:1.4 Rev: src/nettle/examples/nettle-benchmark.c:1.8 Rev: src/nettle/examples/nettle-openssl.c:1.2 Rev: src/nettle/examples/rsa-keygen.c:1.10 Rev: src/nettle/examples/rsa-sign.c:1.5 Rev: src/nettle/examples/rsa-verify.c:1.4 Rev: src/nettle/hmac-md5.c:1.5 Rev: src/nettle/hmac-sha1.c:1.2 Rev: src/nettle/hmac-sha256.c:1.2 Rev: src/nettle/hmac.c:1.4 Rev: src/nettle/knuth-lfib.c:1.2 Rev: src/nettle/md5-compat.c:1.3 Rev: src/nettle/md5-meta.c:1.2 Rev: src/nettle/md5.c:1.6 Rev: src/nettle/memxor.c:1.2 Rev: src/nettle/nettle-internal.c:1.3 Rev: src/nettle/pgp-encode.c:1.4 Rev: src/nettle/pkcs1-rsa-md5.c:1.2 Rev: src/nettle/pkcs1-rsa-sha1.c:1.2 Rev: src/nettle/pkcs1.c:1.2 Rev: src/nettle/realloc.c:1.3 Rev: src/nettle/rsa-compat.c:1.8 Rev: src/nettle/rsa-decrypt.c:1.4 Rev: src/nettle/rsa-encrypt.c:1.5 Rev: src/nettle/rsa-keygen.c:1.5 Rev: src/nettle/rsa-md5-sign.c:1.2 Rev: src/nettle/rsa-md5-verify.c:1.2 Rev: src/nettle/rsa-sha1-sign.c:1.2 Rev: src/nettle/rsa-sha1-verify.c:1.2 Rev: src/nettle/rsa-sign.c:1.3 Rev: src/nettle/rsa-verify.c:1.2 Rev: src/nettle/rsa.c:1.12 Rev: src/nettle/rsa2openpgp.c:1.2 Rev: src/nettle/rsa2sexp.c:1.7 Rev: src/nettle/serpent-meta.c:1.2 Rev: src/nettle/serpent.c:1.4 Rev: src/nettle/sexp-format.c:1.9 Rev: src/nettle/sexp-transport-format.c:1.2 Rev: src/nettle/sexp-transport.c:1.4 Rev: src/nettle/sexp.c:1.14 Rev: src/nettle/sexp2bignum.c:1.5 Rev: src/nettle/sexp2dsa.c:1.4 Rev: src/nettle/sexp2rsa.c:1.11 Rev: src/nettle/sha1-meta.c:1.2 Rev: src/nettle/sha1.c:1.8 Rev: src/nettle/sha256-meta.c:1.2 Rev: src/nettle/sha256.c:1.3 Rev: src/nettle/tools/input.c:1.2 Rev: src/nettle/tools/misc.c:1.2 Rev: src/nettle/tools/output.c:1.3 Rev: src/nettle/tools/parse.c:1.2 Rev: src/nettle/tools/sexp-conv.c:1.14 Rev: src/nettle/twofish-meta.c:1.2 Rev: src/nettle/twofish.c:1.6 Rev: src/nettle/yarrow256.c:1.17 Rev: src/nettle/yarrow_key_event.c:1.4
Niels Möller authoredconfig.h. Rev: src/nettle/ChangeLog:1.195 Rev: src/nettle/aes-decrypt-table.c:1.4 Rev: src/nettle/aes-decrypt.c:1.5 Rev: src/nettle/aes-encrypt-table.c:1.4 Rev: src/nettle/aes-encrypt.c:1.5 Rev: src/nettle/aes-meta.c:1.3 Rev: src/nettle/aes-set-decrypt-key.c:1.2 Rev: src/nettle/aes-set-encrypt-key.c:1.2 Rev: src/nettle/aes.c:1.12 Rev: src/nettle/aesdata.c:1.2 Rev: src/nettle/arcfour-meta.c:1.2 Rev: src/nettle/arcfour.c:1.3 Rev: src/nettle/base16-decode.c:1.2 Rev: src/nettle/base16-encode.c:1.2 Rev: src/nettle/base16-meta.c:1.3 Rev: src/nettle/base64-decode.c:1.5 Rev: src/nettle/base64-encode.c:1.3 Rev: src/nettle/base64-meta.c:1.4 Rev: src/nettle/bignum-random.c:1.3 Rev: src/nettle/bignum.c:1.7 Rev: src/nettle/blowfish.c:1.4 Rev: src/nettle/buffer-init.c:1.3 Rev: src/nettle/buffer.c:1.8 Rev: src/nettle/cast128-meta.c:1.3 Rev: src/nettle/cast128.c:1.4 Rev: src/nettle/cbc.c:1.6 Rev: src/nettle/des-compat.c:1.10 Rev: src/nettle/des.c:1.7 Rev: src/nettle/des3.c:1.2 Rev: src/nettle/dsa-keygen.c:1.6 Rev: src/nettle/dsa-sign.c:1.7 Rev: src/nettle/dsa-verify.c:1.4 Rev: src/nettle/dsa.c:1.5 Rev: src/nettle/examples/io.c:1.4 Rev: src/nettle/examples/nettle-benchmark.c:1.8 Rev: src/nettle/examples/nettle-openssl.c:1.2 Rev: src/nettle/examples/rsa-keygen.c:1.10 Rev: src/nettle/examples/rsa-sign.c:1.5 Rev: src/nettle/examples/rsa-verify.c:1.4 Rev: src/nettle/hmac-md5.c:1.5 Rev: src/nettle/hmac-sha1.c:1.2 Rev: src/nettle/hmac-sha256.c:1.2 Rev: src/nettle/hmac.c:1.4 Rev: src/nettle/knuth-lfib.c:1.2 Rev: src/nettle/md5-compat.c:1.3 Rev: src/nettle/md5-meta.c:1.2 Rev: src/nettle/md5.c:1.6 Rev: src/nettle/memxor.c:1.2 Rev: src/nettle/nettle-internal.c:1.3 Rev: src/nettle/pgp-encode.c:1.4 Rev: src/nettle/pkcs1-rsa-md5.c:1.2 Rev: src/nettle/pkcs1-rsa-sha1.c:1.2 Rev: src/nettle/pkcs1.c:1.2 Rev: src/nettle/realloc.c:1.3 Rev: src/nettle/rsa-compat.c:1.8 Rev: src/nettle/rsa-decrypt.c:1.4 Rev: src/nettle/rsa-encrypt.c:1.5 Rev: src/nettle/rsa-keygen.c:1.5 Rev: src/nettle/rsa-md5-sign.c:1.2 Rev: src/nettle/rsa-md5-verify.c:1.2 Rev: src/nettle/rsa-sha1-sign.c:1.2 Rev: src/nettle/rsa-sha1-verify.c:1.2 Rev: src/nettle/rsa-sign.c:1.3 Rev: src/nettle/rsa-verify.c:1.2 Rev: src/nettle/rsa.c:1.12 Rev: src/nettle/rsa2openpgp.c:1.2 Rev: src/nettle/rsa2sexp.c:1.7 Rev: src/nettle/serpent-meta.c:1.2 Rev: src/nettle/serpent.c:1.4 Rev: src/nettle/sexp-format.c:1.9 Rev: src/nettle/sexp-transport-format.c:1.2 Rev: src/nettle/sexp-transport.c:1.4 Rev: src/nettle/sexp.c:1.14 Rev: src/nettle/sexp2bignum.c:1.5 Rev: src/nettle/sexp2dsa.c:1.4 Rev: src/nettle/sexp2rsa.c:1.11 Rev: src/nettle/sha1-meta.c:1.2 Rev: src/nettle/sha1.c:1.8 Rev: src/nettle/sha256-meta.c:1.2 Rev: src/nettle/sha256.c:1.3 Rev: src/nettle/tools/input.c:1.2 Rev: src/nettle/tools/misc.c:1.2 Rev: src/nettle/tools/output.c:1.3 Rev: src/nettle/tools/parse.c:1.2 Rev: src/nettle/tools/sexp-conv.c:1.14 Rev: src/nettle/twofish-meta.c:1.2 Rev: src/nettle/twofish.c:1.6 Rev: src/nettle/yarrow256.c:1.17 Rev: src/nettle/yarrow_key_event.c:1.4
simple-cache.c 44.68 KiB
/*
* $Id: simple-cache.c,v 0.35 1993/10/13 00:20:14 ceder Exp $
* Copyright (C) 1991 Lysator Academic Computer Association.
*
* 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.
*/
/*
* 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.
*/
static char *rcsid = "$Id: simple-cache.c,v 0.35 1993/10/13 00:20:14 ceder Exp $";
#include "rcs.h"
USE(rcsid);
#include <errno.h>
#include <stdio.h>
#ifndef SEEK_END
# include <fcntl.h>
#endif
#ifndef SEEK_END
# include <unistd.h>
#endif
#ifndef SEEK_END
# define SEEK_SET 0
# define SEEK_END 2
#endif
#include <time.h>
#ifndef HAVE_DIFFTIME
# include <sys/types.h>
# include "tmp-difftime.h"
#endif
#include <setjmp.h>
#include "exp.h"
#include "misc-types.h"
#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"
#include "connections.h"
#include "send-async.h"
/*
* 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 ];
static Cache_node_mcb * pers_mcb;
static Cache_node_mcb * conf_mcb;
static int next_free_num = 1;
static Cache_node_mcb * text_mcb;
static int next_text_num = 1;
/* Defined in ramkomd.c */
extern char datafilename[BUFSIZ];
extern char backupfilename[BUFSIZ];
extern char textfilename[BUFSIZ];
/*
* 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;
EXPORT Conf_no *conf_table = NULL; /* Used in conference.c. */
static FILE *text_file= NULL;
static FILE *file_a = NULL; /* Current file. */
static FILE *file_b = NULL; /* File under construction. */
/*
* Four state variables for the background save.
*/
static enum {
sync_idle,
sync_save_conf,
sync_save_pers,
sync_save_text,
sync_error,
sync_wait,
sync_ready
} sync_state;
/* 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
*/
static long sync_next;
static Conf_no highest_conf_no;
static Text_no highest_text_no;
BUGDECL;
/* Define LOGACCESSES if you want to be able to log all accesses to
the data base. */
#ifdef LOGACCESSES
extern char *logaccess_file; /* From ramkomd.c */
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)
{
extern int putw(int, FILE *);
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
/* Macros */
#define TRACE2(format, arg) if ( buglevel > 2 ) printf(format, arg)
#define TRACE1(format) if ( buglevel > 2 ) printf(format)
#define TRACESTR(str) if ( buglevel > 2 ) s_puts(str)
static Person *
read_person(FILE *fp,
long pos,
long size)
{
Person *p;
p = alloc_person();
fseek(fp, pos+1, SEEK_SET); /* Skip '+' */
if ( fparse_person(fp, p) != OK )
{
free_person(p);
return NULL;
}
else
return p;
}
static Conference *
read_conference(FILE *fp,
long pos,
long size)
{
Conference *c;
c = alloc_conference();
fseek(fp, pos+1, SEEK_SET); /* Skip '+' */
if ( fparse_conference(fp, c) != OK )
{
free_conference(c);
return NULL;
}
else
return c;
}
static Text_stat *
read_text_stat(FILE *fp,
long pos,
long size)
{
Text_stat *t;
t = alloc_text_stat();
fseek(fp, pos+1, SEEK_SET); /* Skip '+' */
if ( fparse_text_stat(fp, t) != OK )
{
free_text_stat(t);
return NULL;
}
else
return t;
}
static void
pers_set_mru(Pers_no pers_no)
{
set_mru(pers_mcb, pers_no);
}
static void
text_set_mru(Text_no text_no)
{
set_mru(text_mcb, text_no);
}
static void
conf_set_mru(Conf_no conf_no)
{
set_mru(conf_mcb, conf_no);
}
static Cache_node *
get_pers_node(Pers_no pers_no)
{
if ( pers_no >= next_free_num )
return NULL;
return get_cache_node(pers_mcb, pers_no);
}
static void
unlink_text_lru (Cache_node *node)
{
unlink_lru (node, &text_mcb->lru, &text_mcb->mru);
}
static void
unlink_conf_lru (Cache_node *node)
{
unlink_lru (node, &conf_mcb->lru, &conf_mcb->mru);
}
static void
unlink_pers_lru (Cache_node *node)
{
unlink_lru (node, &pers_mcb->lru, &pers_mcb->mru);
}
static Cache_node *
get_conf_node(Conf_no conf_no)
{
if ( conf_no >= next_free_num )
return NULL;
return get_cache_node(conf_mcb, conf_no);
}
static Cache_node *
get_text_node(Text_no text_no)
{
if ( text_no >= next_text_num )
return NULL;
return get_cache_node(text_mcb, text_no);
}
/*
* 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);
if ( small_conf_arr [ conf_no ] == NULL )
restart_kom("cached_get_conf_type(%d): conference does not exist.\n",
conf_no);
LOGACC(lt_get_conf_type, conf_no);
return small_conf_arr [ conf_no ]->type;
}
/*
* 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? */
}
/*
* Various function calls to tell the cache that something is changed.
*/
void
mark_person_as_changed(Pers_no pers_no)
{
Cache_node *node;
node = get_pers_node(pers_no);
TRACE2("Person %d is changed\n", pers_no);
if ( node == NULL || node->s.exists == 0)
restart_kom("mark_person_as_changed(%d): nonexistent.\n", pers_no);
node->s.dirty = 1;
pers_set_mru( pers_no );
}
/*
* 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.
*/
void
mark_conference_as_changed(Conf_no conf_no)
{
Cache_node *node;
Conference *conf_c;
node = get_conf_node (conf_no);
TRACE2("Conf. %d is changed\n", conf_no);
if ( node == NULL || node->s.exists == 0)
restart_kom("mark_conference_as_changed(%d): nonexistent.\n", conf_no);
node->s.dirty = 1;
conf_set_mru( conf_no );
conf_c = (Conference *) node->ptr;
small_conf_arr[ conf_no ]->highest_local_no
= (conf_c->texts.first_local_no - 1 + conf_c->texts.no_of_texts );
small_conf_arr[ conf_no ]->nice = conf_c->nice;
small_conf_arr[ conf_no ]->type = conf_c->type;
}
void
mark_text_as_changed( Text_no text_no )
{
Cache_node *node;
node = get_text_node (text_no);
TRACE2("Text %d is changed.\n", text_no);
if ( text_no < 1 || text_no >= next_text_num
|| node == NULL || node->s.exists == 0)
{
restart_kom("mark_text_as_changed(%d): nonexistent.\n", text_no);
}
node->s.dirty = 1;
text_set_mru (text_no);
}
/*
* Person-related calls
*/
extern Success
cached_create_person( Pers_no person )
{
Cache_node *node;
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);
}
if ( get_pers_node(person) != NULL )
{
restart_kom("cached_create_person(%d): Person existed.\n",
person);
}
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");
node->ptr = alloc_person();
node->s.dirty = 1;
node->s.exists = 1;
pers_set_mru( person );
LOGACC(lt_create_pers, person);
return OK;
}
extern Person *
cached_get_person_stat( Pers_no person )
{
Cache_node *node;
TRACE2("cached_get_person_stat %d\n", person);
if ( person == 0 )
{
kom_errno = KOM_CONF_ZERO;
return NULL;
}
if ( person >= next_free_num )
{
kom_errno = KOM_UNDEF_PERS;
return NULL;
}
node = get_pers_node (person);
if ( node == NULL || node->s.exists == 0 )
{
kom_errno = KOM_UNDEF_PERS;
return NULL;
}
LOGACC(lt_pers_stat, person);
if ( node->ptr != NULL )
{
pers_set_mru( person );
++pers_mcb->hits;
return node->ptr;
}
if ( node->snap_shot != NULL )
{
node->ptr = copy_person (node->snap_shot);
pers_set_mru (person);
++pers_mcb->hits;
return node->ptr;
}
node->ptr = read_person(file_a, node->pos, node->size);
++pers_mcb->misses;
pers_set_mru (person);
return node->ptr;
}
/*
* Conference-related calls
*/
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);
}
}
static Small_conf *
alloc_small_conf(void)
{
Small_conf *s;
s = smalloc(sizeof(Small_conf));
*s = EMPTY_SMALL_CONF;
++no_of_allocated_small_confs;
return s;
}
/*
* Create a conference.
*
* Set up a Conference and cache the name in the small_conf_array.
*/
extern Conf_no
cached_create_conf (String name)
{
Conference * conf_c;
Conf_no conf_no;
Cache_node *node;
TRACE1("cached_create_conf( ");
TRACESTR(name);
TRACE1(" )\n");
if ( next_free_num >= MAX_CONF )
{
kom_errno = KOM_INDEX_OUT_OF_RANGE;
return 0;
}
conf_no = next_free_num++;
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();
conf_set_mru(conf_no);
zero_init_cache_node (pers_mcb, conf_no);
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);
TRACE2("Created conference number %d\n", conf_no);
LOGACC(lt_create_conf, conf_no);
return conf_no;
}
extern Success
cached_delete_conf( Conf_no conf )
{
Cache_node *node;
if ( conf == 0 )
{
kom_errno = KOM_CONF_ZERO;
return FAILURE;
}
if ( conf >= next_free_num )
{
kom_errno = KOM_UNDEF_CONF;
return FAILURE;
}
node = get_conf_node (conf);
if ( node == NULL || node->s.exists == 0 )
{
kom_errno = KOM_UNDEF_CONF;
return FAILURE;
}
if ( node->lock_cnt > 0 )
log("WNG: cached_delete_conf(%d): lock_cnt === %d\n",
conf, node->lock_cnt);
free_conference(node->ptr);
node->ptr = NULL;
node->s.exists = 0;
LOGACC(lt_delete_conf, conf);
return OK;
}
Success
cached_delete_person(Pers_no pers)
{
Cache_node *node;
if ( pers == 0 )
{
kom_errno = KOM_CONF_ZERO;
return FAILURE;
}
if ( pers >= next_free_num )
{
log("cached_delete_person(%lu): next_free_num == %lu\n",
(u_long)pers, (u_long)next_free_num);
kom_errno = KOM_UNDEF_PERS;
return FAILURE;
}
node = get_pers_node (pers);
if ( pers >= next_free_num || node == NULL || node->s.exists == 0 )
{
log("cached_delete_person(): attempt to"
" delete non-existing person.\n");
kom_errno = KOM_UNDEF_PERS;
return FAILURE;
}
if ( node->lock_cnt > 0 )
log("cached_delete_pers(%lu): lock_cnt === %lu\n",
(u_long)pers, (u_long)node->lock_cnt);
LOGACC(lt_delete_pers, pers);
free_person (node->ptr);
node->ptr = NULL;
node->s.exists = 0;
return OK;
}
Success
cached_delete_text(Text_no text)
{
Cache_node *node;
if ( text == 0 )
{
kom_errno = KOM_TEXT_ZERO;
return FAILURE;
}
node = get_text_node (text);
if ( text >= next_text_num || node == NULL
|| node->s.exists == 0 )
{
log("cached_delete_text(): attempt to"
" delete non-existing text %d.\n", text);
kom_errno = KOM_NO_SUCH_TEXT;
return FAILURE;
}
if ( node->lock_cnt > 0 )
log("cached_delete_text(%d): lock_cnt === %d\n",
text, node->lock_cnt);
free_text_stat(node->ptr);
node->ptr = NULL;
node->s.exists = 0;
#ifdef LOGACCESSES
if (garb_running)
{
LOGACC(lt_garb_text, text);
}
else
LOGACC(lt_delete_text, text);
#endif
return OK;
}
extern Conference *
cached_get_conf_stat (Conf_no conf_no)
{
Cache_node *node;
TRACE2("cached_get_conf_stat %d\n", conf_no);
if ( conf_no == 0 )
{
kom_errno = KOM_CONF_ZERO;
return NULL;
}
node = get_conf_node (conf_no);
if ( conf_no >= next_free_num || node == NULL || node->s.exists == 0 )
{
kom_errno = KOM_UNDEF_CONF;
return NULL;
}
LOGACC(lt_conf_stat, conf_no);
if ( node->ptr != NULL )
{
conf_set_mru (conf_no);
++conf_mcb->hits;
return node->ptr;
}
if ( node->snap_shot != NULL )
{
node->ptr = copy_conf (node->snap_shot);
conf_set_mru (conf_no);
++conf_mcb->hits;
return node->ptr;
}
node->ptr = read_conference(file_a, node->pos, node->size);
++conf_mcb->misses;
conf_set_mru (conf_no);
return node->ptr;
}
/*
* Return TRUE if conf_no exists.
*/
Bool
cached_conf_exists(Conf_no conf_no)
{
Cache_node *node;
if (conf_no == 0 || conf_no >= next_free_num )
return FALSE;
node = get_conf_node (conf_no);
return node != NULL && node->s.exists != 0;
}
/*
* Calls to handle texts
*/
/*
* +++ Should return Success.
*/
extern String
cached_get_text( Text_no text )
{
String the_string;
Text_stat *t_stat;
TRACE2("cached_get_text %d\n", text);
if ( (t_stat = cached_get_text_stat (text)) == NULL )
return EMPTY_STRING;
else
{
LOGACC(lt_text_mass, text);
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 )
{
log("WARNING: cached_get_text: "
"couldn't read enough characters of text %d\n",
text);
return EMPTY_STRING;
}
return the_string;
}
}
extern Text_stat * /* NULL on error */
cached_get_text_stat( Text_no text )
{
Cache_node *node;
TRACE2("cached_get_text_stat(%d); next_text_num == ", text);
TRACE2("%d\n", next_text_num);
if ( text == 0 )
{
kom_errno = KOM_TEXT_ZERO;
return NULL;
}
node = get_text_node (text);
if ( text >= next_text_num || node == NULL || node->s.exists == 0 )
{
TRACE1("cached_get_text_stat: no such text.\n");
kom_errno = KOM_NO_SUCH_TEXT;
return NULL;
}
LOGACC(lt_text_stat, text);
if ( node->ptr != NULL )
{
TRACE1("Found in ptr.\n");
text_set_mru( text );
++text_mcb->hits;
return node->ptr;
}
if ( node->snap_shot != NULL )
{
TRACE1("Found in snap_shot\n");
node->ptr = copy_text_stat(node->snap_shot);
text_set_mru (text);
++text_mcb->hits;
return node->ptr;
}
TRACE1("Found in file A.\n");
node->ptr = read_text_stat(file_a, node->pos, node->size);
text_set_mru (text);
++text_mcb->misses;
return node->ptr;
}
/*
* The text is set up with an empty misc-field. The misc field is
* then initialized by create_text.
*/
extern Text_no
cached_create_text(const String message)
{
Text_no tno;
Cache_node *node;
tno = next_text_num++;
TRACE2("cached_create_text (len=%d)\n", message.len);
if ( tno >= MAX_TEXT )
{
kom_errno = KOM_INDEX_OUT_OF_RANGE;
next_text_num = MAX_TEXT;
return 0;
}
create_cache_node(text_mcb, tno);
node = get_text_node (tno);
if ( node == NULL )
restart_kom("cached_create_text(): couldn't create cache-node.\n");
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;
fseek(text_file, 0, SEEK_END);
((Text_stat *)node->ptr)->file_pos = ftell(text_file);
text_set_mru( tno );
if ( fwrite(message.string, sizeof(char), message.len, text_file)
!= message.len ) {
log("WARNING: cached_create_text: Couldn't write the text %d\n",
tno);
}
fflush(text_file);
LOGACC(lt_create_text, tno);
TRACE2("cached_create_text -> %d\n", tno);
return tno;
}
EXPORT Text_no
traverse_text(Text_no seed)
{
Cache_node *node;
seed++;
while ( seed < next_text_num )
{
node = get_text_node (seed);
if ( node != NULL && node->s.exists != 0 )
break;
seed++;
}
return (seed >= next_text_num) ? 0 : seed ;
}
Pers_no
traverse_person(Pers_no seed)
{
Cache_node *node;
seed++;
while ( seed < next_free_num )
{
node = get_pers_node (seed);
if (node != NULL && node->s.exists != 0 )
break;
seed++;
}
return (seed >= next_free_num) ? 0 : seed ;
}
Conf_no
traverse_conference(Conf_no seed)
{
Cache_node *node;
seed++;
while ( seed < next_free_num )
{
node = get_conf_node (seed);
if (node != NULL && node->s.exists != 0 )
break;
seed++;
}
return (seed >= next_free_num) ? 0 : seed ;
}
extern Garb_nice
cached_get_garb_nice (Conf_no conf_no)
{
return small_conf_arr [ conf_no ]->nice;
}
extern String
cached_get_name (Conf_no conf_no)
{
return small_conf_arr [ conf_no ]->name;
}
extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no)
{
LOGACC(lt_get_highest, conf_no);
return small_conf_arr[ conf_no ]->highest_local_no;
}
/* Lock a person struct in memory. Increase a referenc count. */
void
cached_lock_person(Pers_no pers_no)
{
Cache_node *node;
LOGACC(lt_lock_pers, pers_no);
node = get_pers_node(pers_no);
if ( node == NULL || node->s.exists == 0 )
restart_kom("cached_lock_person(%d): nonexistent.\n", pers_no);
if ( node->ptr == NULL )
{
Person *pers_stat_ptr;
pers_stat_ptr = cached_get_person_stat( pers_no );
if ( pers_stat_ptr == NULL )
restart_kom("cached_lock_person(%d): couldn't read in person.\n",
pers_no);
if ( pers_stat_ptr != node->ptr )
restart_kom("cached_lock_person(%d): pers_stat_ptr == %d, node"
"->ptr == %d.\n", pers_no, pers_stat_ptr,
node->ptr);
}
node->lock_cnt++;
}
/* Decrease reference count. If zero, unlock person. */
void
cached_unlock_person(Pers_no pers_no)
{
Cache_node *node;
LOGACC(lt_unlock_pers, pers_no);
node = get_pers_node (pers_no);
if ( node == NULL )
restart_kom("cached_unlock_person(): couldn't get cache-node.\n");
if ( node->lock_cnt <= 0 )
{
log("cached_unlock_person(%d): lock_cnt == %d.\n",
pers_no, node->lock_cnt);
node->lock_cnt = 0;
}
else
node->lock_cnt--;
}
/* Lock a conf struct in memory. Increase a reference count. */
void
cached_lock_conf(Conf_no conf_no)
{
Cache_node *node;
node = get_conf_node(conf_no);
if ( node == NULL)
restart_kom("cached_lock_conf(): can't get cache-node.\n");
if ( node->s.exists == 0 )
restart_kom("cached_lock_conf(%d): nonexistent.\n", conf_no);
LOGACC(lt_lock_conf, conf_no);
if ( node->ptr == NULL )
{
Conference *conference_ptr;
conference_ptr = cached_get_conf_stat( conf_no );
if ( conference_ptr == NULL )
restart_kom("cached_lock_conf(%d): couldn't read in conf.\n",
conf_no);
if ( conference_ptr != node->ptr )
restart_kom("cached_lock_conf(%d): conference_ptr == %d, node"
"->ptr == %d.\n", conf_no, conference_ptr,
node->ptr);
}
node->lock_cnt++;
}
/* Decrease reference count. If zero, unlock conf. */
void
cached_unlock_conf(Conf_no conf_no)
{
Cache_node *node;
LOGACC(lt_unlock_conf, conf_no);
node = get_conf_node(conf_no);
if ( node == NULL )
restart_kom("cached_unlock_conf(): can't get node.\n");
if ( node->lock_cnt <= 0 )
{
log("cached_unlock_conf(%d): lock_cnt == %d.\n",
conf_no, node->lock_cnt);
node->lock_cnt = 0;
}
else
node->lock_cnt--;
}
/*
* And here comes some functions to deal with lookup_names.
*/
/* Free the _contents_ of a match_table. The table itself i _not_ freed. */
static void
free_match_table(Matching_info *match)
{
if ( match == NULL )
return;
while ( ! s_empty( match->name ))
{
free_tokens( match->tokens );
/* match->name is not freed since it points into conf_arr[]. */
++match;
}
}
extern Success
build_matching_info(void)
{
Conf_no i;
Matching_info *match;
Conf_no *conf;
free_match_table(match_table);
match_table = srealloc(match_table, next_free_num * sizeof(Matching_info));
conf_table = srealloc(conf_table, next_free_num * sizeof(Conf_no));
no_of_match_info = 0;
match = match_table;
conf = conf_table;
for ( i = 1; i < next_free_num; i++ )
{
if ( small_conf_arr[ i ] != NULL
&& ! s_empty ( small_conf_arr[ i ]->name ) )
{
match->name = small_conf_arr[ i ]->name;
match->tokens = tokenize(match->name, s_fcrea_str(WHITESPACE));
match->priority = 7;
*conf = i;
++match;
++conf;
++no_of_match_info;
}
}
match->name = EMPTY_STRING;
match->tokens = NULL;
match->priority = 0;
*conf = 0;
return OK;
}
/* Map conference name to number */
extern Success
cached_lookup_name(const String name,
Conf_list_old *result)
{
Parse_info tmp;
int i;
tmp = parse(name, match_table, FALSE, FALSE,
s_fcrea_str(WHITESPACE), DEFAULT_COLLAT_TAB);
if ( tmp.no_of_matches == -1 )
return FAILURE;
if ( tmp.no_of_matches == 1 && tmp.indexes[ 0 ] == -1 )
{
/* Return the entire list. */
result->no_of_conf_nos = no_of_match_info;
result->conf_nos = tmp_alloc(no_of_match_info * sizeof(Conf_no));
result->type_of_conf = tmp_alloc(no_of_match_info * sizeof(Conf_type));
for ( i = 0; i < no_of_match_info; i++ )
{
result->conf_nos[ i ] = conf_table[ i ];
result->type_of_conf[ i ] = small_conf_arr[ conf_table[i] ]->type;
}
}
else
{
/* Return the conferences whose conf_nos are in indexes[]. */
result->no_of_conf_nos = tmp.no_of_matches;
result->conf_nos = tmp_alloc(tmp.no_of_matches * sizeof(Conf_no));
result->type_of_conf = tmp_alloc(tmp.no_of_matches
* sizeof(Conf_type));
for ( i = 0; i < tmp.no_of_matches; i++ )
{
result->conf_nos[ i ] = conf_table[ tmp.indexes[ i ] ];
result->type_of_conf[ i ]
= small_conf_arr[ conf_table[ tmp.indexes[ i ] ] ]->type;
}
}
sfree(tmp.indexes);
return OK;
}
static Bool
is_clean(const char *fn)
{
FILE *fp;
if ( (fp = fopen(fn, "rb")) == NULL )
return FALSE;
if ( getc(fp) == 'C' && getc(fp) == 'L' && getc(fp) == 'E'
&& getc(fp) == 'A' && getc(fp) == 'N' )
{
fclose(fp);
return TRUE;
}
else
{
fclose(fp);
return FALSE;
}
}
static void
pre_sync(void)
{
long i;
Cache_node *node;
async_sync_db();
/* Mark up what to save.*/
BUG(("Sync starting\n"));
highest_text_no = next_text_num;
highest_conf_no = next_free_num;
for ( i = 1; i < highest_conf_no; i++ )
{
node = get_conf_node(i);
if ( node != NULL )
{
node->s.exists_b = node->s.exists;
if ( node->s.dirty != 0 && node->s.exists != 0)
{
free_conference(node->snap_shot);
if ( node->lock_cnt == 0 )
{
unlink_conf_lru(node);
node->snap_shot = node->ptr;
node->ptr = NULL;
}
else
{
node->snap_shot = copy_conf(node->ptr);
}
node->s.dirty = 0;
}
}
}
for ( i = 1; i < highest_conf_no; i++ )
{
node = get_pers_node(i);
if ( node != NULL )
{
node->s.exists_b = node->s.exists;
if ( node->s.dirty != 0 && node->s.exists != 0)
{
free_person(node->snap_shot);
if ( node->lock_cnt == 0 )
{
unlink_pers_lru(node);
node->snap_shot = node->ptr;
node->ptr = NULL;
}
else
{
node->snap_shot
= copy_person(node->ptr);
}
node->s.dirty = 0;
}
}
}
for ( i = 1; i < highest_text_no; i++ )
{
node = get_text_node(i);
if ( node != NULL )
{
node->s.exists_b = node->s.exists;
if ( node->s.dirty != 0 && node->s.exists != 0)
{
free_text_stat(node->snap_shot);
if ( node->lock_cnt == 0 )
{
unlink_text_lru(node);
node->snap_shot = node->ptr;
node->ptr = NULL;
}
else
{
node->snap_shot
= copy_text_stat(node->ptr);
}
node->s.dirty = 0;
}
}
}
/* All marking is done. Now open file B. */
if ( is_clean(datafilename) )
{
if ( rename(datafilename, backupfilename) != 0 )
restart_kom("pre_sync: can't backup.\n");
}
else
log("pre_sync: datafile not clean. No backup taken.\n");
if ( file_b != NULL )
{
log("pre_sync: Save in progress aborted.\n");
fclose(file_b);
}
if ( (file_b=fopen(datafilename, "wb") ) == NULL )
{
log("WARNING: pre_sync: can't open file to save in.\n");
sync_state = sync_wait;
return;
}
fprintf(file_b, "DIRTY\n"); /* DIRTY-FLAG */
fprintf(file_b, "%d\n", highest_conf_no); /* NEXT_FREE_NUM */
sync_state = sync_save_conf;
sync_next = 1;
}
static void
copy_file(FILE *from,
FILE *to,
long from_pos,
long len)
{
char *buf;
long result;
buf = smalloc(len);
if ( fseek(from, from_pos, SEEK_SET) == -1 )
{
sync_state = sync_error;
log("sync: copy_file(): fseek failed.\n");
sfree(buf);
return;
}
if ( (result = fread(buf, 1, len, from)) != len )
{
log("sync: copy_file(): fread failed.\n"
"from_pos = %d, len = %d, result = %d\n",
from_pos, len, result);
sync_state = sync_error;
sfree(buf);
return;
}
if ( fseek(to, 0, SEEK_END) == -1 )
{
sync_state = sync_error;
log("sync: copy_file(): second fseek failed.\n");
sfree(buf);
return;
}
if ( fwrite(buf, 1, len, to) != len )
{
sync_state = sync_error;
log("sync: copy_file(): fwrite failed.\n");
sfree(buf);
return;
}
sfree(buf);
}
static void
save_one_conf(void)
{
Cache_node *cn;
if (sync_next < highest_conf_no)
{
cn = get_conf_node (sync_next);
if ( cn == NULL )
{
putc('@', file_b);
putc('\n', file_b);
}
else
{
cn->pos_b = ftell(file_b);
if ( cn->s.exists_b == 0 )
putc('@', file_b);
else if ( cn->snap_shot != NULL )
{
fprintf(file_b, "+ ");
foutput_conference(file_b, cn->snap_shot);
}
else if ( cn->s.dirty == 0 && cn->ptr != NULL )
{
fprintf(file_b, "+ ");
foutput_conference(file_b, cn->ptr);
}
else
{
copy_file(file_a, file_b, cn->pos, cn->size - 1);
}
putc('\n', file_b);
cn->size_b = ftell(file_b) - cn->pos_b;
}
sync_next++;
}
else /* All conferences are written. */
{
sync_next = 1;
sync_state = sync_save_pers;
}
}
static void
write_pers(FILE *fp,
Person *p)
{
fprintf(fp, "+ %dH", PASSWD_LEN);
fwrite(p->pwd, PASSWD_LEN, 1, fp);
foutput_person(fp, p);
}
static void
save_one_pers(void)
{
Cache_node *cn;
if (sync_next < highest_conf_no)
{
cn = get_pers_node (sync_next);
if ( cn == NULL )
{
putc('@', file_b);
putc('\n', file_b);
}
else
{
cn->pos_b = ftell(file_b);
if ( cn->s.exists_b == 0 )
putc('@', file_b);
else if ( cn->snap_shot != NULL )
{
write_pers(file_b, cn->snap_shot);
}
else if ( cn->s.dirty == 0 && cn->ptr != NULL )
{
write_pers(file_b, cn->ptr);
}
else
{
copy_file(file_a, file_b, cn->pos, cn->size - 1);
}
putc('\n', file_b);
cn->size_b = ftell(file_b) - cn->pos_b;
}
sync_next++;
}
else /* All persons are written. */
{
fprintf(file_b, "%d\n", highest_text_no); /* NEXT_TEXT_NUM */
sync_next = 1;
sync_state = sync_save_text;
}
}
static void
post_sync(void)
{
int i;
Cache_node *node;
async_sync_db();
if ( file_a == NULL )
log("WARNING: post_sync(): file_a == NULL. This is only normal "
"if this is the first sync ever on this data file.\n");
else
fclose(file_a);
if ( ( file_a = fopen(datafilename, "rb") ) == NULL )
{
log("post_sync: can't open the file I just saved.\n");
sync_state = sync_wait;
return;
}
for ( i = 1; i < highest_conf_no; i++ )
{
node = get_conf_node(i);
if ( node != NULL )
{
node->pos = node->pos_b;
node->size = node->size_b;
free_conference(node->snap_shot);
node->snap_shot = NULL;
/* +++ Delete if it no longer exists. */
}
}
for ( i = 1; i < highest_conf_no; i++ )
{
node = get_pers_node(i);
if ( node != NULL )
{
node->pos = node->pos_b;
node->size = node->size_b;
free_person(node->snap_shot);
node->snap_shot = NULL;
/* +++ Delete if it no longer exists. */
}
}
for ( i = 1; i < highest_text_no; i++ )
{
node = get_text_node(i);
if ( node != NULL )
{
node->pos = node->pos_b;
node->size = node->size_b;
free_text_stat(node->snap_shot);
node->snap_shot = NULL;
/* +++ Delete if it no longer exists. */
}
}
}
static void
save_one_text(void)
{
Cache_node *cn;
long offset;
long offset2;
while (sync_next < highest_text_no)
{
cn = get_text_node(sync_next);
if ( cn == NULL )
{
putc('@', file_b);
putc('\n', file_b);
sync_next++;
continue;
}
else
{
cn->pos_b = ftell(file_b);
if ( cn->s.exists_b == 0 )
putc('@', file_b);
else if ( cn->snap_shot != NULL )
{
fprintf(file_b, "+ ");
foutput_text_stat(file_b, cn->snap_shot);
}
else if ( cn->s.dirty == 0 && cn->ptr != NULL )
{
fprintf(file_b, "+ ");
foutput_text_stat(file_b, cn->ptr);
}
else
{
copy_file(file_a, file_b, cn->pos, cn->size - 1);
}
putc('\n', file_b);
cn->size_b = ftell(file_b) - cn->pos_b;
sync_next++;
break;
}
restart_kom("Unreachable statement reached.");
}
/* If all texts are written, do some clean-up. */
if (sync_next == highest_text_no)
{
if ( ferror(file_b) != 0 )
{
log ("save_one_text(): ferror() detected.\n");
sync_state = sync_error;
return;
}
offset = ftell(file_b); /* Make sure that the entire file resides
on disk. This test seems to be necessary.
The data file has been corrupted at least
once. */
if (offset == -1)
{
log ("save_one_text(): ftell returned -1.\n");
sync_state = sync_error;
return;
}
rewind(file_b);
if ( ferror(file_b) != 0 )
{
log ("save_one_text(): rewind failed.\n");
sync_state = sync_error;
return;
}
fprintf(file_b, "CLEAN");
if ( ferror(file_b) != 0 )
{
log ("save_one_text(): fprintf(CLEAN) failed.\n");
sync_state = sync_error;
return;
}
if (fflush(file_b) != 0)
{
log ("save_one_text(): fflush failed.\n");
sync_state = sync_error;
return;
}
if ( ferror(file_b) != 0 )
{
log ("save_one_text(): ferror after fflush failed.\n");
sync_state = sync_error;
return;
}
if ( fclose(file_b) != 0 )
{
file_b = NULL;
log("Sync: fclose() failed in save_one_text. Deleting "
"file and retrying.\n");
remove(datafilename);
sync_state = sync_wait;
return;
}
file_b = fopen(datafilename, "rb");
if (file_b == NULL)
{
log("save_one_text(): failed to reopen file.\n");
remove (datafilename);
sync_state = sync_wait;
return;
}
if (fseek(file_b, 0, SEEK_END) != 0)
{
log("save_one_text(): fseek failed.\n");
sync_state = sync_error;
return;
}
offset2 = ftell (file_b);
if ( offset2 != offset )
{
log ("save_one_text(): ftell returns different offsets"
"(%l and %l).\n", offset, offset2);
sync_state = sync_error;
return;
}
fclose (file_b);
file_b = NULL;
sync_state = sync_ready;
BUG(("Sync ready\n"));
post_sync();
}
}
/*
* Sync_part() should be called often as long as it returns FALSE.
* Sync_part() returns TRUE when everything is written to a file.
* Sync_part() should be called once in a while even when it returns
* TRUE (because sync() checks to see if it is time to start yet
* another save.)
*/
Bool
sync_part(void)
{
static time_t last_sync_start = NO_TIME;
if ( last_sync_start == NO_TIME )
{
last_sync_start = time(NULL);
sync_state = sync_idle;
}
#ifdef LOGACCESSES
syncing_or_saving = 1;
#endif
switch(sync_state)
{
case sync_save_conf:
save_one_conf();
break;
case sync_save_pers:
save_one_pers();
break;
case sync_save_text:
save_one_text();
break;
case sync_ready:
sync_state = sync_idle;
return TRUE;
case sync_idle:
if ( difftime(time(NULL), last_sync_start) < 60 * SYNC_INTERVAL )
{
#ifdef LOGACCESSES
syncing_or_saving = 0;
#endif
return TRUE;
}
last_sync_start = time(NULL);
pre_sync();
break;
case sync_wait:
if ( difftime(time(NULL), last_sync_start) < 60 * SYNC_RETRY_INTERVAL )
{
#ifdef LOGACCESSES
syncing_or_saving = 0;
#endif
return TRUE;
}
last_sync_start = time(NULL);
pre_sync();
break;
case sync_error:
log("sync: Error saving new file. Discarding file and "
"trying again.\n");
fclose(file_b);
file_b = NULL;
remove(datafilename);
sync_state = sync_wait;
break;
default:
restart_kom("sync(): sync_state==%d", sync_state);
}
if ( file_b != NULL && ferror(file_b) != 0)
sync_state = sync_error;
#ifdef LOGACCESSES
syncing_or_saving = 0;
#endif
return FALSE;
}
static void
setup_small_conf(Conf_no conf_no,
Conference *conf_c)
{
small_conf_arr[ conf_no ] = alloc_small_conf();
s_strcpy(&small_conf_arr[ conf_no ]->name, conf_c->name);
small_conf_arr[ conf_no ]->type = conf_c->type;
small_conf_arr[ conf_no ]->highest_local_no
= (conf_c->texts.first_local_no - 1
+ conf_c->texts.no_of_texts );
small_conf_arr[ conf_no ]->nice = conf_c->nice;
}
extern Success
init_cache(void)
{
int i;
Cache_node *node;
Conference tmp_conf = EMPTY_CONFERENCE;
Person tmp_pers = EMPTY_PERSON;
Text_stat tmp_text = EMPTY_TEXT_STAT;
pers_mcb = create_cache_node_mcb(100, MAX_CONF);
conf_mcb = create_cache_node_mcb(100, MAX_CONF);
text_mcb = create_cache_node_mcb(100, MAX_TEXT);
#ifdef LOGACCESSES
if (logaccess_file)
{
logfile = fopen(logaccess_file, "a");
if (logfile)
log("Logging db accesses to %s.\n", logaccess_file);
else
log("Failed to open db log file %s. Ignoring -L option.\n",
logaccess_file);
}
#endif
LOGACC(lt_restart, time(NULL));
if ( (text_file = fopen(textfilename, "a+b")) == NULL )
{
restart_kom("ERROR: init_cache: can't open text file \"%s\"."
" errno = %d\n",
textfilename, errno);
}
if ( is_clean(datafilename) )
{
if ( (file_a = fopen(datafilename, "rb")) == NULL )
{
log("WARNING: init_cache: can't open datafile.\n");
return FAILURE;
}
log("MSG: init_cache: using datafile.\n");
}
else if ( is_clean(backupfilename) )
{
if ( (file_a = fopen(backupfilename, "rb")) == NULL )
{
log("WARNING: init_cache: can't open backupfile.\n");
return FAILURE;
}
log("MSG: init_cache: using backup file.\n");
}
else
{
log("WARNING: init_cache: can't find old data base.\n");
return FAILURE;
}
fseek(file_a, 6, SEEK_SET); /* skip clean/dirty flag. */
next_free_num = fparse_long(file_a); /* NEXT_FREE_NUM */
for ( i = 1; i < next_free_num; i++ ) /* CONFS */
{
fskipwhite(file_a);
switch(getc(file_a))
{
case '@':
zero_init_cache_node(conf_mcb, i);
break;
case '+':
LOGACC(lt_conf_def, i);
create_cache_node(conf_mcb, i);
node = get_conf_node(i);
node->s.exists = 1;
node->pos = ftell(file_a) - 1; /* Don't forget the '+' */
if ( fparse_conference(file_a, &tmp_conf) != OK )
restart_kom("init_cache(): fparse_conference failed. "
"i == %d\n", i);
node->size = ftell(file_a) - node->pos;
setup_small_conf(i, &tmp_conf);
clear_conference(&tmp_conf);
break;
}
}
build_matching_info();
for ( i = 1; i < next_free_num; i++ ) /* PERSONS */
{
fskipwhite(file_a);
switch(getc(file_a))
{
case '@':
zero_init_cache_node(pers_mcb, i);
break;
case '+':
LOGACC(lt_pers_def, i);
create_cache_node(pers_mcb, i);
node = get_pers_node(i);
node->s.exists = 1;
node->pos = ftell(file_a) - 1; /* Don't forget the '+' */
if ( fparse_person(file_a, &tmp_pers) != OK )
restart_kom("init_cache: fparse_person failed. i == %d\n", i);
node->size = ftell(file_a) - node->pos;
clear_person(&tmp_pers);
break;
}
}
next_text_num = fparse_long(file_a); /* NEXT_TEXT_NUM */
for ( i = 1; i < next_text_num; i++ ) /* TEXT_STATS */
{
fskipwhite(file_a);
switch(getc(file_a))
{
case '@':
zero_init_cache_node(text_mcb, i);
break;
case '+':
LOGACC(lt_text_def, i);
create_cache_node(text_mcb, i);
node = get_text_node(i);
node->s.exists = 1;
node->pos = ftell(file_a) - 1; /* Don't forget the '+' */
if ( fparse_text_stat(file_a, &tmp_text) != OK )
restart_kom("init_cache(): fparse_text_stat failed. i == %d\n",
i);
node->size = ftell(file_a) - node->pos;
clear_text_stat(&tmp_text);
break;
}
}
log("Read %d confs/persons and %d texts\n",
next_free_num, next_text_num);
return OK;
}
/* ramkomd compatibility: */
extern void
cache_sync(void)
{
}
extern void
cache_sync_all(void)
{
pre_sync();
while ( sync_part() != TRUE )
;
}
void
free_all_cache (void)
{
int i;
Cache_node *node;
#ifdef LOGACCESSES
if (logfile)
fclose(logfile);
#endif
for ( i = 0; i < next_free_num; i++ )
{
node = get_conf_node(i);
if ( node != NULL )
{
if ( node->snap_shot != NULL )
{
free_conference (node->snap_shot);
node->snap_shot = NULL;
}
if ( node->ptr != NULL )
{
free_conference (node->ptr);
node->ptr = NULL;
}
}
destruct_cache_node (conf_mcb, i);
node = get_pers_node(i);
if ( node != NULL )
{
if ( node->snap_shot != NULL )
{
free_person (node->snap_shot);
node->snap_shot = NULL;
}
if ( node->ptr != NULL )
{
free_person (node->ptr);
node->ptr = NULL;
}
}
destruct_cache_node (pers_mcb, i);
if ( small_conf_arr[i] != NULL )
{
free_small_conf (small_conf_arr[i]);
small_conf_arr[i] = NULL;
}
}
for ( i = 0; i < next_text_num; i++ )
{
node = get_text_node(i);
if ( node != NULL )
{
if ( node->snap_shot != NULL )
{
free_text_stat (node->snap_shot);
node->snap_shot = NULL;
}
if ( node->ptr != NULL )
{
free_text_stat (node->ptr);
node->ptr = NULL;
}
}
destruct_cache_node (text_mcb, i);
}
free_match_table(match_table);
free_cache_node_mcb(conf_mcb);
free_cache_node_mcb(text_mcb);
free_cache_node_mcb(pers_mcb);
sfree (match_table);
sfree (conf_table);
}
/* Is it allowed to delete this node from the cache? It is, unless
the node is locked, dirty, or contains a snap-shot. */
static Bool
throwable_p(Cache_node *node)
{
return (node->s.dirty == 0
&& node->snap_shot == NULL
&& node->lock_cnt == 0);
}
static void
limit_pers(void)
{
Cache_node *node;
int i;
node = pers_mcb->mru;
/* Skip first CACHE_PERSONS clean persons. */
for ( i = 0; node != NULL && i < CACHE_PERSONS; i++ )
{
while (node != NULL && !throwable_p(node))
node = node->next;
if ( node != NULL )
node = node->next;
}
/* Delete any remaining clean persons */
while ( node != NULL )
{
if (throwable_p(node))
{
unlink_pers_lru(node);
free_person (node->ptr);
node->ptr = NULL;
/* +++ delete cache-node if non-existent. */
}
node = node->next;
}
}
static void
limit_conf(void)
{
Cache_node *node;
int i;
node = conf_mcb->mru;
/* Skip first CACHE_CONFERENCES clean confs. */
for ( i = 0; node != NULL && i < CACHE_CONFERENCES; i++ )
{
while (node != NULL && !throwable_p(node))
node = node->next;
if ( node != NULL )
node = node->next;
}
/* Delete any remaining clean confs. */
while ( node != NULL )
{
if (throwable_p(node))
{
unlink_conf_lru(node);
free_conference (node->ptr);
node->ptr = NULL;
/* +++ delete if non-existent. */
}
node = node->next;
}
}
static void
limit_text_stat(void)
{
Cache_node *node;
int i;
node = text_mcb->mru;
/* Skip first CACHE_TEXT_STATS clean text_stats. */
for ( i = 0; node != NULL && i < CACHE_TEXT_STATS; i++ )
{
while (node != NULL && !throwable_p(node))
node = node->next;
if (node != NULL)
node = node->next;
}
/* Delete any remaining clean text_stats. */
while ( node != NULL )
{
if (throwable_p(node))
{
unlink_text_lru(node);
free_text_stat (node->ptr);
node->ptr = NULL;
/* +++ delete if non-existent. */
}
node = node->next;
}
}
/*
* Limit the number of 'clean' cache entries.
*/
EXPORT void
cache_limit_size(void)
{
limit_pers();
limit_conf();
limit_text_stat();
}
EXPORT void
dump_cache_mem_usage(FILE *fp)
{
fprintf(fp, "---simple-cache.c:\n"
"\tSmall_confs: %d\n",
no_of_allocated_small_confs);
}
EXPORT void
dump_cache_stats(FILE *fp)
{
fprintf(fp, "---simple-cache.c:\n");
fprintf(fp,
"\tPersons (cache size: %d):\n"
"\t hits: %lu\n"
"\t miss: %lu\n",
CACHE_PERSONS,
pers_mcb->hits,
pers_mcb->misses);
fprintf(fp,
"\tConferences (cache size: %d):\n"
"\t hits: %lu\n"
"\t miss: %lu\n",
CACHE_CONFERENCES,
conf_mcb->hits,
conf_mcb->misses);
fprintf(fp,
"\tText_stats (cache size: %d):\n"
"\t hits: %lu\n"
"\t miss: %lu\n",
CACHE_TEXT_STATS,
text_mcb->hits,
text_mcb->misses);
}
EXPORT int
query_next_text_num(void)
{
return next_text_num;
}
EXPORT void
tell_cache_garb_text(int running)
{
#ifdef LOGACCESSES
garb_running = running;
#endif
}