/************************************************************************ * 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 #include #include #include #include #include #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); }