#ifndef	ACL_ZDB_INCLUDE_H
#define	ACL_ZDB_INCLUDE_H

#include "../stdlib/acl_define.h"
#include "../stdlib/acl_vstring.h"
#include "../stdlib/acl_fhandle.h"

#ifndef ACL_CLIENT_ONLY

typedef struct ZDB ZDB;
typedef struct ZDB_KEY_HDR ZDB_KEY_HDR;
typedef struct ZDB_BLK ZDB_BLK;
typedef struct ZDB_BLK_OFF ZDB_BLK_OFF;
typedef struct ZDB_DAT_HDR ZDB_DAT_HDR;
typedef struct ZDB_KEY_STORE ZDB_KEY_STORE;
typedef struct ZDB_DAT_STORE ZDB_DAT_STORE;
typedef struct ZDB_IO ZDB_IO;

/* ƫĳ */
typedef acl_int64 zdb_off_t;

/* Ͷ */
typedef acl_int64 zdb_key_t;

/* ֵ洢пݿƫ */
typedef int zdb_lnk_t;

/* ̷Ϣ */
typedef struct ZDB_DISK {
	acl_int64 limit;	/* ÷ */
	acl_int64 count;	/* Ŀǰ÷ѷ */
	char *path;		/* ̷· */
	int   idisk;		/* ô̷ */
	int   priority;		/* Ȩȼ */
	int  *dat_ifiles;	/* ǰõ dat_ifile ֵ洢ļ */
	int   dat_ifiles_size;	/* dat_ifiles ĴС */
} ZDB_DISK;

/*  zdb_open() ʱ ZDB ö */
typedef struct ZDB_CFG {
	const char *key_path;	/* 洢ڵĸĿ¼ */
	zdb_key_t key_begin;	/* ֵʼֵ */
	zdb_key_t key_limit;	/* ÿ洢ļм */
	acl_int64 dat_limit;	/* ÿֵ洢ļݵ */

	int   key_cache_max;	/* ü洢 IO ʱ󻺴ݿ */
	int   key_cache_timeout; /* ü洢 IO ʱÿĹʱ */
	int   key_wback_max;	/* ü洢 IO ʱд󻺴ݿ */

	int   dat_nstep;	/* ֵ洢ݿʱĲֵ */
	int   blk_dlen;		/* ֵ洢ݿݲֵĳ(ûݳ) */
	int   dat_cache_max;	/* ֵ洢 IO ʱ󻺴ݿ */
	int   dat_cache_timeout; /* ֵ洢 IO ʱÿĹʱ */
	int   dat_wback_max;	/* ֵ洢 IO ʱд󻺴ݿ */
} ZDB_CFG;

/* ZDB ṹ */
struct ZDB {
	/* public */

	char *dbname;		/* ݿ */
	char *key_path;		/* ZDB key洢· */
	unsigned int oflags;	/* ʱı־λ */
#define	ZDB_FLAG_LINK_BUSY	(1 << 0)  /* ֵ洢еռݿ */
#define	ZDB_FLAG_OPEN_LOCK	(1 << 1)  /* Լģʽ򿪴洢 */
#define	ZDB_FLAG_CACHE_DAT	(1 << 2)  /* Ƿ񻺴ֵ洢 */
#define	ZDB_FLAG_CACHE_KEY	(1 << 3)  /* Ƿ񻺴洢 */
#define	ZDB_FLAG_SLICE_KEY	(1 << 4)  /* ֵ洢ʱǷڴƬʽ */
#define	ZDB_FLAG_SLICE_DAT	(1 << 5)  /* ü洢ʱǷڴƬʽ */

	unsigned int status;	/* ״̬λ */
#define	ZDB_STAT_KEY_NEW	(1 << 0)  /* ¼ */

	/* private */

	zdb_key_t key_begin;	/* м洢ʼֵ */
	zdb_key_t key_limit;	/* ÿ洢мĸֵ */
	int   key_cache_max;	/* ü洢 IO ʱ󻺴ݿ */
	int   key_cache_timeout; /* ü洢 IO ʱÿĹʱ */
	int   key_wback_max;	/* ü洢 IO ʱд󻺴ݿ */

	acl_int64 dat_limit;	/* ֵ洢ֵ洢 */
	int   blk_dlen;		/* ֵ洢ݿÿ鵥Ԫ */
	int   dat_nstep;	/* ֵ洢ÿݿĸ */
	int   dat_cache_max;	/* ֵ洢 IO ʱ󻺴ݿ */
	int   dat_cache_timeout; /* ֵ洢 IO ʱÿĹʱ */
	int   dat_wback_max;	/* ֵ洢 IO ʱд󻺴ݿ */

