/* Distributed Checksum Clearinghouse
 *
 * database definitions
 *
 * --C-LICENSE--
 * $Revision: 1.162 $
 */

#ifndef DB_H
#define DB_H

#include "srvr_defs.h"
#include <math.h>

extern u_char grey_on;
extern u_char ssd_mode;			/* 1=ultra fast disk */

#define DB_DCC_NAME	"dcc_db"
#define DB_GREY_NAME	"grey_db"
#define DB_HASH_SUFFIX	".hash"
#define DB_LOCK_SUFFIX	".lock"

#define WHITELIST_NM(g) ((g) ? "grey_whitelist" : "whitelist")

#define DB_VERSION3_STR "DCC checksum database version 3"
#define DB_VERSION4_STR "DCC checksum database version 4"
#define DB_VERSION5_STR "DCC checksum database version 5"
#define DB_VERSION6_STR "DCC checksum database version 6"
#define DB_VERSION_STR	DB_VERSION6_STR

#define HASH_MAGIC_STR	 "DCC hash 8"


#define DB_CP3(x,v) do {u_int32_t _v = v; (x)[0] = _v>>16;		\
    (x)[1] = _v>>8; (x)[2] = _v;} while (0)
#define DB_CP4(x,v) do {u_int32_t _v = v; (x)[0] = _v>>24;		\
    (x)[1] = _v>>16; (x)[2] = _v>>8; (x)[3] = _v;} while (0)
#define DB_EX3(x) ((((u_int32_t)(x)[0])<<16) + ((x)[1]<<8) + (x)[2])
#define DB_EX4(x) ((((u_int32_t)(x)[0])<<24) + (((u_int32_t)(x)[1])<<16) \
		   + ((x)[2]<<8) + (x)[3])
/* the least significant byte should be tested first */
#define DB_ZERO3(x) ((x)[2] == 0 && (x)[1] == 0 && (x)[0] == 0)
#define DB_ZERO4(x) ((x)[3] == 0 && (x)[2] == 0 && (x)[1] == 0 && (x)[0] == 0)


/* a single checksum in a database record */
typedef u_char	    DB_TGTS[3];		/* a compressed count */
typedef u_int64_t   DB_PTR;		/* database record offset */
typedef u_int32_t   DB_PTR_C;		/*	compressed by DB_PTR_CP() */
typedef struct {
    DB_PTR_C	prev;			/* previous record for this checksum */
    DB_TGTS	tgts;			/* accumulated reported targets */
    DCC_CK_TYPE_B type_fgs;
#    define	 DB_CK_FG_JUNK	0x80
#     define	  DB_CK_JUNK(ck) ((ck)->type_fgs & DB_CK_FG_JUNK)
#    define	 DB_CK_FG_OSPAM 0x40	/* obsolete report of spam */
#     define	  DB_CK_OSPAM(ck) ((ck)->type_fgs & DB_CK_FG_OSPAM)
#    define	 DB_CK_MASK	0x0f
#    define	 DB_CK_TYPE(ck) ((DCC_CK_TYPES)((ck)->type_fgs & DB_CK_MASK))
    DCC_SUM	sum;
} DB_RCD_CK;
#define DB_TGTS_CK_SET(ck,v) DB_CP3((ck)->tgts,v)
#define DB_TGTS_CK(ck) DB_EX3((ck)->tgts)

/* shape of a checksum database entry */
typedef struct {
    DCC_TS	ts;			/* original server's creation date */
    DCC_SRVR_ID srvr_id;		/* initial server */
#    define	 DB_RCD_ID(r)	((r)->srvr_id)
    DB_TGTS	tgts_del;		/* # target addresses or delete flag */
    u_char	fgs_num_cks;		/* # of cksums | flags */
#    define	 DB_RCD_FG_TRIM	    0x80    /* some checksums deleted */
#     define	  DB_RCD_TRIMMED(r)  ((r)->fgs_num_cks & DB_RCD_FG_TRIM)
#    define	 DB_RCD_FG_SUMRY    0x40    /* fake summary record */
#     define	  DB_RCD_SUMRY(r)   ((r)->fgs_num_cks & DB_RCD_FG_SUMRY)
#    define	 DB_RCD_FG_DELAY    0x20    /* delayed for fake summary */
#     define	  DB_RCD_DELAY(r)   ((r)->fgs_num_cks & DB_RCD_FG_DELAY)
/* # define	 DB_RCD_FG_	    0x10       unused */
#    define	 DB_RCD_FG_MASK	    0x0f    /* depends on DCC_MAX_FLOD_PATHS */
#    define	 DB_NUM_CKS(r)	    ((r)->fgs_num_cks & DB_RCD_FG_MASK)
    DB_RCD_CK	cks[DCC_DIM_CKS];
} DB_RCD;

