1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
/************************************************************************
* Routines to interface with db *
* *
* Copyright (c) 1998, S.R. van den Berg, The Netherlands *
* #include "README" *
************************************************************************/
#ifdef RCS
static /*const*/char rcsid[]=
"$Id: dbops.c,v 1.13 1998/05/13 16:57:39 srb Exp $";
#endif
#include "config.h"
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#include "sdb.h"
#include "dbops.h"
#define MX(a,b) ((a)>(b)?(a):(b))
#define STRLEN(x) (sizeof(x)-1)
#define MS(a,b) MX(STRLEN(a),STRLEN(b))
const char statedbfile[]=STATE_DB,cplib[]=CUCIPOP_LIB;
static const char dblockshare[]="__db_lock.share",
dbmpoolshare[]="__db_mpool.share";
static DB_ENV dbenv;
static DB*db;
static int dbisopen,dbinited,dbrecover;
static DBC*cs;
static dounlink(const char*file)
{ char buf[STRLEN(cplib)+1+
MX(STRLEN(statedbfile),MS(dblockshare,dbmpoolshare))+1];
strcpy(buf,cplib);buf[STRLEN(cplib)]='/';strcpy(buf+STRLEN(cplib)+1,file);
unlink(buf);
}
static void tryrecovery();
void initappdb()
{ if(!dbinited)
{ memset(&dbenv,0,sizeof dbenv);dbenv.mp_size=MEMORY_CACHE;
dbinited=!db_appinit(cplib,0,&dbenv,
/*DB_INIT_LOG|*/DB_INIT_LOCK|DB_CREATE|DB_INIT_MPOOL/*|DB_USE_ENVIRON*/);
#ifdef USE_DB
if(!dbrecover&&!dbinited)
tryrecovery();
#endif
}
}
void exitappdb()
{ if(dbinited)
db_appexit(&dbenv),dbinited=0;
}
static void tryrecovery()
{ dbrecover++;exitappdb();
dounlink(dblockshare);dounlink(dbmpoolshare);
initappdb();
}
void opendb()
{ int retry=2;
if(!dbinited)
return;
for(;;)
{ int reterrno;
if(dbrecover>1)
dounlink(statedbfile);
if(reterrno=db_open(statedbfile,DB_HASH,
DB_CREATE,0622,&dbenv,(void*)0,&db))
{ syslog(LOG_ALERT,"Can't open %s %d",statedbfile,reterrno);
if(reterrno!=EPERM&&reterrno!=EINVAL||!retry--)
break;
tryrecovery();syslog(LOG_ALERT,"Attempting recovery %s",statedbfile);
}
else
{ dbisopen=1;
break;
}
}
}
void closedb()
{ if(dbisopen)
{ if(cs)
cs->c_close(cs),cs=0;
db->close(db,0),dbisopen=0;
}
}
static int checkrecover(int reterrno)
{ if(reterrno==EPERM)
{ closedb();
syslog(LOG_ALERT,"Database %s corrupted, attempt recovery",statedbfile);
tryrecovery();opendb();
}
return reterrno;
}
static DBT d,k;
int maxage(time_t dif)
{ return dif<-MAXSTATEAGE||dif>MAXSTATEAGE;
}
struct stateinfo*getstate(const char*key,time_t curt)
{ if(!dbisopen)
return 0;
;{ static time_t lastcheck;
if(lastcheck!=curt)
{ lastcheck=curt;
if(!cs)
{ db->cursor(db,0,&cs);d.data="";d.size=1;
if(!db->get(db,0,&d,&k,0))
cs->c_get(cs,&k,&d,DB_SET);
}
if(!(cs->c_get(cs,&k,&d,DB_NEXT)&&cs->c_get(cs,&k,&d,DB_FIRST))&&
!(k.size==1&&!*(char*)k.data)&& /* exception for \0 entry */
(d.size!=sizeof(struct stateinfo)||
maxage(curt-((struct stateinfo*)d.data)->lastsuccess)&&
maxage(curt-((struct stateinfo*)d.data)->lastabort)))
cs->c_del(cs,0),cs->c_get(cs,&k,&d,DB_PREV);
d.data="";d.size=1;db->put(db,0,&d,&k,0);
}
}
k.size=strlen(key);k.data=(char*)key;
if(checkrecover(db->get(db,0,&k,&d,0)))
return 0;
if(d.size!=sizeof(struct stateinfo))
{ db->del(db,0,&k,0);
return 0;
}
return d.data;
}
void putstate(const char*key,const struct stateinfo*state)
{ if(!dbisopen)
return;
k.size=strlen(key);k.data=(char*)key;d.data=(char*)state;d.size=sizeof*state;
db->put(db,0,&k,&d,0);
}
|