	ZDB_DISK *dat_disks;	/* ֵ洢̷ */

	int   (*key_get)(ZDB*, zdb_key_t, ZDB_BLK_OFF*);
	int   (*key_set) (ZDB*, zdb_key_t, const ZDB_BLK_OFF*);

	ZDB_BLK *(*dat_get)(ZDB*, const ZDB_BLK_OFF*, zdb_key_t*, size_t*);
	int   (*dat_add)(ZDB*, zdb_key_t, const void*, int);
	int   (*dat_update)(ZDB*, zdb_key_t, const ZDB_BLK_OFF*,
			const void*, size_t);

	/* private */

	/* Ϊʱ */

	ACL_VSTRING *path_tmp;	/* ʱõĴ洢ļȫ·, ҪΪ˲ */
	int   blk_count_tmp;	/* ʱõĿ, ҪΪ˲ */
	int   inode_tmp;	/* ʱõ·ţҪΪ˲ */
};

/* xxx: Ϊ˱֤ƽ̨ԣ½ṹ嶼4ֽڶ */

#ifdef	ACL_SUNOS5
#pragma pack(4)
#else
#pragma pack(push, 4)
#endif

/* ֵ洢ͷ */
struct ZDB_DAT_HDR {
	acl_int64  limit;	/* ֵ洢ֵ洢 */
	acl_int64  size;	/* ǰֵ洢ļѾĶ洢ĸ */
	acl_int64  count;	/* ǰֵ洢е */
	acl_int64  reserv1;	/* ֶ */
	acl_int64  reserv2;	/* ֶ */
	acl_int64  reserv3;	/* ֶ */
	acl_int64  reserv4;	/* ֶ */
	int   nstep;		/* ÿʱֵ洢ļСʱĲֵС */
	int   blk_hdr_dlen;	/* ֵ洢ÿݵͷ: ZDB_BLK_HDR.sizeof */
	int   blk_dlen;		/* ֵ洢ݿÿ鵥Ԫ */
	int   blk_count;	/* ֵ洢еݿл */

	/* һпλõʵλõļ㹫ʽΪ:
	 * zdb_off_t off_head = ZDB_DAT_HDR.sizeof +
	 *     ZDB_DAT_HDR.ihead_idle * (ZDB_DAT_HDR.blk_hdr_dlen +
	 *         ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count);
	 */
	zdb_lnk_t ihead_idle;

	/* һݿλõʵλõļ㹫ʽΪ:
	 * zdb_off_t off_head = ZDB_DAT_HDR.sizeof +
	 *     ZDB_DAT_HDR.ihead_busy * (ZDB_DAT_HDR.blk_hdr_dlen +
	 *         ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count);
	 */
	zdb_lnk_t ihead_busy;
	zdb_lnk_t itail_busy;
	int   dummy;		/* ֤8ֽڶ */
};

/* 洢ͷ */
struct ZDB_KEY_HDR {
	zdb_key_t  key_limit;	/* ü洢 */
	zdb_key_t  key_count;	/* ǰм */
	zdb_key_t  key_begin;	/* ʼֵ */
	acl_int64  reserv1;	/* ֶ */
	acl_int64  reserv2;	/* ֶ */
	acl_int64  reserv3;	/* ֶ */
	acl_int64  reserv4;	/* ֶ */
};

/* ݵͷṹ */
typedef struct ZDB_BLK_HDR {
	zdb_key_t  key;		/* Ӧڼ洢еļ */

	/* ʶݿλ, У, ͬʱ֤ 8 ֽڶ */
	zdb_lnk_t  blk_ilnk;

	/*  inext_idle ݿӳһ, ֵΪ -1 ʾ
	 * ǿп, һпλ, һпʵλõļ㹫ʽΪ:
	 * zdb_off_t off_next = ZDB_BLK_HDR.sizeof +
	 *     ZDB_BLK_HDR.inext_idle * (ZDB_BLK_HDR.blk_hdr_dlen +
	 *         ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count);
	 */
	zdb_lnk_t  inext_idle;

#ifdef	ZDB_LINK_BUSY
	/*  inext_busy/iprev_busy ռݿӳһ˫, ֵΪ -1
	 * ʾռÿ, һռÿλ, һռÿʵλõļ㹫ʽΪ:
	 * zdb_off_t off_next = ZDB_BLK_HDR.sizeof +
	 *     ZDB_BLK_HDR.inext_busy * (ZDB_BLK_HDR.blk_hdr_dlen +
	 *         ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count);
	 * zdb_off_t off_prev = ZDB_BLK_HDR.sizeof +
	 *     ZDB_BLK_HDR.inext_prev * (ZDB_BLK_HDR.blk_hdr_dlen +
	 *         ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count);
	 */
	zdb_lnk_t  inext_busy;
	zdb_lnk_t  iprev_busy;
#endif
} ZDB_BLK_HDR;