#define DB_RCD_HDR_LEN (ISZ(DB_RCD) - ISZ(DB_RCD_CK)*DCC_DIM_CKS)
#define DB_RCD_LEN(r) (DB_RCD_HDR_LEN + DB_NUM_CKS(r) * ISZ(DB_RCD_CK))
#define DB_RCD_LEN_MAX sizeof(DB_RCD)

#define DB_TGTS_RCD_SET(r,v) DB_CP3((r)->tgts_del,v)
#define DB_TGTS_RCD_RAW(r) DB_EX3((r)->tgts_del)

#define DB_COOK_TGTS(raw) ((raw) == DCC_TGTS_DEL ? 0 : (raw))
#ifdef HAVE_GCC_INLINE			/* no prototypes without inline */
static inline DCC_TGTS
DB_TGTS_RCD(const DB_RCD *rcd) {return DB_COOK_TGTS(DB_TGTS_RCD_RAW(rcd));}
#else
#define DB_TGTS_RCD(rcd) DB_COOK_TGTS(DB_TGTS_RCD_RAW(rcd))
#endif

/* this allows databases of up to 48 GBytes */
#define DB_PTR_MULT	    ((DB_PTR)12)    /* gcd of all sizes of DB_RCD */
#define DB_PTR_CP(v)	    ((u_int32_t)((v) / DB_PTR_MULT))
#define DB_PTR_EX(x)	    ((x) * DB_PTR_MULT)

/* The kludge to speed conversion of database addresses to block numbers
 * and offsets on 32-bit systems */
#define DB_PTR_SHIFT 8
#ifdef HAVE_64BIT_LONG
#define DB_PTR2BLK_NUM(bn,s) ((bn) / (s))
#else
#define DB_PTR2BLK_NUM(bn,s) ((u_int32_t)((bn) >> DB_PTR_SHIFT)		\
			      / (s >> DB_PTR_SHIFT))
#endif

#define DB_PTR_NULL	    ((DB_PTR)0)
#define DB_PTR_BASE	    ISZ(DB_HDR)
#define DB_PTR_MAX	    DB_PTR_EX((((DB_PTR)1)<<(sizeof(DB_PTR_C)*8))-2)
#define DB_PTR_BAD	    DB_PTR_EX((((DB_PTR)1)<<(sizeof(DB_PTR_C)*8))-1)
#define DB_PTR_IS_BAD(l,c)  ((l) < DB_PTR_BASE || (l) >= (c))


typedef DCC_TS DB_SN;			/* database serial number */

#define FLOD_STALE_SECS		    (24*60*60)
/* non-spam expiration */
#define DB_EXPIRE_SECS_DEF	    (24*60*60)
#define DB_EXPIRE_SECS_MAX	    DCC_MAX_SECS
#define DB_EXPIRE_SECS_MIN	    (60*60)
#define DB_EXPIRE_SECS_DEF_MIN	    (2*60*60)
/* spam expiration */
#define DB_EXPIRE_SPAMSECS_DEF	    (30*24*60*60)
#define DB_EXPIRE_SPAMSECS_DEF_MIN  (1*24*60*60)
/* reputations need consistent expirations */
#define DB_EXPIRE_REP_SECS_DEF	    (24*60*60)
#define DB_EXPIRE_REP_SPAMSECS_DEF  (30*24*60*60)
/* so do server-IDs */
#define DB_EXPIRE_SERVER_ID	    (30*24*60*60)

/* re-announce spam this often */
#define DCC_OLD_SPAM_SECS   (DB_EXPIRE_SPAMSECS_DEF_MIN/2)


