
/* $Id: ndbz.h,v 1.2 1995/09/29 17:40:52 wfp5p Exp $ */

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 1.2 $   $State: Exp $
 *
 *                      Copyright (c) 1988-1995 USENET Community Trust
 * 			Copyright (c) 1986,1987 Dave Taylor
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *      Bill Pemberton, Elm Coordinator
 *      flash@virginia.edu
 *
 *******************************************************************************
 * $Log: ndbz.h,v $
 * Revision 1.2  1995/09/29  17:40:52  wfp5p
 * Alpha 8 (Chip's big changes)
 *
 * Revision 1.1.1.1  1995/04/19  20:38:30  wfp5p
 * Initial import of elm 2.4 PL0 as base for elm 2.5.
 *
 ******************************************************************************/

/**  define file for ndbz for mail system.  **/

/*
 * Stdio buffer for .pag reads.  Buffering more than about 16 does not help
 * significantly at the densities we try to maintain, and the much larger
 * buffers that most stdios default to are much more expensive to fill.
 * With small buffers, stdio is performance-competitive with raw read(),
 * and it's much more portable.
 */
#ifndef NPAGBUF
#define	NPAGBUF	16
#endif

/*
 * Stdio buffer for base-file reads.
 */
#ifndef SHISTBUF
#define	SHISTBUF	512
#endif

/* for dbz and ndbz */
typedef struct {
	char *dptr;
	int dsize;
} datum;

/*
 * ANSI C says an offset into a file is a long, not an off_t, for some
 * reason.  This actually does simplify life a bit, but it's still nice
 * to have a distinctive name for it.  Beware, this is just for readability,
 * don't try to change this.
 */

/*
 * Big kludge: this is set up as 32-bit rather than a long so that ndbz db's 
 * will work across NFS on 64 bit machines as well as 32 bit machines.
 */

#define	of_t	int32
#define	SOF	(sizeof(of_t))

/*
 * We read configuration info from the .dir file into this structure,
 * so we can avoid wired-in assumptions for an existing database.
 *
 * Among the info is a record of recent peak usages, so that a new table
 * size can be chosen intelligently when rebuilding.  10 is a good
 * number of usages to keep, since news displays marked fluctuations
 * in volume on a 7-day cycle.
 */
struct dbzconfig {
	int olddbz;		/* .dir file empty but .pag not? */
	of_t tsize;		/* table size */
#	ifndef NMEMORY
#	define	NMEMORY	10	/* # days of use info to remember */
#	endif
#	define	NUSEDS	(1+NMEMORY)
	of_t used[NUSEDS];	/* entries used today, yesterday, ... */
	int valuesize;		/* size of table values, == SOF */
	int bytemap[SOF];	/* byte-order map */
	char casemap;		/* case-mapping algorithm (see cipoint()) */
	char fieldsep;		/* field separator in base file, if any */
	of_t tagenb;		/* unshifted tag-enable bit */
	of_t tagmask;		/* unshifted tag mask */
	int tagshift;		/* shift count for tagmask and tagenb */
};

/*
 * Data structure for recording info about searches.
 */
struct searcher {
	of_t place;		/* current location in file */
	int tabno;		/* which table we're in */
	int run;		/* how long we'll stay in this table */
	long hash;		/* the key's hash code (for optimization) */
	of_t tag;		/* tag we are looking for */
	int seen;		/* have we examined current location? */
	int aborted;		/* has i/o error aborted search? */
};
typedef struct dbz {
	FILE *dbz_basef;		/* descriptor for base file */
	char *dbz_basefname;		/* name for not-yet-opened base file */
	FILE *dbz_dirf;			/* descriptor for .dir file */
	int dbz_dirronly;		/* dirf open read-only? */
	FILE *dbz_pagf;			/* descriptor for .pag file */
	of_t dbz_pagpos;		/* posn in pagf; only search may set != -1 */
	int dbz_pagronly;		/* pagf open read-only? */
	of_t *dbz_corepag;		/* incore version of .pag file, if any */
	FILE *dbz_bufpagf;		/* well-buffered pagf, for incore rewrite */
	of_t dbz_tagbits;		/* pre-shifted tag mask */
	of_t dbz_taghere;		/* pre-shifted tag-enable bit */
	of_t dbz_tagboth;		/* tagbits|taghere */
	struct dbzconfig dbz_conf;
	int dbz_incore;
	of_t dbz_pagbuf[NPAGBUF];
	char dbz_basebuf[SHISTBUF];
	struct searcher dbz_srch;
	struct searcher *dbz_prevp;	/* &srch or FRESH */
	int dbz_mybmap[SOF];		/* my byte order (see mybytemap()) */
	int dbz_bytesame;		/* is database order same as mine? */
	int dbz_debug;			/* controlled by dbzdebug() */
	int dbz_written;		/* has a store() been done? */
	} DBZ;

/* FOO - should these declarations be ANSIfied? */

/* standard dbz functions */
extern DBZ *dbz_open();
extern datum dbz_fetch();
extern int dbz_store();
extern int dbz_delete();	/* not in dbz */
extern datum dbz_firstkey();	/* not in dbz */
extern datum dbz_nextkey();	/* not in dbz */
extern int dbz_close();		/* in dbz, but not in old dbm */

/* new stuff for dbz */
extern DBZ *dbz_fresh();
extern DBZ *dbz_again();
extern int dbz_sync();
extern long dbz_size();
extern int dbz_incore();
extern int dbz_cancel();
extern int dbz_debug();

/*
 * In principle we could handle unlimited-length keys by operating a chunk
 * at a time, but it's not worth it in practice.  Setting a nice large
 * bound on them simplifies the code and doesn't hurt anything.
 */
#define DBZMAXKEY	255