/* 洢д洢ֵ洢ƫ */
struct ZDB_BLK_OFF {
	zdb_off_t offset;	/* ƫϢ */
	int   inode;		/* ·Ϣ */
};

/* ݽṹ */
struct ZDB_BLK {
	ZDB_BLK_HDR hdr;
	char  dat[1];		/* ֵ洢ÿݵ */
};

#ifdef	ACL_SUNOS5
#pragma pack(0)  /* ȡ4ֽڶ */
#else
#pragma pack(pop)  /* ȡ4ֽڶ */
#endif

/* ͨô洢ṹ */
typedef struct ZDB_STORE {
	ACL_FHANDLE fhandle;	/* ļ */
	ZDB *db;		/* ö */
	ZDB_IO *io;		/* IO  */
	int   cache_max;	/* ô洢 IO ʱ󻺴ݿ */
	int   cache_timeout;	/* ô洢 IO ʱÿĹʱ */
	int   wback_max;	/* дݿ */

	unsigned int flag;	/* ־λ */
#define	STORE_FLAG_KEY		(1 << 0)  /* ʾǼ洢 */
#define	STORE_FLAG_DAT		(1 << 1)  /* ʾֵ洢 */
#define	STORE_FLAG_IO_SLICE	(1 << 2)  /* Ƿ ZDB_IO ڴƬ䷽ʽ */

	/* for acl_iterator */

	/* ȡͷ */
	const void *(*iter_head)(ACL_ITER*, struct ZDB_STORE*);
	/* ȡһ */
	const void *(*iter_next)(ACL_ITER*, struct ZDB_STORE*);
} ZDB_STORE;

/* 洢 */
struct ZDB_KEY_STORE {
	ZDB_STORE store;
	ZDB_KEY_HDR hdr;	/* 洢ͷ */
};


/* ֵ洢 */
struct ZDB_DAT_STORE {
	ZDB_STORE store;
	ZDB_DAT_HDR hdr;	/* ֵ洢ͷ */
};

#ifdef	__cplusplus
extern "C" {
#endif

/*-------------------------  in zdb_test.c  ----------------------------------*/

/**
 * zdb Ժ
 */
ACL_API void zdb_test(const char *cmd);

/*----------------------------   in zdb.c   ----------------------------------*/

/* in zdb.c */

/**
 * ʼʱҪʼ zdb
 */
ACL_API void zdb_init(void);

/**
 * ˳ǰҪͷ zdb ڲһЩԴ
 */
ACL_API void zdb_end(void);

/**
 * ZDBϢ
 * @param db {ZDB*}
 */
ACL_API void zdb_sync(ZDB *db);

/**
 * 򿪻򴴽һ ZDB ݿ
 * @param dbname {const char*} ZDB ݿ
 * @param oflags {unsigned int}  ZDB ʱı־λ
 * @param cfg {const ZDB_CFG*}  ZDB ʱö
 * @return {ZDB*} ZDB ݿ
 */
ACL_API ZDB *zdb_open(const char *dbname, unsigned int oflags, const ZDB_CFG *cfg);

/**
 * ر ZDB ݿ
 * @param db {ZDB*} ZDB ݿ
 */
ACL_API void zdb_close(ZDB *db);

/**
 *  ZDB ݿвӦֵ
 * @param db {ZDB*} ZDB ݿ
 * @param key {zdb_key_t} ֵ
 * @param size {size_t*} ָǿҲѯҲǿ洢ѯݳ,
 *   ZDB_BLK.dat д洢ݵĳ
 * @param blk_off_buf {ZDB_BLK_OFF*} ǿ洢ֵƫλ
 * @return {ZDB_BLK*} NULL: δҵ; !NULL: ZDB_BLK->dat Ϊûݵĵַ,
 *   ZDB_BLK  acl_myfree()/1 ͷ
 * ע:
 *   size ַָǿʱߵͱ size_t Ͷ int ͣΪ
 *  64λ size_t Ϊ8ֽڳȣ int Ϊ4ֽڳȣڲڶ size ֵַ
 *  ʱԶ size_t ʵռ䳤ȸֵߵ size Ϊ int ͣ
 *  ͻֿռԽ󣬴ӶʹĪ⣬ valgrind
 *  Ҳ鲻!
 */
ACL_API ZDB_BLK *zdb_lookup(ZDB *db, zdb_key_t key, size_t *size, ZDB_BLK_OFF *blk_off_buf);

/**
 *  ZDB_BLK ȡû
 * @param b {ZDB_BLK*}
 * @return {void*}
 */
#define	zdb_blk_data(b)	((b)->dat)

/**
 * ͷ zdb_lookup()/3 صݿռ
 * @param b {ZDB_BLK*}
 */
#define	zdb_blk_free(b)	acl_myfree((b))

/**
 * ӻ ZDB ݿе
 * @param db {ZDB*} ZDB ݿ
 * @param key {zdb_key_t} ֵ
 * @param blk_off_saved {const ZDB_BLK_OFF*} ϴε zdb_lookup()/4 ʱķؽ,
 *  ӶͨظòѯЧ, ڵ zdb_lookup()/4 ʱؽΪ,
 *   zdb_update()/5 ʱ뽫ֵ NULL
 * @param dat {const void*}  key Ӧݵַ
 * @param len {size_t} dat ݳ
 * @return {int} 0: δ»; -1: ; 1: ɹ
 */
ACL_API int zdb_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off_saved,
	const void *dat, size_t len);