/* seconds to greylist or delay new mail messages
 *  RFC 2821 says SMTP clients should wait at least 30 minutes to retry,
 *  but 15 minutes seems more common than 30 minutes.  Many retry after
 *  only 5 minutes, and some after only 1 (one!) second.  However,
 *  many of those that retry after a few seconds keep trying for a minute
 *  or two. */
#define DEF_GREY_EMBARGO    270
#define MAX_GREY_EMBARGO    (24*60*60)

#define DEF_GREY_WINDOW	    (7*24*60*60)    /* wait as long as this */
#define MAX_GREY_WINDOW	    (10*24*60*60)
#define DEF_GREY_WHITE	    (63*24*60*60)   /* remember this long */
#define MAX_GREY_WHITE	    DB_EXPIRE_SECS_MAX


typedef DCC_TS	DB_EX_TS[DCC_DIM_CKS];
typedef struct {
    int32_t	all;			/* allsecs */
    int32_t	spam;			/* spamsecs */
} DB_EX_SEC;
typedef DB_EX_SEC DB_EX_SECS[DCC_DIM_CKS];

#define DCC_CK_OK_GREY_CLNT(t) ((t) > DCC_CK_INVALID			    \
				&& t <= DCC_CK_G_TRIPLE_R_BULK)
#define DCC_CK_OK_GREY_FLOD(t) ((t) == DCC_CK_BODY			    \
				|| ((t) >= DCC_CK_G_MSG_R_TOTAL		    \
				    && (t) <= DCC_CK_FLOD_PATH)		    \
				|| ((t) == DCC_CK_IP && grey_weak_ip))

#define DEF_FLOD_THOLDS(g,t) ((g) ? 1					    \
			      : t == DCC_CK_SRVR_ID ? 1 : BULK_THRESHOLD)

#define DCC_CK_TYPE_CLNT_OK(t)	DCC_CK_OK_GREY_CLNT(t)

#define DCC_CK_TYPE_DB_OK(t)	((t) > DCC_CK_INVALID && t <= DCC_CK_TYPE_LAST)

#define DCC_CK_TYPE_FLOD_OK(g,t) ((g) ? DCC_CK_OK_GREY_FLOD(t)		    \
				  : ((t) > DCC_CK_INVALID		    \
				     && (t) <= DCC_CK_FLOD_PATH))

typedef u_int32_t DB_NOKEEP_CKS;	/* bitmask of ignored checksums */
#define DB_SET_NOKEEP(map,t)	((map) |= (1<<(t)))
#define DB_RESET_NOKEEP(map,t)	((map) &= ~(1<<(t)))
#define DB_TEST_NOKEEP(map,t)	((map) & (1<<(t)))

/* relative fuzziness of checksums */
#define DCC_CK_FUZ_LVL_NO   1		/* least fuzzy */
#define DCC_CK_FUZ_LVL1	    2		/* somewhat fuzzy */
#define DCC_CK_FUZ_LVL2	    3		/* fuzzier */
#define DCC_CK_FUZ_LVL3	    4		/* reputations */
#define DCC_CK_FUZ_LVL_REP  DCC_CK_FUZ_LVL3
extern const u_char *db_ck_fuzziness;


typedef DB_PTR		    DB_HOFF;	/* byte offset into hash table */
typedef u_int32_t	    DB_HADDR;	/* index of a hash table entry */
#define MAX_HASH_ENTRIES    ((DB_HADDR)-1)

#define MIN_FREE_HASH_ENTRIES	1024	/* run dbclean at this size */
#define MIN_HASH_ENTRIES    (8*MIN_FREE_HASH_ENTRIES)
#define MIN_HASH_DIVISOR    ((MIN_HASH_ENTRIES*7)/8)

typedef u_char DB_HADDR_C[4];		/* compressed hash chain link */
#define DB_HADDR_CP(x,v)    DB_CP4(x,v)
#define DB_HADDR_EX(x)	    DB_EX4(x)
#define DB_HADDR_NULL	    0		/* no-answer from hashing & linking */
#define DB_HADDR_C_NULL(x)  DB_ZERO4(x)
#define DB_HADDR_INVALID(h) ((h) < DB_HADDR_BASE || (h) >= db_hash_len)
#define DB_HADDR_C_INVALID(h) DB_HADDR_INVALID(DB_HADDR_EX(h))

