/************************************************************************
* 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,0);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);
}
syntax highlighted by Code2HTML, v. 0.9.1