/*--------------------------------- in zdb_key.c -----------------------------*/

/**
 * ͬ洢ͷ
 * @param store {ZDB_KEY_STORE*} ֵ洢
 * @return {int} -1: error, > 0 ok
 */
ACL_API int key_store_header_sync(ZDB_KEY_STORE *store);

/**
 * ݼֵ򿪼洢
 * @param db {ZDB*}
 * @param key {zdb_key_t} ֵ
 * @return {ZDB_KEY_STORE*} !NULL: ok; NULL: error
 */
ACL_API ZDB_KEY_STORE *zdb_key_store_open(ZDB *db, zdb_key_t key);

/**
 * ļ򿪼洢
 * @param db {ZDB*}
 * @param filepath {const char*} ļ
 * @return {ZDB_KEY_STORE*} !NULL: ok; NULL: error
 */
ACL_API ZDB_KEY_STORE *zdb_key_store_open2(ZDB *db, const char *filepath);

/**
 * رռ洢
 * @param store {ZDB_KEY_STORE*} 洢
 */
ACL_API void zdb_key_store_close(ZDB_KEY_STORE *store);

/**
 * ü洢мλõֵλֵ
 * @param db {ZDB*}
 * @param key {zdb_key_t}
 * @param blk_off {const ZDB_BLK_OFF*}
 * @return {int} 0: ok; -1: error
 */
ACL_API int zdb_key_set(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off);

/**
 * ݼֵӼ洢ȡøüӦλ
 * @param db {ZDB*}
 * @param key {zdb_key_t} ֵ
 * @param blk_off {ZDB_BLK_OFF*} 洢Ķ
 * @return {int} 1: ʾ鵽, 0: ʾδ鵽, -1: ʾ
 */
ACL_API int zdb_key_get(ZDB *db, zdb_key_t key, ZDB_BLK_OFF *blk_off);

/**
 * ѯ洢ͷ״̬
 * @param db {ZDB*}
 * @param filepath {const char*} 洢ļȫ·
 * @param key_hdr {ZDB_KEY_HDR*} ż洢ͷϢڴַ
 * @return {int} 0: ok; -1: error
 */
ACL_API int zdb_key_status(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr);

/**
 * 洢еļ״̬
 * @param db {ZDB*}
 * @param filepath {const char*} 洢ļȫ·
 * @param key_hdr {ZDB_KEY_HDR*} ǿż洢ͷϢڴַ
 * @return {int} 0: ok; -1: error
 */
ACL_API int zdb_key_check3(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr);
ACL_API int zdb_key_check(ZDB_KEY_STORE *store, ZDB_KEY_HDR *key_hdr);

/**
 * ʼ洢
 * @param db {ZDB*}
 * @param key_begin {zdb_key_t} ʼֵ
 * @param key_end {zdb_key_t} ֵ
 * @return {int} 0: ok; -1: error
 */