typedef u_char DB_PTR_HC[4];
#define DB_HPTR_CP(x,v) {u_int32_t _v = DB_PTR_CP(v);			\
    (x)[0] = _v>>24; (x)[1] = _v>>16; (x)[2] = _v>>8; (x)[3] = _v;}
#define DB_HPTR_EX(x) DB_PTR_EX(((x)[0]<<24) + ((x)[1]<<16)		\
				+ ((x)[2]<<8) + (x)[3])


/* shape of the magic string that starts a database */
typedef char DB_VERSION_BUF[64];
typedef struct {
    DB_VERSION_BUF version;		/* see DB_VERSION_STR */
    DB_PTR	db_csize;		/* size of database contents in bytes */
    u_int32_t	blksize;		/* size of one DB block */
    DB_SN	sn;			/* creation or expiration serial # */
    DCC_PTIME	cleared;		/* when created */
    DCC_PTIME	cleaned;		/* real instead of repair cleaning */
    DCC_PTIME	cleaned_cron;		/* cleaned by cron */
    DB_EX_TS	ex_spam;		/* recent expiration timestamps */
    DB_EX_TS	ex_all;			/* recent expiration timestamps */
    DB_EX_SECS	ex_secs;		/* recent expiration durations */
    DB_NOKEEP_CKS nokeep_cks;		/* ignore these checksums */
    u_int32_t	flags;
#    define DB_PARM_FG_GREY	0x01	/* greylist database */
#    define DB_PARM_FG_NEED_RWD	0x02	/* need to rewind floods from peers */
#    define DB_PARM_FG_EXP_SET	0x04	/* have explicit expiration durations */
#    define DB_PARM_FG_NO_CLR	0x08
#    define DB_PARM_FG_SSD	0x10	/* using ultra fast disk */
    DB_PTR	old_db_csize;		/* byte size at end of last cleaning */
    DB_PTR	db_added;		/* bytes previously added to database */
    DB_HADDR	hash_used;		/* recent # of entries used */
    DB_HADDR	old_hash_used;		/* entries used at last cleaning */
    DB_HADDR	hash_added;		/* entries added */
    DCC_PTIME	rate_secs;		/* denominator of rates */
#    define	 DB_MIN_RATE_SECS (12*60*60)
#    define	 DB_NEW_RATE_SECS ((7*24-1)*60*60)
#    define	 DB_GOOD_RATE_SECS (2*24*60*60)
#    define	 DB_MAX_RATE_SECS (60*24*60*60)
    DCC_PTIME	last_rate_sec;
    DB_HADDR	old_kept_cks;		/* reported checksums at cleaning */
    DB_PTR	min_confirm_pos;	/* flood after this */
    u_int32_t	failsafe_cleanings;	/* consecutive cleanings by dccd */
    DB_PTR	prev_db_added;
    DB_HADDR	prev_hash_added;
    DCC_PTIME	prev_rate_secs;
} DB_PARMS;
typedef union {
    DB_PARMS	p;
    char	c[256*3];
} DB_HDR;

