Select Git revision
oop_adns_query.html
dbck-cache.c 16.08 KiB
/*
* $Id: dbck-cache.c,v 0.9 1992/02/26 18:45:15 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 very 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.
* Also save time as a time_t instead of a struct tm.
*/
static char *rcsid = "$Id: dbck-cache.c,v 0.9 1992/02/26 18:45:15 ceder Exp $";
/*
* All functions that can fail sets kom_errno to a suitable value
* if they fail.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <kom-errno.h>
#include <kom-types.h>
#include "s-collat-tabs.h"
#include <server/smalloc.h>
#include "cache.h"
#include <debug.h>
#include "lyskomd.h"
#include <parser.h>
#include "ram-parse.h"
#include "log.h"
#include "ram-output.h"
#include "com.h"
#include "connections.h"
#include "send-async.h"
#include "memory.h"
#include "dbck-cache.h"
#ifdef TIME_SYNC
# include <sys/resource.h>
#endif
#define EXPORT
#include "tmp-limits.h"
Person * pers_arr[ MAX_CONF ];
Conference * conf_arr[ MAX_CONF ];
Conf_type conf_type_arr[ MAX_CONF ];
String name_list [ MAX_CONF ]; /* "cache" list */
/* Global var auto init to NULL */
int next_free_num = 1;
Text_stat * text_arr[ MAX_TEXT ];
int next_text_num = 1;
/* Defined in ramkomd.c */
extern char datafilename[];
extern char backupfilename[];
extern char textfilename[];
static FILE *text_file = NULL;
static FILE *new_text_file = NULL; /* Used when garbage collecting. */
BUGDECL;
/* 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)
#define INRANGE(str, num, retval) if ( num == 0 || num >= next_free_num ) \
{ \
return retval; \
printf("%s: conf_no %d out of range 1 ... %d ", str, num, next_free_num); \
fflush(stdout); \
fflush(stderr); \
abort(); \
}
#define TEXT_RANGE(str, num, retval) if ( num == 0 || num >= next_text_num ) \
{ \
return retval;\
printf("Text_no out of range 1 ... %d ", next_text_num); \
printf(str); \
fflush(stdout); \
fflush(stderr); \
abort(); \
}
extern Conf_type
cached_get_conf_type (Conf_no conf_no)
{
return conf_arr [ conf_no ]->type;
}
#define IMPL(retval) if (1) { fflush(stderr); fflush(stdout); abort(); }
/*
* Various function calls to tell the cache that something is changed.
*/
void
mark_person_as_changed(Pers_no pers_no)
{
TRACE2("Person %d is changed\n", pers_no);
return;
}
void
mark_conference_as_changed(Conf_no conf_no)
{
TRACE2("Conf. %d is changed\n", conf_no);
return;
}
void
mark_text_as_changed( Text_no text_no )
{
TRACE2("Text %d is changed.\n", text_no);
TEXT_RANGE("mark_text_as_changed\n", text_no, (void)0);
}
/*
* Person-related calls
*/
extern Success
cached_create_person( Pers_no person )
{
TRACE2("Person %d is being created.\n", person);
INRANGE("cached_create_person\n", person, FAILURE);
if ( pers_arr[ person ] != NULL )
{
TRACE1("pers_arr not NULL");
fflush(stdout);
fflush(stderr);
abort();
}
pers_arr[ person ] = alloc_person();
return OK;
}
extern Person *
cached_get_person_stat( Pers_no person )
{
INRANGE("cached_get_person_stat\n", person, NULL);
TRACE2("cached_get_person_stat %d\n", person);
kom_errno = KOM_UNDEF_PERS;
return pers_arr[ person ];
}
/*
* Conference-related calls
*/
extern Conf_no /* Also cache the name */
cached_create_conf (String name)
{
Conference * conf_c;
Conf_no conf_no;
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++;
conf_c = alloc_conference();
conf_c->name = EMPTY_STRING;
s_strcpy(&conf_c->name, name);
TRACE2(" number %d\n", conf_no);
conf_arr[ conf_no ] = conf_c;
pers_arr[ conf_no ] = NULL;
return conf_no;
}
extern Success
cached_delete_conf( Conf_no conf )
{
INRANGE("cached_delete_conf()", conf, FAILURE);
if ( conf_arr[ conf ] == NULL )
{
kom_errno = KOM_UNDEF_CONF;
return FAILURE;
}
free_conference(conf_arr[ conf ]);
conf_arr[ conf ] = NULL;
return OK;
}
Success
cached_delete_person(Pers_no pers)
{
INRANGE("cached_delete_person()", pers, FAILURE);
if ( pers_arr[ pers ] == NULL )
{
kom_errno = KOM_UNDEF_PERS;
return FAILURE;
}
pers_arr[ pers ] = NULL;
return OK;
}
Success
cached_delete_text(Text_no text)
{
TEXT_RANGE("cached_delete_text()", text, FAILURE);
if ( text_arr[ text ] == NULL )
{
kom_errno = KOM_NO_SUCH_TEXT;
return FAILURE;
}
free_text_stat(text_arr[ text ]);
text_arr[ text ] = NULL;
return OK;
}
extern Conference *
cached_get_conf_stat( Conf_no conf_no )
{
INRANGE("cached_get_conf_stat\n", conf_no, NULL);
TRACE2("cached_get_conf_stat %d\n", conf_no);
kom_errno = KOM_UNDEF_CONF;
return conf_arr[ conf_no ];
}
/*
* Return TRUE if conf_no exists.
*/
Bool
cached_conf_exists(Conf_no conf_no)
{
return conf_arr[ conf_no ] != NULL ? TRUE : FALSE;
}
/*
* Calls to handle texts
*/
extern String
cached_get_text( Text_no text )
{
String the_string;
TEXT_RANGE("cached_get_text\n", text, EMPTY_STRING);
TRACE2("cached_get_text %d\n", text);
if ( text_arr[ text ] == NULL )
return EMPTY_STRING;
else
{
the_string.string = tmp_alloc( text_arr[text]->no_of_chars );
the_string.len = text_arr[text]->no_of_chars;
fseek(text_file, text_arr[ text ]->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 the_string;
}
}
extern Text_stat * /* NULL on error */
cached_get_text_stat( Text_no text )
{
kom_errno = KOM_NO_SUCH_TEXT;
TEXT_RANGE("cached_get_text_stat\n", text, NULL);
TRACE2("cached_get_text_stat %d\n", text);
return text_arr[ text ];
}
/*
* The text is set up with an empty misc-field. The misc field is
* later initialized by create_text.
*/
#if 0
extern Text_no
cached_create_text( String message)
{
Text_no tno;
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;
}
text_arr[ tno ] = alloc_text_stat();
text_arr[ tno ]->no_of_misc = 0;
text_arr[ tno ]->misc_items = NULL;
text_arr[ tno ]->no_of_marks = 0;
text_arr[ tno ]->no_of_lines = 0;
text_arr[ tno ]->no_of_chars = 0;
fseek(text_file, 0, SEEK_END);
text_arr[ tno ]->file_pos = ftell(text_file);
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);
TRACE2("cached_create_text -> %d\n", tno);
return tno;
}
#endif
void
cached_flush_text(Text_no text_no,
String message)
{
if ( text_no >= next_text_num )
{
log("cached_flush_text(%lu, string): only text %lu exists.",
(u_long) text_no, (u_long) next_text_num);
return;
}
fseek(new_text_file, 0, SEEK_END);
text_arr[ text_no ]->file_pos = ftell(new_text_file);
if ( fwrite(message.string, sizeof(char), message.len, new_text_file)
!= message.len )
{
log("WARNING: cached_flush_text: Couldn't write the text %d\n",
text_no);
}
fflush(new_text_file);
}
Text_no
traverse_text(Text_no seed)
{
seed++;
while ( seed < next_text_num && text_arr[ seed ] == NULL )
seed++;
return (seed == next_text_num) ? 0 : seed ;
}
Pers_no
traverse_person(Pers_no seed)
{
seed++;
while ( seed < next_free_num && pers_arr[ seed ] == NULL )
seed++;
return (seed == next_free_num) ? 0 : seed ;
}
Conf_no
traverse_conference(Conf_no seed)
{
seed++;
while ( seed < next_free_num && conf_arr[ seed ] == NULL )
seed++;
return (seed == next_free_num) ? 0 : seed ;
}
extern Garb_nice
cached_get_garb_nice (Conf_no conf_no)
{
return conf_arr [ conf_no ]->nice;
}
extern Local_text_no
cached_get_highest_local_no (Conf_no conf_no)
{
return ( conf_arr [ conf_no ]->texts.first_local_no
- 1 + conf_arr [ conf_no ]->texts.no_of_texts );
}
/* Lock a person struct in memory. Increase a referenc count. */
void
cached_lock_person(Pers_no pers_no)
{}
/* Decrease reference count. If zero, unlock person. */
void
cached_unlock_person(Pers_no pers_no)
{}
/* Lock a conf struct in memory. Increase a referenc count. */
void
cached_lock_conf(Conf_no conf_no)
{}
/* Decrease reference count. If zero, unlock conf. */
void
cached_unlock_conf(Conf_no conf_no)
{}
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;
}
}
#ifdef TIME_SYNC
static long
timerdiff(struct timeval a,
struct timeval b)
{
return a.tv_sec - b.tv_sec;
}
#endif
extern void /* Write out everything. */
cache_sync(void)
{
FILE *fp;
int i;
#ifdef TIME_SYNC
struct rusage start, after_confs, after_persons, after_text_stats,
after_text_masses;
time_t st, ac, ap, ats, atm;
void getrusage(int who, struct rusage *rusage);
#endif
#ifdef TIME_SYNC
getrusage(0, &start);
time(&st);
#endif
if ( is_clean(datafilename) )
{
if ( rename(datafilename, backupfilename) != 0 )
log("WARNING: cache_sync: can't backup.\n");
}
else
log("cache_sync: datafile not clean. No backup taken.\n");
if ( (fp=fopen(datafilename, "w") ) == NULL )
{
log("WARNING: cache_sync: can't open file to save in.\n");
return;
}
fprintf(fp, "DIRTY\n"); /* DIRTY-FLAG */
fprintf(fp, "%d\n", next_free_num); /* NEXT_FREE_NUM */
for ( i = 1; i < next_free_num; i++ ) /* CONFS */
{
if ( conf_arr[ i ] == NULL )
fprintf(fp, "@");
else
{
fprintf(fp, "+ ");
foutput_conference(fp, conf_arr[ i ]);
}
putc('\n', fp);
}
#ifdef TIME_SYNC
getrusage(0, &after_confs);
time(&ac);
#endif
for ( i = 1; i < next_free_num; i++ ) /* PERSONS */
{
if ( pers_arr[ i ] == NULL )
fprintf(fp, "@");
else
{
fprintf(fp, "+ %dH", PASSWD_LEN);
fwrite(pers_arr[ i ]->pwd, PASSWD_LEN, 1, fp);
foutput_person(fp, pers_arr[ i ]);
}
putc('\n', fp);
}
#ifdef TIME_SYNC
getrusage(0, &after_persons);
time(&ap);
#endif
fprintf(fp, "%d\n", next_text_num); /* NEXT_TEXT_NUM */
for ( i = 1; i < next_text_num; i++ ) /* TEXT_STATS */
{
if ( text_arr[ i ] == NULL )
fprintf(fp, "@");
else
{
fprintf(fp, "+ ");
foutput_text_stat(fp, text_arr[ i ]);
}
putc('\n', fp);
}
#ifdef TIME_SYNC
getrusage(0, &after_text_stats);
time(&ats);
getrusage(0, &after_text_masses);
time(&atm);
#endif
rewind(fp);
fprintf(fp, "CLEAN");
fclose(fp);
#ifdef TIME_SYNC
log("Sync ready.\n"
"User: %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
"Sys: %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
"Real: %4ld sec (%4ld conf, %4ld pers, %4ld stat, %4ld text)\n"
"Page faults: %4ld. Swapped: %4ld. Outblocked: %4ld.\n",
timerdiff(after_text_masses.ru_utime, start.ru_utime),
timerdiff(after_confs.ru_utime, start.ru_utime),
timerdiff(after_persons.ru_utime, after_confs.ru_utime),
timerdiff(after_text_stats.ru_utime, after_persons.ru_utime),
timerdiff(after_text_masses.ru_utime, after_text_stats.ru_utime),
timerdiff(after_text_masses.ru_stime, start.ru_stime),
timerdiff(after_confs.ru_stime, start.ru_stime),
timerdiff(after_persons.ru_stime, after_confs.ru_stime),
timerdiff(after_text_stats.ru_stime, after_persons.ru_stime),
timerdiff(after_text_masses.ru_stime, after_text_stats.ru_stime),
(u_long)difftime(atm, st),
(u_long)difftime(ac, st),
(u_long)difftime(ap, ac),
(u_long)difftime(ats, ap),
(u_long)difftime(atm, ats),
after_text_masses.ru_majflt - start.ru_majflt,
after_text_masses.ru_nswap - start.ru_nswap,
after_text_masses.ru_oublock - start.ru_oublock);
#endif
}
void
cache_open_new_text_file(void)
{
if ( ( new_text_file = fopen(textfilename, "w")) == NULL )
{
log("Can't open file to save new texts. Goodbye.\n");
exit(1);
}
}
extern Success
init_cache(void)
{
FILE *fp = NULL;
int i;
extern int vflag; /* from dbck.c */
new_text_file = NULL;
if ( (text_file = fopen(textfilename, "rb")) == NULL )
{
perror(textfilename);
restart_kom("ERROR: init_cache: can't open text file %s.\n",
textfilename);
}
if ( is_clean(datafilename) )
{
if ( (fp = 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 ( (fp = 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(fp, 6, SEEK_SET); /* skip clean/dirty flag. */
next_free_num = fparse_long(fp); /* NEXT_FREE_NUM */
if ( vflag )
log("Reading %d conferences, starting at pos %d.\n",
next_free_num-1, ftell(fp));
for ( i = 1; i < next_free_num; i++ ) /* CONFS */
{
fskipwhite(fp);
switch(getc(fp))
{
case '@':
conf_arr[ i ] = NULL;
break;
case '+':
conf_arr[ i ] = alloc_conference();
if ( fparse_conference(fp, conf_arr[ i ]) != OK )
restart_kom("init_cache(): fparse_conference failed. "
"i == %d\n", i);
name_list[i] = EMPTY_STRING;
s_strcpy(&name_list[i], conf_arr[ i ]->name);
break;
}
}
if ( vflag )
log("Reading %d persons, starting at pos %d.\n",
next_free_num-1, ftell(fp));
for ( i = 1; i < next_free_num; i++ ) /* PERSONS */
{
fskipwhite(fp);
switch(getc(fp))
{
case '@':
pers_arr[ i ] = NULL;
break;
case '+':
pers_arr[ i ] = alloc_person();
if ( fparse_person(fp, pers_arr[ i ]) != OK )
restart_kom("init_cache: fparse_person failed. i == %d\n", i);
break;
}
}
next_text_num = fparse_long(fp); /* NEXT_TEXT_NUM */
if ( vflag )
log("Reading %d texts, starting at pos %d.\n",
next_text_num-1, ftell(fp));
for ( i = 1; i < next_text_num; i++ ) /* TEXT_STATS */
{
fskipwhite(fp);
switch(getc(fp))
{
case '@':
text_arr[ i ] = NULL;
break;
case '+':
text_arr[ i ] = alloc_text_stat();
if ( fparse_text_stat(fp, text_arr[ i ]) != OK )
restart_kom("init_cache(): fparse_text_stat failed. i == %d\n",
i);
break;
}
}
log("Read %d confs/persons and %d texts, eof at %d\n",
next_free_num-1, next_text_num-1, ftell(fp));
fclose(fp);
return OK;
}