ACL_API int zdb_key_init(ZDB *db, zdb_key_t key_begin, zdb_key_t key_end);
/*--------------------------------- in zdb_dat.c -----------------------------*/

/**
 * ֵͬ洢ͷ
 * @param store {ZDB_DAT_STORE*} ֵ洢
 * @return {int} -1: error, > 0 ok
 */
ACL_API int dat_store_header_sync(ZDB_DAT_STORE *store);

/**
 * رֵ洢
 * @param store {ZDB_DAT_STORE*} ֵ洢
 */
ACL_API void zdb_dat_store_close(ZDB_DAT_STORE *store);

/**
 * 򿪻򴴽ֵ洢
 * @param filepath {const char*} ֵ洢ļȫ·
 * @return {ZDB_DAT_STORE*} !NULL: ok; NULL: error
 */
ACL_API ZDB_DAT_STORE *zdb_dat_store_open(ZDB *db, const char *filepath);

/**
 * ֵ洢ȡöӦ
 * @param db {ZDB*}
 * @param blk_off {const ZDB_BLK_OFF*}
 * @param key {zdb_key_t*} 洢ֵ
 * @param size {size_t*} 洢ݵĳ
 * @return {void*} ݵַҵΪգҲΪ, Ϊ,
 *  Ҫ zdb_blk_free()/1 ͷ
 * ע:
 *   size ַָǿʱߵͱ size_t Ͷ int ͣΪ
 *  64λ size_t Ϊ8ֽڳȣ int Ϊ4ֽڳȣڲڶ size ֵַ
 *  ʱԶ size_t ʵռ䳤ȸֵߵ size Ϊ int ͣ
 *  ͻֿռԽ󣬴ӶʹĪ⣬ valgrind
 *  Ҳ鲻!
 */
ACL_API ZDB_BLK *zdb_dat_get(ZDB *db, const ZDB_BLK_OFF *blk_off,
	zdb_key_t *key, size_t *size);

/**
 * ֵ洢
 * @param db {ZDB*}
 * @param key {zdb_key_t} ֵ
 * @param dat {const void*} ݵַ
 * @param len {size_t} dat ݳ
 * @return {int} 0: ûи; 1: ݸ; -1: 
 */
ACL_API int zdb_dat_add(ZDB *db, zdb_key_t key, const void *dat, int len);

/**
 * ֵ洢еϢ
 * @param db {ZDB*}
 * @param key {zdb_key_t} 
 * @param blk_off {const ZDB_BLK_OFF*} 洢ڼ洢ӦֵλϢ
 * @param dat {const void*} ݵַ
 * @param len {size_t} dat ݳ
 * @return {int} 0: ûи; 1: ݸ; -1: 
 */
ACL_API int zdb_dat_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off,
	const void *dat, size_t len);

/**
 * ȡֵ洢ͷϢ
 * @param db {ZDB*}
 * @param filepath {const char*} ֵ洢ļ
 * @param dat_hdr {ZDB_DAT_HDR*} 洢
 * @retur {int} 0: ok; -1: error
 */
ACL_API int zdb_dat_stat(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr);

/**
 * ֵ洢еݿȷ
 * @param db {ZDB*}
 * @param filepath {const char*} ֵ洢ļ
 * @param dat_hdr {ZDB_DAT_HDR*} ǿ洢ֵ洢ͷϢ
 * @return {int} 0: ok; -1: error
 */
ACL_API int zdb_dat_check3(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr);
ACL_API int zdb_dat_check(ZDB_DAT_STORE *store, ZDB_DAT_HDR *dat_hdr);

/*--------------------   in zdb_key_walk.c -----------------------------------*/
ACL_API int zdb_key_walk(ZDB *db, int (*walk_fn)(ZDB_KEY_STORE *store));

/*--------------------   in zdb_dat_walk.c -----------------------------------*/
ACL_API int zdb_dat_walk(ZDB *db, int (*walk_fn)(ZDB_DAT_STORE *store));

/*--------------------   in zdb_key_iter.c -----------------------------------*/

/*--------------------   in zdb_dat_iter.c -----------------------------------*/
/**
 * ֵ洢ĵ
 * @param store {ZDB_DAT_STORE*}
 * @param read_data {int} ǷҪȡݿеݲ, !0: ʾȡݿе
 *  ݲ; 0: ȡݿеͷ
 */
ACL_API void zdb_dat_iter_set(ZDB_DAT_STORE *store, int read_data);

#ifdef	__cplusplus
}
#endif

#endif /* ACL_CLIENT_ONLY */
#endif