#ifdef DB_VERSION5_STR
typedef struct {
    DCC_TGTS	unused;
    int32_t	all;
    int32_t	spam;
} DB_V5_EX_SEC;
typedef DB_V5_EX_SEC DB_V5_EX_SECS[DCC_DIM_CKS];
typedef struct {
    DB_VERSION_BUF version;
    DB_PTR	db_csize;
    u_int32_t	blksize;
    DB_SN	sn;
    time_t	cleared;
    time_t	cleaned;
    time_t	cleaned_cron;
    DB_EX_TS	ex_spam;
    DB_EX_TS	ex_all;
    DB_V5_EX_SECS ex_secs;
    DB_NOKEEP_CKS nokeep_cks;
    u_int	flags;
    DB_PTR	old_db_csize;
    DB_PTR	db_added;
    DB_HADDR	hash_used;
    DB_HADDR	old_hash_used;
    DB_HADDR	hash_added;
    time_t	rate_secs;
    time_t	last_rate_sec;
    DB_HADDR	old_kept_cks;
    DB_PTR	min_confirm_pos;
    u_int	failsafe_cleanings;
} DB_V5_PARMS;
#endif
#ifdef DB_VERSION4_STR
typedef struct {
    DB_VERSION_BUF version;
    DB_PTR	db_csize;
    u_int32_t	blksize;
    DB_SN	sn;
    time_t	cleared;
    time_t	cleaned;
    time_t	cleaned_cron;
    DB_EX_TS	ex_spam;
    DB_V5_EX_SECS ex_secs;
    DB_NOKEEP_CKS nokeep_cks;
    u_int	flags;
    DB_PTR	old_db_csize;
    DB_PTR	db_added;
    DB_HADDR	hash_used;
    DB_HADDR	old_hash_used;
    DB_HADDR	hash_added;
    time_t	rate_secs;
    time_t	last_rate_sec;
    DB_HADDR	old_kept_cks;
} DB_V4_PARMS;
#endif
#ifdef DB_VERSION3_STR
typedef struct {
    DB_VERSION_BUF version;
    DB_PTR	db_csize;
    u_int32_t	blksize;
    DB_SN	sn;
    DB_EX_TS	ex_spam;
    DB_V5_EX_SECS ex_secs;
    DB_NOKEEP_CKS nokeep_cks;
    DCC_TGTS	unused[DCC_DIM_CKS];
    u_int	flags;
#    define DB_PARM_V3_FG_GREY		0x01
#    define DB_PARM_V3_FG_SELF_CLEAN	0x02
#    define DB_PARM_V3_FG_SELF_CLEAN2	0x04
#    define DB_PARM_V3_FG_NEED_RWD	0x08
    DB_PTR	old_db_csize;
    DB_PTR	db_added;
    DB_HADDR	hash_used;
    DB_HADDR	old_hash_used;
    DB_HADDR	hash_added;
    time_t	rate_secs;
    time_t	last_rate_sec;
    DB_HADDR	old_kept_cks;
} DB_V3_PARMS;
#endif

/* shape of a database hash table entry */
typedef struct {
    DB_HADDR_C	fwd, bak;		/* hash collision chain */
    u_char	hv_type[2];		/* checksum type + some hash bits */
#    define	 HE_TYPE(e)	 ((DCC_CK_TYPES)((e)->hv_type[0] & 0xf))
#    define	 HE_IS_FREE(e)	 ((e)->hv_type[0] == 0)
#    define	 HE_MERGE(e,t,s) ((e)->hv_type[0] = ((((s)->b[0])<<4) + t),\
				  (e)->hv_type[1] = (s)->b[1])
#    define	 HE_CMP(e,t,s)	 ((e)->hv_type[1] == (s)->b[1]		\
				  && ((e)->hv_type[0]			\
				      == (u_char)((((s)->b[0])<<4) + t)))

    DB_PTR_HC	rcd;			/* record for this hash table entry */
} HASH_ENTRY;



/* the start of the hash table file */
typedef u_int32_t HCTL_FGS;
typedef struct {
    char	magic[16];
    HCTL_FGS	fgs;
#    define	 HCTL_FG_KCACHE_OK  0x1 /* 1=kernal cache contents valid */
#    define	 HCTL_FG_SYNC_OK    0x2	/* 1=disk contents valid */
    DB_HADDR    free_fwd;		/* hash table internal free list */
    DB_HADDR    free_bak;
#    define	 FREE_HADDR_END 1
    DB_HADDR    len;			/* size of file in entries */
    DB_HADDR    used;			/* entries actually used */
    DB_HADDR    divisor;		/* hash modulus */
    DB_PTR	db_csize;		/* copy of size of the database file */
    DCC_PTIME   sync_sec;
} HCTL;


/* index of the first real hash entry after the control data at the base */
#define DB_HADDR_BASE	((DB_HADDR)((sizeof(HCTL)+sizeof(HASH_ENTRY)-1) \
				    / sizeof(HASH_ENTRY)))

/* Adjust a hash table index by the control data at the base.
 * This is required when computing ratios of entries used to free entries
 * so that the ratio does not include the control data. */
#define ADJ_HLEN(l)	((int)((l)-DB_HADDR_BASE))  /* offset to length */


/* fix configure script if this changes */
#define DB_MIN_MIN_MBYTE    32
#define DB_DEF_MIN_MBYTE    64		/* a reasonable tiny default */
#define DB_PAD_MBYTE	    128		/* RAM for rate limiting blocks etc */
#define DB_PAD_BYTE	(DB_PAD_MBYTE*1024*1024)
#define DB_MAX_2G_MBYTE (2048-DB_PAD_MBYTE) /* <2 GByte on 32 bit machines */
#define DB_NEEDED_MBYTE	    DB_MAX_2G_MBYTE /* need at least this much RAM */
/* the database cannot exceed 48 GBytes because of DB_PTR_CP */
#define MAX_MAX_DB_MBYTE    (48*1024)
/*	fix INSTALL.html if those change */

/* Both database files are divided into blocks.
 * Each block is mmap()ed into one of DB_BUF_NUM buffers. */
typedef u_int DB_BLK_NUM;		/* index of a DB block */
typedef u_int32_t DB_BLK_OFF;		/* byte or hash entry offset */

typedef enum {
    DB_BUF_TYPE_FREE = 0,
    DB_BUF_TYPE_HASH,
    DB_BUF_TYPE_DB
} DB_BUF_TYPE;

/* 5 seconds between flushes ==> 2^16 flushes/day
 * 2^31 bytes flooded/day ==> 2^15 bytes/flush
 * 2^32 bytes of checksums + 2^31 bytes of hash table = 2^33 bytes/database
 * 2^33 bytes/database & 2^7 blocks ==> 2^26 bytes/block
 * 2^15 bytes/flush & 2^26 bytes/block ==> 2^11 parts/block
 * 2^6 bytes/dirty mask word & 2^11 parts/block ==> 2^5 dirty mask words
 * round up to 2^6 dirty mask words
 */
typedef u_long DB_BIT;
#define PARTBITS    (8*sizeof(DB_BIT))
#define	PARTWORDS   64
#define DB_BUF_NUM_PARTS (PARTWORDS*PARTBITS)

/* This bits show the need for write() in DB_BUF_FG_PRIVATE buffers
 * or the need for msync() in ordinary mmap() buffers. */
typedef struct {
    DB_BIT	    w[PARTWORDS];
    u_int	    num;
} DB_PART_MAP;
#define OFF2PNO(off)		((off) / bufpart_size)
#define PNO2WNO(pno)		((pno) / PARTBITS)
#define PNO2BIT(pno)		(((DB_BIT)1) << ((pno) % PARTBITS))
#define PNO2WORD(b,pno)		(&(b)->dirt.w[PNO2WNO(pno)])
#define PNO2WORD_URGENT(b,pno)	(&(b)->dirt_urgent.w[PNO2WNO(pno)])
#define GET_DIRT(b,pno)		((*PNO2WORD(b,pno)	  & PNO2BIT(pno)) != 0)
#define GET_DIRT_URGENT(b,pno)	((*PNO2WORD_URGENT(b,pno) & PNO2BIT(pno)) != 0)
#define SET_DIRT(b,pno)		(*PNO2WORD(b,pno)	 |= PNO2BIT(pno),   \
				 ++(b)->dirt.num)
#define SET_DIRT_URGENT(b,pno)	(*PNO2WORD_URGENT(b,pno) |= PNO2BIT(pno),   \
				 ++(b)->dirt_urgent.num)
#define CLR_DIRT(b,pno)		(*PNO2WORD(b,pno)	 &= ~PNO2BIT(pno),  \
				 --(b)->dirt.num)
#define CLR_DIRT_URGENT(b,pno)	(*PNO2WORD_URGENT(b,pno) &= ~PNO2BIT(pno),  \
				 --(b)->dirt_urgent.num)

typedef struct db_buf {
    struct db_buf *addr_fwd, *addr_bak, **hash;
    struct db_buf *older, *newer;
    union {
	void	    *v;
	HASH_ENTRY  *h;
	char	    *c;
    } buf;
    DB_BLK_NUM	blk_num;		/* block # in file */
    int		lock_cnt;
    DB_BUF_TYPE	buf_type;
    DB_PART_MAP	dirt;
    DB_PART_MAP	dirt_urgent;
    u_int	flags;
#    define	 DB_BUF_FG_PRIVATE	0x01	/* mmap(MAP_PRIVATE) used */
#    define	 DB_BUF_FG_ANON_EXTEND	0x02	/* new block in anon. memory */
} DB_BUF;

/* context for searching for or adding a record */
typedef struct db_st {
    struct db_st *fwd, *bak;
#	define DB_ST_BUSY ((struct db_st *)1)
    union {				/* pointer to data in buffer */
	char	    *c;
	void	    *v;
	HASH_ENTRY  *h;
	DB_RCD	    *r;
    } d;
    union {				/* database address */
	DB_HADDR    haddr;
	DB_PTR	    rptr;
    } s;
    DB_BUF	*b;
    const char	*bufend;
    const char	*file;
    int		lineno;
} DB_ST;

extern int db_failed_line;
extern const char *db_failed_file;
#define DB_ERROR_MSG(s) db_error_msg(__LINE__,__FILE__, "%s", s)
#define DB_ERROR_MSG2(s1,s2) db_error_msg(__LINE__,__FILE__, "%s: %s", s1,s2)

extern struct timeval db_time;
#define DB_IS_TIME(tgt,lim) DCC_IS_TIME(db_time.tv_sec, tgt, lim)
#define DB_ADJ_TIMER(tgt,lim,new) DCC_ADJ_TIMER(db_time.tv_sec, tgt, lim, new)

extern u_char dbclean_running;		/* this is dccd & dbclean is running */
extern int db_fd, db_hash_fd;
extern DCC_PATH db_nm, db_nm_path;
extern DCC_PATH db_hash_nm, db_hash_nm_path;
extern struct timeval db_locked;	/* 0 or when database was locked */
extern int db_debug;
extern DB_SN db_sn;

extern u_int sys_pagesize;

extern DB_HOFF db_hash_fsize;		/* size of hash table file */
extern DB_HADDR db_hash_len;		/* # of hash table entries */
extern DB_HADDR db_hash_divisor;	/* hash function modulus */
extern DB_HADDR db_hash_used;		/* # of hash table entries in use */
extern u_int db_hash_blk_len;		/* # of HASH_ENTRYs per block */
extern DB_HADDR db_max_hash_entries;	/* max size of hash table */
extern DB_PTR db_fsize;			/* size of database file */
extern DB_PTR db_csize;			/* size of database contents in bytes */
extern const DB_VERSION_BUF db_version_buf;
extern DB_PARMS db_parms;
extern DCC_TGTS db_tholds[DCC_DIM_CKS];
extern u_int db_blksize;		/* size of one DB block */

typedef struct {
    u_int   db_mmaps;
    u_int   hash_mmaps;
    u_int   adds;			/* reports added */
} DB_STATS;
extern DB_STATS db_stats;


/* If the two files were smaller than the typical mmap() limit of a fraction
 * of a GByte, they could be mmap()'ed directly.  They are often too large.
 *
 * Use a modest pool of buffers to map the DB hash table
 * and the checksum database.
 *
 * Most of the DB hash table is expected to fit in the application's memory.
 *
 * Use the same modest pool of buffers to map the database itself.
 * References to the database have a lot of locality, so the commonly used
 * checksums and counts should remain in memory.
 *
 * Common operating system limits on the number of mapped segments are
 * below 256 and so that is a bound on DB_BUF_NUM */
#define DB_BUF_NUM 128			/* maximum # of buffers */

extern DB_PTR db_max_rss;		/* maximum db resident set size */
extern DB_PTR db_max_byte;

extern time_t db_need_flush_secs;
#define DB_NEED_FLUSH_SECS	5


/* srvrlib/db.c */
extern void db_vfailure(int, const char *, int, DCC_EMSG *,
			const char *, va_list);
extern void db_failure(int, const char *, int, DCC_EMSG *,
		       const char *, ...) DCC_PF(5,6);
extern void db_error_msg(int, const char *, const char *, ...) DCC_PF(3,4);
extern void db_dirty_data(DB_ST *, u_char, u_int);
#define DIRTY_RCD(st,u)	    db_dirty_data(st,u, DB_RCD_LEN((st)->d.r))
extern DB_ST *get_db_st(const char *, int);
#define GET_DB_ST() get_db_st(__FILE__, __LINE__)
extern void free_db_st(DB_ST *);
typedef enum {
    DB_UNLOAD_RELEASE,			/* release buffers without msync() */
    DB_UNLOAD_INVALIDATE,		/* invalidate buffers & contents */
    DB_UNLOAD_ONE,			/* reduce resident set */
    DB_UNLOAD_ENOUGH,			/* unload until dbclean has room */
    DB_UNLOAD_REBOOT,			/* start closing for reboot */
    DB_UNLOAD_REBOOT_CLEAN,		/* start closing for clean reboot */
} DB_UNLOAD_MODE;
extern int db_unload(DCC_EMSG *, DB_UNLOAD_MODE);
extern u_char dbclean_flush(DCC_EMSG *);
typedef enum {
    DB_CLOSE_FORK,			/* clean after a fork */
    DB_CLOSE,				/* flush buffers to the kernel */
    DB_CLOSE_REBOOT,			/* discard the hash table */
    DB_CLOSE_STABLE,			/* fsync() */
    DB_CLOSE_DISCARD_ALL,		/* discard and invalidate all buffers */
    DB_CLOSE_NEW_DB,			/* switch to cleaned database */
} DB_CLOSE_MODE;
extern u_char unlink_whine(DCC_EMSG *, const char *, u_char);
extern u_char db_close(DB_CLOSE_MODE);
extern u_char lock_dbclean(DCC_EMSG *, const char *);
extern void unlock_dbclean(void);
extern u_int get_db_blksize(DB_PTR, u_int);
extern u_char db_buf_init(DB_PTR, u_int);
typedef u_int DB_OPEN_MODES;
# define DB_OPEN_RDONLY		    0x01
# define DB_OPEN_LOCK_WAIT	    0x02    /* wait to get lock */
# define DB_OPEN_LOCK_NOWAIT	    0x04    /* get lock but don't wait */
# define DB_OPEN_MSYNC		    0x08    /* use msync() instead of write() */
# define DB_OPEN_WRITE		    0x10    /* use write() instead of msync() */
# define DB_OPEN_DBCLEAN_DEFAULT    0x20    /* use default dbclean choices  */
# define DB_OPEN_DCCD_DEFAULT	    0x40    /* use default dccd choices  */
extern u_char db_open(DCC_EMSG *, int, const char *, const char *,
		      DB_HADDR, DB_OPEN_MODES);
extern u_char db_flush_parms(DCC_EMSG *);
#define DB_IS_LOCKED() (db_locked.tv_sec != 0)
extern int db_lock(void);
extern u_char db_unlock(void);
extern void dccd_flush(u_char);
extern DCC_TGTS db_sum_ck(DCC_TGTS, DCC_TGTS, DCC_CK_TYPES);
extern const char *size2str(char *, u_int, double, u_char);
extern double db_add_rate(const DB_PARMS *, u_char, u_char);
extern DB_NOKEEP_CKS def_nokeep_cks(void);
extern void set_db_tholds(DB_NOKEEP_CKS);
extern u_char db_map_rcd(DCC_EMSG *, DB_ST *, DB_PTR, int *);
extern DB_RCD_CK *db_map_rcd_ck(DCC_EMSG *, DB_ST *, DB_PTR, DCC_CK_TYPES);
extern DB_HADDR db_hash(DCC_CK_TYPES, const DCC_SUM *);
typedef enum {
    DB_FOUND_SYSERR=0,			/* fatal error */
    DB_FOUND_IT,
    DB_FOUND_EMPTY,			/* home slot empty */
    DB_FOUND_CHAIN,			/* not in chain--have last entry */
    DB_FOUND_INTRUDER			/* intruder in home slot */
} DB_FOUND;
extern DB_FOUND db_lookup(DCC_EMSG *, DCC_CK_TYPES, const DCC_SUM *,
			  DB_ST *, DB_ST *, DB_RCD_CK **);
extern u_char db_link_rcd(DCC_EMSG *, DB_ST *);
extern DB_PTR db_add_rcd(DCC_EMSG *, const DB_RCD *, DB_ST *);

#endif /* DB_H */
