summaryrefslogtreecommitdiff
path: root/qdbm/depot.c
diff options
context:
space:
mode:
Diffstat (limited to 'qdbm/depot.c')
-rw-r--r--qdbm/depot.c2219
1 files changed, 0 insertions, 2219 deletions
diff --git a/qdbm/depot.c b/qdbm/depot.c
deleted file mode 100644
index 717335b8..00000000
--- a/qdbm/depot.c
+++ /dev/null
@@ -1,2219 +0,0 @@
-/*************************************************************************************************
- * Implementation of Depot
- * Copyright (C) 2000-2007 Mikio Hirabayashi
- * This file is part of QDBM, Quick Database Manager.
- * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
- * Lesser General Public License as published by the Free Software Foundation; either version
- * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
- * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
- * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA.
- *************************************************************************************************/
-
-
-#define QDBM_INTERNAL 1
-
-#include "depot.h"
-#include "myconf.h"
-
-#define DP_FILEMODE 00644 /* permission of a creating file */
-#define DP_MAGICNUMB "[DEPOT]\n\f" /* magic number on environments of big endian */
-#define DP_MAGICNUML "[depot]\n\f" /* magic number on environments of little endian */
-#define DP_HEADSIZ 48 /* size of the reagion of the header */
-#define DP_LIBVEROFF 12 /* offset of the region for the library version */
-#define DP_FLAGSOFF 16 /* offset of the region for flags */
-#define DP_FSIZOFF 24 /* offset of the region for the file size */
-#define DP_BNUMOFF 32 /* offset of the region for the bucket number */
-#define DP_RNUMOFF 40 /* offset of the region for the record number */
-#define DP_DEFBNUM 8191 /* default bucket number */
-#define DP_FBPOOLSIZ 16 /* size of free block pool */
-#define DP_ENTBUFSIZ 128 /* size of the entity buffer */
-#define DP_STKBUFSIZ 256 /* size of the stack key buffer */
-#define DP_WRTBUFSIZ 8192 /* size of the writing buffer */
-#define DP_FSBLKSIZ 4096 /* size of a block of the file system */
-#define DP_TMPFSUF MYEXTSTR "dptmp" /* suffix of a temporary file */
-#define DP_OPTBLOAD 0.25 /* ratio of bucket loading at optimization */
-#define DP_OPTRUNIT 256 /* number of records in a process of optimization */
-#define DP_NUMBUFSIZ 32 /* size of a buffer for a number */
-#define DP_IOBUFSIZ 8192 /* size of an I/O buffer */
-
-/* get the first hash value */
-#define DP_FIRSTHASH(DP_res, DP_kbuf, DP_ksiz) \
- do { \
- const unsigned char *_DP_p; \
- int _DP_ksiz; \
- _DP_p = (const unsigned char *)(DP_kbuf); \
- _DP_ksiz = DP_ksiz; \
- if((_DP_ksiz) == sizeof(int)){ \
- memcpy(&(DP_res), (DP_kbuf), sizeof(int)); \
- } else { \
- (DP_res) = 751; \
- } \
- while(_DP_ksiz--){ \
- (DP_res) = (DP_res) * 31 + *(_DP_p)++; \
- } \
- (DP_res) = ((DP_res) * 87767623) & INT_MAX; \
- } while(FALSE)
-
-/* get the second hash value */
-#define DP_SECONDHASH(DP_res, DP_kbuf, DP_ksiz) \
- do { \
- const unsigned char *_DP_p; \
- int _DP_ksiz; \
- _DP_p = (const unsigned char *)(DP_kbuf) + DP_ksiz - 1; \
- _DP_ksiz = DP_ksiz; \
- for((DP_res) = 19780211; _DP_ksiz--;){ \
- (DP_res) = (DP_res) * 37 + *(_DP_p)--; \
- } \
- (DP_res) = ((DP_res) * 43321879) & INT_MAX; \
- } while(FALSE)
-
-/* get the third hash value */
-#define DP_THIRDHASH(DP_res, DP_kbuf, DP_ksiz) \
- do { \
- int _DP_i; \
- (DP_res) = 774831917; \
- for(_DP_i = (DP_ksiz) - 1; _DP_i >= 0; _DP_i--){ \
- (DP_res) = (DP_res) * 29 + ((const unsigned char *)(DP_kbuf))[_DP_i]; \
- } \
- (DP_res) = ((DP_res) * 5157883) & INT_MAX; \
- } while(FALSE)
-
-enum { /* enumeration for a record header */
- DP_RHIFLAGS, /* offset of flags */
- DP_RHIHASH, /* offset of value of the second hash function */
- DP_RHIKSIZ, /* offset of the size of the key */
- DP_RHIVSIZ, /* offset of the size of the value */
- DP_RHIPSIZ, /* offset of the size of the padding bytes */
- DP_RHILEFT, /* offset of the offset of the left child */
- DP_RHIRIGHT, /* offset of the offset of the right child */
- DP_RHNUM /* number of elements of a header */
-};
-
-enum { /* enumeration for the flag of a record */
- DP_RECFDEL = 1 << 0, /* deleted */
- DP_RECFREUSE = 1 << 1 /* reusable */
-};
-
-
-/* private function prototypes */
-static int dpbigendian(void);
-static char *dpstrdup(const char *str);
-static int dplock(int fd, int ex, int nb);
-static int dpwrite(int fd, const void *buf, int size);
-static int dpseekwrite(int fd, int off, const void *buf, int size);
-static int dpseekwritenum(int fd, int off, int num);
-static int dpread(int fd, void *buf, int size);
-static int dpseekread(int fd, int off, void *buf, int size);
-static int dpfcopy(int destfd, int destoff, int srcfd, int srcoff);
-static int dpgetprime(int num);
-static int dppadsize(DEPOT *depot, int ksiz, int vsiz);
-static int dprecsize(int *head);
-static int dprechead(DEPOT *depot, int off, int *head, char *ebuf, int *eep);
-static char *dpreckey(DEPOT *depot, int off, int *head);
-static char *dprecval(DEPOT *depot, int off, int *head, int start, int max);
-static int dprecvalwb(DEPOT *depot, int off, int *head, int start, int max, char *vbuf);
-static int dpkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz);
-static int dprecsearch(DEPOT *depot, const char *kbuf, int ksiz, int hash, int *bip, int *offp,
- int *entp, int *head, char *ebuf, int *eep, int delhit);
-static int dprecrewrite(DEPOT *depot, int off, int rsiz, const char *kbuf, int ksiz,
- const char *vbuf, int vsiz, int hash, int left, int right);
-static int dprecappend(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
- int hash, int left, int right);
-static int dprecover(DEPOT *depot, int off, int *head, const char *vbuf, int vsiz, int cat);
-static int dprecdelete(DEPOT *depot, int off, int *head, int reusable);
-static void dpfbpoolcoal(DEPOT *depot);
-static int dpfbpoolcmp(const void *a, const void *b);
-
-
-
-/*************************************************************************************************
- * public objects
- *************************************************************************************************/
-
-
-/* String containing the version information. */
-const char *dpversion = _QDBM_VERSION;
-
-
-/* Get a message string corresponding to an error code. */
-const char *dperrmsg(int ecode){
- switch(ecode){
- case DP_ENOERR: return "no error";
- case DP_EFATAL: return "with fatal error";
- case DP_EMODE: return "invalid mode";
- case DP_EBROKEN: return "broken database file";
- case DP_EKEEP: return "existing record";
- case DP_ENOITEM: return "no item found";
- case DP_EALLOC: return "memory allocation error";
- case DP_EMAP: return "memory mapping error";
- case DP_EOPEN: return "open error";
- case DP_ECLOSE: return "close error";
- case DP_ETRUNC: return "trunc error";
- case DP_ESYNC: return "sync error";
- case DP_ESTAT: return "stat error";
- case DP_ESEEK: return "seek error";
- case DP_EREAD: return "read error";
- case DP_EWRITE: return "write error";
- case DP_ELOCK: return "lock error";
- case DP_EUNLINK: return "unlink error";
- case DP_EMKDIR: return "mkdir error";
- case DP_ERMDIR: return "rmdir error";
- case DP_EMISC: return "miscellaneous error";
- }
- return "(invalid ecode)";
-}
-
-
-/* Get a database handle. */
-DEPOT *dpopen(const char *name, int omode, int bnum){
- char hbuf[DP_HEADSIZ], *map, c, *tname;
- int i, mode, fd, inode, fsiz, rnum, msiz, *fbpool;
- struct stat sbuf;
- time_t mtime;
- DEPOT *depot;
- assert(name);
- mode = O_RDONLY;
- if(omode & DP_OWRITER){
- mode = O_RDWR;
- if(omode & DP_OCREAT) mode |= O_CREAT;
- }
- if((fd = open(name, mode, DP_FILEMODE)) == -1){
- dpecodeset(DP_EOPEN, __FILE__, __LINE__);
- return NULL;
- }
- if(!(omode & DP_ONOLCK)){
- if(!dplock(fd, omode & DP_OWRITER, omode & DP_OLCKNB)){
- close(fd);
- return NULL;
- }
- }
- if((omode & DP_OWRITER) && (omode & DP_OTRUNC)){
- if(ftruncate(fd, 0) == -1){
- close(fd);
- dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
- return NULL;
- }
- }
- if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode) ||
- (sbuf.st_ino == 0 && lstat(name, &sbuf) == -1)){
- close(fd);
- dpecodeset(DP_ESTAT, __FILE__, __LINE__);
- return NULL;
- }
- inode = sbuf.st_ino;
- mtime = sbuf.st_mtime;
- fsiz = sbuf.st_size;
- if((omode & DP_OWRITER) && fsiz == 0){
- memset(hbuf, 0, DP_HEADSIZ);
- if(dpbigendian()){
- memcpy(hbuf, DP_MAGICNUMB, strlen(DP_MAGICNUMB));
- } else {
- memcpy(hbuf, DP_MAGICNUML, strlen(DP_MAGICNUML));
- }
- sprintf(hbuf + DP_LIBVEROFF, "%d", _QDBM_LIBVER / 100);
- bnum = bnum < 1 ? DP_DEFBNUM : bnum;
- bnum = dpgetprime(bnum);
- memcpy(hbuf + DP_BNUMOFF, &bnum, sizeof(int));
- rnum = 0;
- memcpy(hbuf + DP_RNUMOFF, &rnum, sizeof(int));
- fsiz = DP_HEADSIZ + bnum * sizeof(int);
- memcpy(hbuf + DP_FSIZOFF, &fsiz, sizeof(int));
- if(!dpseekwrite(fd, 0, hbuf, DP_HEADSIZ)){
- close(fd);
- return NULL;
- }
- if(omode & DP_OSPARSE){
- c = 0;
- if(!dpseekwrite(fd, fsiz - 1, &c, 1)){
- close(fd);
- return NULL;
- }
- } else {
- if(!(map = malloc(bnum * sizeof(int)))){
- close(fd);
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return NULL;
- }
- memset(map, 0, bnum * sizeof(int));
- if(!dpseekwrite(fd, DP_HEADSIZ, map, bnum * sizeof(int))){
- free(map);
- close(fd);
- return NULL;
- }
- free(map);
- }
- }
- if(!dpseekread(fd, 0, hbuf, DP_HEADSIZ)){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- if(!(omode & DP_ONOLCK) &&
- ((dpbigendian() ? memcmp(hbuf, DP_MAGICNUMB, strlen(DP_MAGICNUMB)) != 0 :
- memcmp(hbuf, DP_MAGICNUML, strlen(DP_MAGICNUML)) != 0) ||
- *((int *)(hbuf + DP_FSIZOFF)) != fsiz)){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- bnum = *((int *)(hbuf + DP_BNUMOFF));
- rnum = *((int *)(hbuf + DP_RNUMOFF));
- if(bnum < 1 || rnum < 0 || fsiz < DP_HEADSIZ + bnum * sizeof(int)){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- msiz = DP_HEADSIZ + bnum * sizeof(int);
- map = mmap(0, msiz, PROT_READ | ((mode & DP_OWRITER) ? PROT_WRITE : 0), MAP_SHARED, fd, 0);
- if(map == MAP_FAILED){
- close(fd);
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- return NULL;
- }
- tname = NULL;
- fbpool = NULL;
- if(!(depot = malloc(sizeof(DEPOT))) || !(tname = dpstrdup(name)) ||
- !(fbpool = malloc(DP_FBPOOLSIZ * 2 * sizeof(int)))){
- free(fbpool);
- free(tname);
- free(depot);
- munmap(map, msiz);
- close(fd);
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return NULL;
- }
- depot->name = tname;
- depot->wmode = (mode & DP_OWRITER);
- depot->inode = inode;
- depot->mtime = mtime;
- depot->fd = fd;
- depot->fsiz = fsiz;
- depot->map = map;
- depot->msiz = msiz;
- depot->buckets = (int *)(map + DP_HEADSIZ);
- depot->bnum = bnum;
- depot->rnum = rnum;
- depot->fatal = FALSE;
- depot->ioff = 0;
- depot->fbpool = fbpool;
- for(i = 0; i < DP_FBPOOLSIZ * 2; i += 2){
- depot->fbpool[i] = -1;
- depot->fbpool[i+1] = -1;
- }
- depot->fbpsiz = DP_FBPOOLSIZ * 2;
- depot->fbpinc = 0;
- depot->align = 0;
- return depot;
-}
-
-
-/* Close a database handle. */
-int dpclose(DEPOT *depot){
- int fatal, err;
- assert(depot);
- fatal = depot->fatal;
- err = FALSE;
- if(depot->wmode){
- *((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
- *((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
- }
- if(depot->map != MAP_FAILED){
- if(munmap(depot->map, depot->msiz) == -1){
- err = TRUE;
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- }
- }
- if(close(depot->fd) == -1){
- err = TRUE;
- dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
- }
- free(depot->fbpool);
- free(depot->name);
- free(depot);
- if(fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- return err ? FALSE : TRUE;
-}
-
-
-/* Store a record. */
-int dpput(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode){
- int head[DP_RHNUM], next[DP_RHNUM];
- int i, hash, bi, off, entoff, ee, newoff, rsiz, nsiz, fdel, mroff, mrsiz, mi, min;
- char ebuf[DP_ENTBUFSIZ], *tval, *swap;
- assert(depot && kbuf && vbuf);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- if(ksiz < 0) ksiz = strlen(kbuf);
- if(vsiz < 0) vsiz = strlen(vbuf);
- newoff = -1;
- DP_SECONDHASH(hash, kbuf, ksiz);
- switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, TRUE)){
- case -1:
- depot->fatal = TRUE;
- return FALSE;
- case 0:
- fdel = head[DP_RHIFLAGS] & DP_RECFDEL;
- if(dmode == DP_DKEEP && !fdel){
- dpecodeset(DP_EKEEP, __FILE__, __LINE__);
- return FALSE;
- }
- if(fdel){
- head[DP_RHIPSIZ] += head[DP_RHIVSIZ];
- head[DP_RHIVSIZ] = 0;
- }
- rsiz = dprecsize(head);
- nsiz = DP_RHNUM * sizeof(int) + ksiz + vsiz;
- if(dmode == DP_DCAT) nsiz += head[DP_RHIVSIZ];
- if(off + rsiz >= depot->fsiz){
- if(rsiz < nsiz){
- head[DP_RHIPSIZ] += nsiz - rsiz;
- rsiz = nsiz;
- depot->fsiz = off + rsiz;
- }
- } else {
- while(nsiz > rsiz && off + rsiz < depot->fsiz){
- if(!dprechead(depot, off + rsiz, next, NULL, NULL)) return FALSE;
- if(!(next[DP_RHIFLAGS] & DP_RECFREUSE)) break;
- head[DP_RHIPSIZ] += dprecsize(next);
- rsiz += dprecsize(next);
- }
- for(i = 0; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i] >= off && depot->fbpool[i] < off + rsiz){
- depot->fbpool[i] = -1;
- depot->fbpool[i+1] = -1;
- }
- }
- }
- if(nsiz <= rsiz){
- if(!dprecover(depot, off, head, vbuf, vsiz, dmode == DP_DCAT)){
- depot->fatal = TRUE;
- return FALSE;
- }
- } else {
- tval = NULL;
- if(dmode == DP_DCAT){
- if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
- if(!(tval = malloc(head[DP_RHIVSIZ] + vsiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- memcpy(tval, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ]), head[DP_RHIVSIZ]);
- } else {
- if(!(tval = dprecval(depot, off, head, 0, -1))){
- depot->fatal = TRUE;
- return FALSE;
- }
- if(!(swap = realloc(tval, head[DP_RHIVSIZ] + vsiz + 1))){
- free(tval);
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- tval = swap;
- }
- memcpy(tval + head[DP_RHIVSIZ], vbuf, vsiz);
- vsiz += head[DP_RHIVSIZ];
- vbuf = tval;
- }
- mi = -1;
- min = -1;
- for(i = 0; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i+1] < nsiz) continue;
- if(mi == -1 || depot->fbpool[i+1] < min){
- mi = i;
- min = depot->fbpool[i+1];
- }
- }
- if(mi >= 0){
- mroff = depot->fbpool[mi];
- mrsiz = depot->fbpool[mi+1];
- depot->fbpool[mi] = -1;
- depot->fbpool[mi+1] = -1;
- } else {
- mroff = -1;
- mrsiz = -1;
- }
- if(!dprecdelete(depot, off, head, TRUE)){
- free(tval);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(mroff > 0 && nsiz <= mrsiz){
- if(!dprecrewrite(depot, mroff, mrsiz, kbuf, ksiz, vbuf, vsiz,
- hash, head[DP_RHILEFT], head[DP_RHIRIGHT])){
- free(tval);
- depot->fatal = TRUE;
- return FALSE;
- }
- newoff = mroff;
- } else {
- if((newoff = dprecappend(depot, kbuf, ksiz, vbuf, vsiz,
- hash, head[DP_RHILEFT], head[DP_RHIRIGHT])) == -1){
- free(tval);
- depot->fatal = TRUE;
- return FALSE;
- }
- }
- free(tval);
- }
- if(fdel) depot->rnum++;
- break;
- default:
- if((newoff = dprecappend(depot, kbuf, ksiz, vbuf, vsiz, hash, 0, 0)) == -1){
- depot->fatal = TRUE;
- return FALSE;
- }
- depot->rnum++;
- break;
- }
- if(newoff > 0){
- if(entoff > 0){
- if(!dpseekwritenum(depot->fd, entoff, newoff)){
- depot->fatal = TRUE;
- return FALSE;
- }
- } else {
- depot->buckets[bi] = newoff;
- }
- }
- return TRUE;
-}
-
-
-/* Delete a record. */
-int dpout(DEPOT *depot, const char *kbuf, int ksiz){
- int head[DP_RHNUM], hash, bi, off, entoff, ee;
- char ebuf[DP_ENTBUFSIZ];
- assert(depot && kbuf);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_SECONDHASH(hash, kbuf, ksiz);
- switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
- case -1:
- depot->fatal = TRUE;
- return FALSE;
- case 0:
- break;
- default:
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return FALSE;
- }
- if(!dprecdelete(depot, off, head, FALSE)){
- depot->fatal = TRUE;
- return FALSE;
- }
- depot->rnum--;
- return TRUE;
-}
-
-
-/* Retrieve a record. */
-char *dpget(DEPOT *depot, const char *kbuf, int ksiz, int start, int max, int *sp){
- int head[DP_RHNUM], hash, bi, off, entoff, ee, vsiz;
- char ebuf[DP_ENTBUFSIZ], *vbuf;
- assert(depot && kbuf && start >= 0);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return NULL;
- }
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_SECONDHASH(hash, kbuf, ksiz);
- switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
- case -1:
- depot->fatal = TRUE;
- return NULL;
- case 0:
- break;
- default:
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return NULL;
- }
- if(start > head[DP_RHIVSIZ]){
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return NULL;
- }
- if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
- head[DP_RHIVSIZ] -= start;
- if(max < 0){
- vsiz = head[DP_RHIVSIZ];
- } else {
- vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
- }
- if(!(vbuf = malloc(vsiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return NULL;
- }
- memcpy(vbuf, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start), vsiz);
- vbuf[vsiz] = '\0';
- } else {
- if(!(vbuf = dprecval(depot, off, head, start, max))){
- depot->fatal = TRUE;
- return NULL;
- }
- }
- if(sp){
- if(max < 0){
- *sp = head[DP_RHIVSIZ];
- } else {
- *sp = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
- }
- }
- return vbuf;
-}
-
-
-/* Retrieve a record and write the value into a buffer. */
-int dpgetwb(DEPOT *depot, const char *kbuf, int ksiz, int start, int max, char *vbuf){
- int head[DP_RHNUM], hash, bi, off, entoff, ee, vsiz;
- char ebuf[DP_ENTBUFSIZ];
- assert(depot && kbuf && start >= 0 && max >= 0 && vbuf);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_SECONDHASH(hash, kbuf, ksiz);
- switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
- case -1:
- depot->fatal = TRUE;
- return -1;
- case 0:
- break;
- default:
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return -1;
- }
- if(start > head[DP_RHIVSIZ]){
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return -1;
- }
- if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
- head[DP_RHIVSIZ] -= start;
- vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
- memcpy(vbuf, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start), vsiz);
- } else {
- if((vsiz = dprecvalwb(depot, off, head, start, max, vbuf)) == -1){
- depot->fatal = TRUE;
- return -1;
- }
- }
- return vsiz;
-}
-
-
-/* Get the size of the value of a record. */
-int dpvsiz(DEPOT *depot, const char *kbuf, int ksiz){
- int head[DP_RHNUM], hash, bi, off, entoff, ee;
- char ebuf[DP_ENTBUFSIZ];
- assert(depot && kbuf);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_SECONDHASH(hash, kbuf, ksiz);
- switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
- case -1:
- depot->fatal = TRUE;
- return -1;
- case 0:
- break;
- default:
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return -1;
- }
- return head[DP_RHIVSIZ];
-}
-
-
-/* Initialize the iterator of a database handle. */
-int dpiterinit(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- depot->ioff = 0;
- return TRUE;
-}
-
-
-/* Get the next key of the iterator. */
-char *dpiternext(DEPOT *depot, int *sp){
- int off, head[DP_RHNUM], ee;
- char ebuf[DP_ENTBUFSIZ], *kbuf;
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return NULL;
- }
- off = DP_HEADSIZ + depot->bnum * sizeof(int);
- off = off > depot->ioff ? off : depot->ioff;
- while(off < depot->fsiz){
- if(!dprechead(depot, off, head, ebuf, &ee)){
- depot->fatal = TRUE;
- return NULL;
- }
- if(head[DP_RHIFLAGS] & DP_RECFDEL){
- off += dprecsize(head);
- } else {
- if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
- if(!(kbuf = malloc(head[DP_RHIKSIZ] + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return NULL;
- }
- memcpy(kbuf, ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
- kbuf[head[DP_RHIKSIZ]] = '\0';
- } else {
- if(!(kbuf = dpreckey(depot, off, head))){
- depot->fatal = TRUE;
- return NULL;
- }
- }
- depot->ioff = off + dprecsize(head);
- if(sp) *sp = head[DP_RHIKSIZ];
- return kbuf;
- }
- }
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- return NULL;
-}
-
-
-/* Set alignment of a database handle. */
-int dpsetalign(DEPOT *depot, int align){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- depot->align = align;
- return TRUE;
-}
-
-
-/* Set the size of the free block pool of a database handle. */
-int dpsetfbpsiz(DEPOT *depot, int size){
- int *fbpool;
- int i;
- assert(depot && size >= 0);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- size *= 2;
- if(!(fbpool = realloc(depot->fbpool, size * sizeof(int) + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return FALSE;
- }
- for(i = 0; i < size; i += 2){
- fbpool[i] = -1;
- fbpool[i+1] = -1;
- }
- depot->fbpool = fbpool;
- depot->fbpsiz = size;
- return TRUE;
-}
-
-
-
-/* Synchronize contents of updating a database with the file and the device. */
-int dpsync(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- *((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
- *((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
- if(msync(depot->map, depot->msiz, MS_SYNC) == -1){
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(fsync(depot->fd) == -1){
- dpecodeset(DP_ESYNC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Optimize a database. */
-int dpoptimize(DEPOT *depot, int bnum){
- DEPOT *tdepot;
- char *name;
- int i, err, off, head[DP_RHNUM], ee, ksizs[DP_OPTRUNIT], vsizs[DP_OPTRUNIT], unum;
- char ebuf[DP_ENTBUFSIZ], *kbufs[DP_OPTRUNIT], *vbufs[DP_OPTRUNIT];
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- if(!(name = malloc(strlen(depot->name) + strlen(DP_TMPFSUF) + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = FALSE;
- return FALSE;
- }
- sprintf(name, "%s%s", depot->name, DP_TMPFSUF);
- if(bnum < 0){
- bnum = (int)(depot->rnum * (1.0 / DP_OPTBLOAD)) + 1;
- if(bnum < DP_DEFBNUM / 2) bnum = DP_DEFBNUM / 2;
- }
- if(!(tdepot = dpopen(name, DP_OWRITER | DP_OCREAT | DP_OTRUNC, bnum))){
- free(name);
- depot->fatal = TRUE;
- return FALSE;
- }
- free(name);
- if(!dpsetflags(tdepot, dpgetflags(depot))){
- dpclose(tdepot);
- depot->fatal = TRUE;
- return FALSE;
- }
- tdepot->align = depot->align;
- err = FALSE;
- off = DP_HEADSIZ + depot->bnum * sizeof(int);
- unum = 0;
- while(off < depot->fsiz){
- if(!dprechead(depot, off, head, ebuf, &ee)){
- err = TRUE;
- break;
- }
- if(!(head[DP_RHIFLAGS] & DP_RECFDEL)){
- if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
- if(!(kbufs[unum] = malloc(head[DP_RHIKSIZ] + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- memcpy(kbufs[unum], ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
- if(DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
- if(!(vbufs[unum] = malloc(head[DP_RHIVSIZ] + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- memcpy(vbufs[unum], ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ]),
- head[DP_RHIVSIZ]);
- } else {
- vbufs[unum] = dprecval(depot, off, head, 0, -1);
- }
- } else {
- kbufs[unum] = dpreckey(depot, off, head);
- vbufs[unum] = dprecval(depot, off, head, 0, -1);
- }
- ksizs[unum] = head[DP_RHIKSIZ];
- vsizs[unum] = head[DP_RHIVSIZ];
- unum++;
- if(unum >= DP_OPTRUNIT){
- for(i = 0; i < unum; i++){
- if(kbufs[i] && vbufs[i]){
- if(!dpput(tdepot, kbufs[i], ksizs[i], vbufs[i], vsizs[i], DP_DKEEP)) err = TRUE;
- } else {
- err = TRUE;
- }
- free(kbufs[i]);
- free(vbufs[i]);
- if(err) break;
- }
- unum = 0;
- }
- }
- off += dprecsize(head);
- if(err) break;
- }
- for(i = 0; i < unum; i++){
- if(kbufs[i] && vbufs[i]){
- if(!dpput(tdepot, kbufs[i], ksizs[i], vbufs[i], vsizs[i], DP_DKEEP)) err = TRUE;
- } else {
- err = TRUE;
- }
- free(kbufs[i]);
- free(vbufs[i]);
- if(err) break;
- }
- if(!dpsync(tdepot)) err = TRUE;
- if(err){
- unlink(tdepot->name);
- dpclose(tdepot);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(munmap(depot->map, depot->msiz) == -1){
- dpclose(tdepot);
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- depot->map = MAP_FAILED;
- if(ftruncate(depot->fd, 0) == -1){
- dpclose(tdepot);
- unlink(tdepot->name);
- dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(dpfcopy(depot->fd, 0, tdepot->fd, 0) == -1){
- dpclose(tdepot);
- unlink(tdepot->name);
- depot->fatal = TRUE;
- return FALSE;
- }
- depot->fsiz = tdepot->fsiz;
- depot->bnum = tdepot->bnum;
- depot->ioff = 0;
- for(i = 0; i < depot->fbpsiz; i += 2){
- depot->fbpool[i] = -1;
- depot->fbpool[i+1] = -1;
- }
- depot->msiz = tdepot->msiz;
- depot->map = mmap(0, depot->msiz, PROT_READ | PROT_WRITE, MAP_SHARED, depot->fd, 0);
- if(depot->map == MAP_FAILED){
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- depot->buckets = (int *)(depot->map + DP_HEADSIZ);
- if(!(name = dpname(tdepot))){
- dpclose(tdepot);
- unlink(tdepot->name);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(!dpclose(tdepot)){
- free(name);
- unlink(tdepot->name);
- depot->fatal = TRUE;
- return FALSE;
- }
- if(unlink(name) == -1){
- free(name);
- dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- free(name);
- return TRUE;
-}
-
-
-/* Get the name of a database. */
-char *dpname(DEPOT *depot){
- char *name;
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return NULL;
- }
- if(!(name = dpstrdup(depot->name))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return NULL;
- }
- return name;
-}
-
-
-/* Get the size of a database file. */
-int dpfsiz(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- return depot->fsiz;
-}
-
-
-/* Get the number of the elements of the bucket array. */
-int dpbnum(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- return depot->bnum;
-}
-
-
-/* Get the number of the used elements of the bucket array. */
-int dpbusenum(DEPOT *depot){
- int i, hits;
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- hits = 0;
- for(i = 0; i < depot->bnum; i++){
- if(depot->buckets[i]) hits++;
- }
- return hits;
-}
-
-
-/* Get the number of the records stored in a database. */
-int dprnum(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return -1;
- }
- return depot->rnum;
-}
-
-
-/* Check whether a database handle is a writer or not. */
-int dpwritable(DEPOT *depot){
- assert(depot);
- return depot->wmode;
-}
-
-
-/* Check whether a database has a fatal error or not. */
-int dpfatalerror(DEPOT *depot){
- assert(depot);
- return depot->fatal;
-}
-
-
-/* Get the inode number of a database file. */
-int dpinode(DEPOT *depot){
- assert(depot);
- return depot->inode;
-}
-
-
-/* Get the last modified time of a database. */
-time_t dpmtime(DEPOT *depot){
- assert(depot);
- return depot->mtime;
-}
-
-
-/* Get the file descriptor of a database file. */
-int dpfdesc(DEPOT *depot){
- assert(depot);
- return depot->fd;
-}
-
-
-/* Remove a database file. */
-int dpremove(const char *name){
- struct stat sbuf;
- DEPOT *depot;
- assert(name);
- if(lstat(name, &sbuf) == -1){
- dpecodeset(DP_ESTAT, __FILE__, __LINE__);
- return FALSE;
- }
- if((depot = dpopen(name, DP_OWRITER | DP_OTRUNC, -1)) != NULL) dpclose(depot);
- if(unlink(name) == -1){
- dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Repair a broken database file. */
-int dprepair(const char *name){
- DEPOT *tdepot;
- char dbhead[DP_HEADSIZ], *tname, *kbuf, *vbuf;
- int fd, fsiz, flags, bnum, tbnum, err, head[DP_RHNUM], off, rsiz, ksiz, vsiz;
- struct stat sbuf;
- assert(name);
- if(lstat(name, &sbuf) == -1){
- dpecodeset(DP_ESTAT, __FILE__, __LINE__);
- return FALSE;
- }
- fsiz = sbuf.st_size;
- if((fd = open(name, O_RDWR, DP_FILEMODE)) == -1){
- dpecodeset(DP_EOPEN, __FILE__, __LINE__);
- return FALSE;
- }
- if(!dpseekread(fd, 0, dbhead, DP_HEADSIZ)){
- close(fd);
- return FALSE;
- }
- flags = *(int *)(dbhead + DP_FLAGSOFF);
- bnum = *(int *)(dbhead + DP_BNUMOFF);
- tbnum = *(int *)(dbhead + DP_RNUMOFF) * 2;
- if(tbnum < DP_DEFBNUM) tbnum = DP_DEFBNUM;
- if(!(tname = malloc(strlen(name) + strlen(DP_TMPFSUF) + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return FALSE;
- }
- sprintf(tname, "%s%s", name, DP_TMPFSUF);
- if(!(tdepot = dpopen(tname, DP_OWRITER | DP_OCREAT | DP_OTRUNC, tbnum))){
- free(tname);
- close(fd);
- return FALSE;
- }
- err = FALSE;
- off = DP_HEADSIZ + bnum * sizeof(int);
- while(off < fsiz){
- if(!dpseekread(fd, off, head, DP_RHNUM * sizeof(int))) break;
- if(head[DP_RHIFLAGS] & DP_RECFDEL){
- if((rsiz = dprecsize(head)) < 0) break;
- off += rsiz;
- continue;
- }
- ksiz = head[DP_RHIKSIZ];
- vsiz = head[DP_RHIVSIZ];
- if(ksiz >= 0 && vsiz >= 0){
- kbuf = malloc(ksiz + 1);
- vbuf = malloc(vsiz + 1);
- if(kbuf && vbuf){
- if(dpseekread(fd, off + DP_RHNUM * sizeof(int), kbuf, ksiz) &&
- dpseekread(fd, off + DP_RHNUM * sizeof(int) + ksiz, vbuf, vsiz)){
- if(!dpput(tdepot, kbuf, ksiz, vbuf, vsiz, DP_DKEEP)) err = TRUE;
- } else {
- err = TRUE;
- }
- } else {
- if(!err) dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- }
- free(vbuf);
- free(kbuf);
- } else {
- if(!err) dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- err = TRUE;
- }
- if((rsiz = dprecsize(head)) < 0) break;
- off += rsiz;
- }
- if(!dpsetflags(tdepot, flags)) err = TRUE;
- if(!dpsync(tdepot)) err = TRUE;
- if(ftruncate(fd, 0) == -1){
- if(!err) dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
- err = TRUE;
- }
- if(dpfcopy(fd, 0, tdepot->fd, 0) == -1) err = TRUE;
- if(!dpclose(tdepot)) err = TRUE;
- if(close(fd) == -1){
- if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
- err = TRUE;
- }
- if(unlink(tname) == -1){
- if(!err) dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
- err = TRUE;
- }
- free(tname);
- return err ? FALSE : TRUE;
-}
-
-
-/* Dump all records as endian independent data. */
-int dpexportdb(DEPOT *depot, const char *name){
- char *kbuf, *vbuf, *pbuf;
- int fd, err, ksiz, vsiz, psiz;
- assert(depot && name);
- if(!(dpiterinit(depot))) return FALSE;
- if((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, DP_FILEMODE)) == -1){
- dpecodeset(DP_EOPEN, __FILE__, __LINE__);
- return FALSE;
- }
- err = FALSE;
- while(!err && (kbuf = dpiternext(depot, &ksiz)) != NULL){
- if((vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
- if((pbuf = malloc(ksiz + vsiz + DP_NUMBUFSIZ * 2)) != NULL){
- psiz = 0;
- psiz += sprintf(pbuf + psiz, "%X\n%X\n", ksiz, vsiz);
- memcpy(pbuf + psiz, kbuf, ksiz);
- psiz += ksiz;
- pbuf[psiz++] = '\n';
- memcpy(pbuf + psiz, vbuf, vsiz);
- psiz += vsiz;
- pbuf[psiz++] = '\n';
- if(!dpwrite(fd, pbuf, psiz)){
- dpecodeset(DP_EWRITE, __FILE__, __LINE__);
- err = TRUE;
- }
- free(pbuf);
- } else {
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- }
- free(vbuf);
- } else {
- err = TRUE;
- }
- free(kbuf);
- }
- if(close(fd) == -1){
- if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
- return FALSE;
- }
- return !err && !dpfatalerror(depot);
-}
-
-
-/* Load all records from endian independent data. */
-int dpimportdb(DEPOT *depot, const char *name){
- char mbuf[DP_IOBUFSIZ], *rbuf;
- int i, j, fd, err, fsiz, off, msiz, ksiz, vsiz, hlen;
- struct stat sbuf;
- assert(depot && name);
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- if(dprnum(depot) > 0){
- dpecodeset(DP_EMISC, __FILE__, __LINE__);
- return FALSE;
- }
- if((fd = open(name, O_RDONLY, DP_FILEMODE)) == -1){
- dpecodeset(DP_EOPEN, __FILE__, __LINE__);
- return FALSE;
- }
- if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
- dpecodeset(DP_ESTAT, __FILE__, __LINE__);
- close(fd);
- return FALSE;
- }
- err = FALSE;
- fsiz = sbuf.st_size;
- off = 0;
- while(!err && off < fsiz){
- msiz = fsiz - off;
- if(msiz > DP_IOBUFSIZ) msiz = DP_IOBUFSIZ;
- if(!dpseekread(fd, off, mbuf, msiz)){
- err = TRUE;
- break;
- }
- hlen = 0;
- ksiz = -1;
- vsiz = -1;
- for(i = 0; i < msiz; i++){
- if(mbuf[i] == '\n'){
- mbuf[i] = '\0';
- ksiz = strtol(mbuf, NULL, 16);
- for(j = i + 1; j < msiz; j++){
- if(mbuf[j] == '\n'){
- mbuf[j] = '\0';
- vsiz = strtol(mbuf + i + 1, NULL, 16);
- hlen = j + 1;
- break;
- }
- }
- break;
- }
- }
- if(ksiz < 0 || vsiz < 0 || hlen < 4){
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- if(hlen + ksiz + vsiz + 2 < DP_IOBUFSIZ){
- if(!dpput(depot, mbuf + hlen, ksiz, mbuf + hlen + ksiz + 1, vsiz, DP_DKEEP)) err = TRUE;
- } else {
- if((rbuf = malloc(ksiz + vsiz + 2)) != NULL){
- if(dpseekread(fd, off + hlen, rbuf, ksiz + vsiz + 2)){
- if(!dpput(depot, rbuf, ksiz, rbuf + ksiz + 1, vsiz, DP_DKEEP)) err = TRUE;
- } else {
- err = TRUE;
- }
- free(rbuf);
- } else {
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- }
- }
- off += hlen + ksiz + vsiz + 2;
- }
- if(close(fd) == -1){
- if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
- return FALSE;
- }
- return !err && !dpfatalerror(depot);
-}
-
-
-/* Retrieve a record directly from a database file. */
-char *dpsnaffle(const char *name, const char* kbuf, int ksiz, int *sp){
- char hbuf[DP_HEADSIZ], *map, *vbuf, *tkbuf;
- int fd, fsiz, bnum, msiz, *buckets, hash, thash, head[DP_RHNUM], err, off, vsiz, tksiz, kcmp;
- struct stat sbuf;
- assert(name && kbuf);
- if(ksiz < 0) ksiz = strlen(kbuf);
- if((fd = open(name, O_RDONLY, DP_FILEMODE)) == -1){
- dpecodeset(DP_EOPEN, __FILE__, __LINE__);
- return NULL;
- }
- if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
- close(fd);
- dpecodeset(DP_ESTAT, __FILE__, __LINE__);
- return NULL;
- }
- fsiz = sbuf.st_size;
- if(!dpseekread(fd, 0, hbuf, DP_HEADSIZ)){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- if(dpbigendian() ? memcmp(hbuf, DP_MAGICNUMB, strlen(DP_MAGICNUMB)) != 0 :
- memcmp(hbuf, DP_MAGICNUML, strlen(DP_MAGICNUML)) != 0){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- bnum = *((int *)(hbuf + DP_BNUMOFF));
- if(bnum < 1 || fsiz < DP_HEADSIZ + bnum * sizeof(int)){
- close(fd);
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return NULL;
- }
- msiz = DP_HEADSIZ + bnum * sizeof(int);
- map = mmap(0, msiz, PROT_READ, MAP_SHARED, fd, 0);
- if(map == MAP_FAILED){
- close(fd);
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- return NULL;
- }
- buckets = (int *)(map + DP_HEADSIZ);
- err = FALSE;
- vbuf = NULL;
- vsiz = 0;
- DP_SECONDHASH(hash, kbuf, ksiz);
- DP_FIRSTHASH(thash, kbuf, ksiz);
- off = buckets[thash%bnum];
- while(off != 0){
- if(!dpseekread(fd, off, head, DP_RHNUM * sizeof(int))){
- err = TRUE;
- break;
- }
- if(head[DP_RHIKSIZ] < 0 || head[DP_RHIVSIZ] < 0 || head[DP_RHIPSIZ] < 0 ||
- head[DP_RHILEFT] < 0 || head[DP_RHIRIGHT] < 0){
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- thash = head[DP_RHIHASH];
- if(hash > thash){
- off = head[DP_RHILEFT];
- } else if(hash < thash){
- off = head[DP_RHIRIGHT];
- } else {
- tksiz = head[DP_RHIKSIZ];
- if(!(tkbuf = malloc(tksiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- if(!dpseekread(fd, off + DP_RHNUM * sizeof(int), tkbuf, tksiz)){
- free(tkbuf);
- err = TRUE;
- break;
- }
- tkbuf[tksiz] = '\0';
- kcmp = dpkeycmp(kbuf, ksiz, tkbuf, tksiz);
- free(tkbuf);
- if(kcmp > 0){
- off = head[DP_RHILEFT];
- } else if(kcmp < 0){
- off = head[DP_RHIRIGHT];
- } else if(head[DP_RHIFLAGS] & DP_RECFDEL){
- break;
- } else {
- vsiz = head[DP_RHIVSIZ];
- if(!(vbuf = malloc(vsiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- err = TRUE;
- break;
- }
- if(!dpseekread(fd, off + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ], vbuf, vsiz)){
- free(vbuf);
- vbuf = NULL;
- err = TRUE;
- break;
- }
- vbuf[vsiz] = '\0';
- break;
- }
- }
- }
- if(vbuf){
- if(sp) *sp = vsiz;
- } else if(!err){
- dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
- }
- munmap(map, msiz);
- close(fd);
- return vbuf;
-}
-
-
-/* Hash function used inside Depot. */
-int dpinnerhash(const char *kbuf, int ksiz){
- int res;
- assert(kbuf);
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_FIRSTHASH(res, kbuf, ksiz);
- return res;
-}
-
-
-/* Hash function which is independent from the hash functions used inside Depot. */
-int dpouterhash(const char *kbuf, int ksiz){
- int res;
- assert(kbuf);
- if(ksiz < 0) ksiz = strlen(kbuf);
- DP_THIRDHASH(res, kbuf, ksiz);
- return res;
-}
-
-
-/* Get a natural prime number not less than a number. */
-int dpprimenum(int num){
- assert(num > 0);
- return dpgetprime(num);
-}
-
-
-
-/*************************************************************************************************
- * features for experts
- *************************************************************************************************/
-
-
-/* Name of the operating system. */
-const char *dpsysname = _QDBM_SYSNAME;
-
-
-/* File descriptor for debugging output. */
-int dpdbgfd = -1;
-
-
-/* Whether this build is reentrant. */
-const int dpisreentrant = _qdbm_ptsafe;
-
-
-/* Set the last happened error code. */
-void dpecodeset(int ecode, const char *file, int line){
- char iobuf[DP_IOBUFSIZ];
- assert(ecode >= DP_ENOERR && file && line >= 0);
- dpecode = ecode;
- if(dpdbgfd >= 0){
- fflush(stdout);
- fflush(stderr);
- sprintf(iobuf, "* dpecodeset: %s:%d: [%d] %s\n", file, line, ecode, dperrmsg(ecode));
- dpwrite(dpdbgfd, iobuf, strlen(iobuf));
- }
-}
-
-
-/* Get the pointer of the variable of the last happened error code. */
-int *dpecodeptr(void){
- static int defdpecode = DP_ENOERR;
- void *ptr;
- if(_qdbm_ptsafe){
- if(!(ptr = _qdbm_settsd(&defdpecode, sizeof(int), &defdpecode))){
- defdpecode = DP_EMISC;
- return &defdpecode;
- }
- return (int *)ptr;
- }
- return &defdpecode;
-}
-
-
-/* Synchronize updating contents on memory. */
-int dpmemsync(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- *((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
- *((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
- if(msync(depot->map, depot->msiz, MS_SYNC) == -1){
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Synchronize updating contents on memory, not physically. */
-int dpmemflush(DEPOT *depot){
- assert(depot);
- if(depot->fatal){
- dpecodeset(DP_EFATAL, __FILE__, __LINE__);
- return FALSE;
- }
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- *((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
- *((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
- if(mflush(depot->map, depot->msiz, MS_SYNC) == -1){
- dpecodeset(DP_EMAP, __FILE__, __LINE__);
- depot->fatal = TRUE;
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Get flags of a database. */
-int dpgetflags(DEPOT *depot){
- int flags;
- assert(depot);
- memcpy(&flags, depot->map + DP_FLAGSOFF, sizeof(int));
- return flags;
-}
-
-
-/* Set flags of a database. */
-int dpsetflags(DEPOT *depot, int flags){
- assert(depot);
- if(!depot->wmode){
- dpecodeset(DP_EMODE, __FILE__, __LINE__);
- return FALSE;
- }
- memcpy(depot->map + DP_FLAGSOFF, &flags, sizeof(int));
- return TRUE;
-}
-
-
-
-/*************************************************************************************************
- * private objects
- *************************************************************************************************/
-
-
-/* Check whether the byte order of the platform is big endian or not.
- The return value is true if bigendian, else, it is false. */
-static int dpbigendian(void){
- char buf[sizeof(int)];
- *(int *)buf = 1;
- return !buf[0];
-}
-
-
-/* Get a copied string.
- `str' specifies an original string.
- The return value is a copied string whose region is allocated by `malloc'. */
-static char *dpstrdup(const char *str){
- int len;
- char *buf;
- assert(str);
- len = strlen(str);
- if(!(buf = malloc(len + 1))) return NULL;
- memcpy(buf, str, len + 1);
- return buf;
-}
-
-
-/* Lock a file descriptor.
- `fd' specifies a file descriptor.
- `ex' specifies whether an exclusive lock or a shared lock is performed.
- `nb' specifies whether to request with non-blocking.
- The return value is true if successful, else, it is false. */
-static int dplock(int fd, int ex, int nb){
- struct flock lock;
- assert(fd >= 0);
- memset(&lock, 0, sizeof(struct flock));
- lock.l_type = ex ? F_WRLCK : F_RDLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- lock.l_pid = 0;
- while(fcntl(fd, nb ? F_SETLK : F_SETLKW, &lock) == -1){
- if(errno != EINTR){
- dpecodeset(DP_ELOCK, __FILE__, __LINE__);
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-/* Write into a file.
- `fd' specifies a file descriptor.
- `buf' specifies a buffer to write.
- `size' specifies the size of the buffer.
- The return value is the size of the written buffer, or, -1 on failure. */
-static int dpwrite(int fd, const void *buf, int size){
- const char *lbuf;
- int rv, wb;
- assert(fd >= 0 && buf && size >= 0);
- lbuf = buf;
- rv = 0;
- do {
- wb = write(fd, lbuf, size);
- switch(wb){
- case -1: if(errno != EINTR) return -1;
- case 0: break;
- default:
- lbuf += wb;
- size -= wb;
- rv += wb;
- break;
- }
- } while(size > 0);
- return rv;
-}
-
-
-/* Write into a file at an offset.
- `fd' specifies a file descriptor.
- `off' specifies an offset of the file.
- `buf' specifies a buffer to write.
- `size' specifies the size of the buffer.
- The return value is true if successful, else, it is false. */
-static int dpseekwrite(int fd, int off, const void *buf, int size){
- assert(fd >= 0 && buf && size >= 0);
- if(size < 1) return TRUE;
- if(off < 0){
- if(lseek(fd, 0, SEEK_END) == -1){
- dpecodeset(DP_ESEEK, __FILE__, __LINE__);
- return FALSE;
- }
- } else {
- if(lseek(fd, off, SEEK_SET) != off){
- dpecodeset(DP_ESEEK, __FILE__, __LINE__);
- return FALSE;
- }
- }
- if(dpwrite(fd, buf, size) != size){
- dpecodeset(DP_EWRITE, __FILE__, __LINE__);
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Write an integer into a file at an offset.
- `fd' specifies a file descriptor.
- `off' specifies an offset of the file.
- `num' specifies an integer.
- The return value is true if successful, else, it is false. */
-static int dpseekwritenum(int fd, int off, int num){
- assert(fd >= 0);
- return dpseekwrite(fd, off, &num, sizeof(int));
-}
-
-
-/* Read from a file and store the data into a buffer.
- `fd' specifies a file descriptor.
- `buffer' specifies a buffer to store into.
- `size' specifies the size to read with.
- The return value is the size read with, or, -1 on failure. */
-static int dpread(int fd, void *buf, int size){
- char *lbuf;
- int i, bs;
- assert(fd >= 0 && buf && size >= 0);
- lbuf = buf;
- for(i = 0; i < size && (bs = read(fd, lbuf + i, size - i)) != 0; i += bs){
- if(bs == -1 && errno != EINTR) return -1;
- }
- return i;
-}
-
-
-/* Read from a file at an offset and store the data into a buffer.
- `fd' specifies a file descriptor.
- `off' specifies an offset of the file.
- `buffer' specifies a buffer to store into.
- `size' specifies the size to read with.
- The return value is true if successful, else, it is false. */
-static int dpseekread(int fd, int off, void *buf, int size){
- char *lbuf;
- assert(fd >= 0 && off >= 0 && buf && size >= 0);
- lbuf = (char *)buf;
- if(lseek(fd, off, SEEK_SET) != off){
- dpecodeset(DP_ESEEK, __FILE__, __LINE__);
- return FALSE;
- }
- if(dpread(fd, lbuf, size) != size){
- dpecodeset(DP_EREAD, __FILE__, __LINE__);
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Copy data between files.
- `destfd' specifies a file descriptor of a destination file.
- `destoff' specifies an offset of the destination file.
- `srcfd' specifies a file descriptor of a source file.
- `srcoff' specifies an offset of the source file.
- The return value is the size copied with, or, -1 on failure. */
-static int dpfcopy(int destfd, int destoff, int srcfd, int srcoff){
- char iobuf[DP_IOBUFSIZ];
- int sum, iosiz;
- if(lseek(srcfd, srcoff, SEEK_SET) == -1 || lseek(destfd, destoff, SEEK_SET) == -1){
- dpecodeset(DP_ESEEK, __FILE__, __LINE__);
- return -1;
- }
- sum = 0;
- while((iosiz = dpread(srcfd, iobuf, DP_IOBUFSIZ)) > 0){
- if(dpwrite(destfd, iobuf, iosiz) == -1){
- dpecodeset(DP_EWRITE, __FILE__, __LINE__);
- return -1;
- }
- sum += iosiz;
- }
- if(iosiz < 0){
- dpecodeset(DP_EREAD, __FILE__, __LINE__);
- return -1;
- }
- return sum;
-}
-
-
-/* Get a natural prime number not less than a number.
- `num' specified a natural number.
- The return value is a prime number not less than the specified number. */
-static int dpgetprime(int num){
- int primes[] = {
- 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 43, 47, 53, 59, 61, 71, 79, 83,
- 89, 103, 109, 113, 127, 139, 157, 173, 191, 199, 223, 239, 251, 283, 317, 349,
- 383, 409, 443, 479, 509, 571, 631, 701, 761, 829, 887, 953, 1021, 1151, 1279,
- 1399, 1531, 1663, 1789, 1913, 2039, 2297, 2557, 2803, 3067, 3323, 3583, 3833,
- 4093, 4603, 5119, 5623, 6143, 6653, 7159, 7673, 8191, 9209, 10223, 11261,
- 12281, 13309, 14327, 15359, 16381, 18427, 20479, 22511, 24571, 26597, 28669,
- 30713, 32749, 36857, 40949, 45053, 49139, 53239, 57331, 61417, 65521, 73727,
- 81919, 90107, 98299, 106487, 114679, 122869, 131071, 147451, 163819, 180221,
- 196597, 212987, 229373, 245759, 262139, 294911, 327673, 360439, 393209, 425977,
- 458747, 491503, 524287, 589811, 655357, 720887, 786431, 851957, 917503, 982981,
- 1048573, 1179641, 1310719, 1441771, 1572853, 1703903, 1835003, 1966079,
- 2097143, 2359267, 2621431, 2883577, 3145721, 3407857, 3670013, 3932153,
- 4194301, 4718579, 5242877, 5767129, 6291449, 6815741, 7340009, 7864301,
- 8388593, 9437179, 10485751, 11534329, 12582893, 13631477, 14680063, 15728611,
- 16777213, 18874367, 20971507, 23068667, 25165813, 27262931, 29360087, 31457269,
- 33554393, 37748717, 41943023, 46137319, 50331599, 54525917, 58720253, 62914549,
- 67108859, 75497467, 83886053, 92274671, 100663291, 109051903, 117440509,
- 125829103, 134217689, 150994939, 167772107, 184549373, 201326557, 218103799,
- 234881011, 251658227, 268435399, 301989881, 335544301, 369098707, 402653171,
- 436207613, 469762043, 503316469, 536870909, 603979769, 671088637, 738197503,
- 805306357, 872415211, 939524087, 1006632947, 1073741789, 1207959503,
- 1342177237, 1476394991, 1610612711, 1744830457, 1879048183, 2013265907, -1
- };
- int i;
- assert(num > 0);
- for(i = 0; primes[i] > 0; i++){
- if(num <= primes[i]) return primes[i];
- }
- return primes[i-1];
-}
-
-
-/* Get the padding size of a record.
- `vsiz' specifies the size of the value of a record.
- The return value is the padding size of a record. */
-static int dppadsize(DEPOT *depot, int ksiz, int vsiz){
- int pad;
- assert(depot && vsiz >= 0);
- if(depot->align > 0){
- return depot->align - (depot->fsiz + DP_RHNUM * sizeof(int) + ksiz + vsiz) % depot->align;
- } else if(depot->align < 0){
- pad = (int)(vsiz * (2.0 / (1 << -(depot->align))));
- if(vsiz + pad >= DP_FSBLKSIZ){
- if(vsiz <= DP_FSBLKSIZ) pad = 0;
- if(depot->fsiz % DP_FSBLKSIZ == 0){
- return (pad / DP_FSBLKSIZ) * DP_FSBLKSIZ + DP_FSBLKSIZ -
- (depot->fsiz + DP_RHNUM * sizeof(int) + ksiz + vsiz) % DP_FSBLKSIZ;
- } else {
- return (pad / (DP_FSBLKSIZ / 2)) * (DP_FSBLKSIZ / 2) + (DP_FSBLKSIZ / 2) -
- (depot->fsiz + DP_RHNUM * sizeof(int) + ksiz + vsiz) % (DP_FSBLKSIZ / 2);
- }
- } else {
- return pad >= DP_RHNUM * sizeof(int) ? pad : DP_RHNUM * sizeof(int);
- }
- }
- return 0;
-}
-
-
-/* Get the size of a record in a database file.
- `head' specifies the header of a record.
- The return value is the size of a record in a database file. */
-static int dprecsize(int *head){
- assert(head);
- return DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] + head[DP_RHIPSIZ];
-}
-
-
-/* Read the header of a record.
- `depot' specifies a database handle.
- `off' specifies an offset of the database file.
- `head' specifies a buffer for the header.
- `ebuf' specifies the pointer to the entity buffer.
- `eep' specifies the pointer to a variable to which whether ebuf was used is assigned.
- The return value is true if successful, else, it is false. */
-static int dprechead(DEPOT *depot, int off, int *head, char *ebuf, int *eep){
- assert(depot && off >= 0 && head);
- if(off > depot->fsiz){
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return FALSE;
- }
- if(ebuf){
- *eep = FALSE;
- if(off < depot->fsiz - DP_ENTBUFSIZ){
- *eep = TRUE;
- if(!dpseekread(depot->fd, off, ebuf, DP_ENTBUFSIZ)) return FALSE;
- memcpy(head, ebuf, DP_RHNUM * sizeof(int));
- if(head[DP_RHIKSIZ] < 0 || head[DP_RHIVSIZ] < 0 || head[DP_RHIPSIZ] < 0 ||
- head[DP_RHILEFT] < 0 || head[DP_RHIRIGHT] < 0){
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return FALSE;
- }
- return TRUE;
- }
- }
- if(!dpseekread(depot->fd, off, head, DP_RHNUM * sizeof(int))) return FALSE;
- if(head[DP_RHIKSIZ] < 0 || head[DP_RHIVSIZ] < 0 || head[DP_RHIPSIZ] < 0 ||
- head[DP_RHILEFT] < 0 || head[DP_RHIRIGHT] < 0){
- dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
- return FALSE;
- }
- return TRUE;
-}
-
-
-/* Read the entitiy of the key of a record.
- `depot' specifies a database handle.
- `off' specifies an offset of the database file.
- `head' specifies the header of a record.
- The return value is a key data whose region is allocated by `malloc', or NULL on failure. */
-static char *dpreckey(DEPOT *depot, int off, int *head){
- char *kbuf;
- int ksiz;
- assert(depot && off >= 0);
- ksiz = head[DP_RHIKSIZ];
- if(!(kbuf = malloc(ksiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return NULL;
- }
- if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int), kbuf, ksiz)){
- free(kbuf);
- return NULL;
- }
- kbuf[ksiz] = '\0';
- return kbuf;
-}
-
-
-/* Read the entitiy of the value of a record.
- `depot' specifies a database handle.
- `off' specifies an offset of the database file.
- `head' specifies the header of a record.
- `start' specifies the offset address of the beginning of the region of the value to be read.
- `max' specifies the max size to be read. If it is negative, the size to read is unlimited.
- The return value is a value data whose region is allocated by `malloc', or NULL on failure. */
-static char *dprecval(DEPOT *depot, int off, int *head, int start, int max){
- char *vbuf;
- int vsiz;
- assert(depot && off >= 0 && start >= 0);
- head[DP_RHIVSIZ] -= start;
- if(max < 0){
- vsiz = head[DP_RHIVSIZ];
- } else {
- vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
- }
- if(!(vbuf = malloc(vsiz + 1))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return NULL;
- }
- if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start, vbuf, vsiz)){
- free(vbuf);
- return NULL;
- }
- vbuf[vsiz] = '\0';
- return vbuf;
-}
-
-
-/* Read the entitiy of the value of a record and write it into a given buffer.
- `depot' specifies a database handle.
- `off' specifies an offset of the database file.
- `head' specifies the header of a record.
- `start' specifies the offset address of the beginning of the region of the value to be read.
- `max' specifies the max size to be read. It shuld be less than the size of the writing buffer.
- If successful, the return value is the size of the written data, else, it is -1. */
-static int dprecvalwb(DEPOT *depot, int off, int *head, int start, int max, char *vbuf){
- int vsiz;
- assert(depot && off >= 0 && start >= 0 && max >= 0 && vbuf);
- head[DP_RHIVSIZ] -= start;
- vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
- if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start, vbuf, vsiz))
- return -1;
- return vsiz;
-}
-
-
-/* Compare two keys.
- `abuf' specifies the pointer to the region of the former.
- `asiz' specifies the size of the region.
- `bbuf' specifies the pointer to the region of the latter.
- `bsiz' specifies the size of the region.
- The return value is 0 if two equals, positive if the formar is big, else, negative. */
-static int dpkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz){
- assert(abuf && asiz >= 0 && bbuf && bsiz >= 0);
- if(asiz > bsiz) return 1;
- if(asiz < bsiz) return -1;
- return memcmp(abuf, bbuf, asiz);
-}
-
-
-/* Search for a record.
- `depot' specifies a database handle.
- `kbuf' specifies the pointer to the region of a key.
- `ksiz' specifies the size of the region.
- `hash' specifies the second hash value of the key.
- `bip' specifies the pointer to the region to assign the index of the corresponding record.
- `offp' specifies the pointer to the region to assign the last visited node in the hash chain,
- or, -1 if the hash chain is empty.
- `entp' specifies the offset of the last used joint, or, -1 if the hash chain is empty.
- `head' specifies the pointer to the region to store the header of the last visited record in.
- `ebuf' specifies the pointer to the entity buffer.
- `eep' specifies the pointer to a variable to which whether ebuf was used is assigned.
- `delhit' specifies whether a deleted record corresponds or not.
- The return value is 0 if successful, 1 if there is no corresponding record, -1 on error. */
-static int dprecsearch(DEPOT *depot, const char *kbuf, int ksiz, int hash, int *bip, int *offp,
- int *entp, int *head, char *ebuf, int *eep, int delhit){
- int off, entoff, thash, kcmp;
- char stkey[DP_STKBUFSIZ], *tkey;
- assert(depot && kbuf && ksiz >= 0 && hash >= 0 && bip && offp && entp && head && ebuf && eep);
- DP_FIRSTHASH(thash, kbuf, ksiz);
- *bip = thash % depot->bnum;
- off = depot->buckets[*bip];
- *offp = -1;
- *entp = -1;
- entoff = -1;
- *eep = FALSE;
- while(off != 0){
- if(!dprechead(depot, off, head, ebuf, eep)) return -1;
- thash = head[DP_RHIHASH];
- if(hash > thash){
- entoff = off + DP_RHILEFT * sizeof(int);
- off = head[DP_RHILEFT];
- } else if(hash < thash){
- entoff = off + DP_RHIRIGHT * sizeof(int);
- off = head[DP_RHIRIGHT];
- } else {
- if(*eep && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
- kcmp = dpkeycmp(kbuf, ksiz, ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
- } else if(head[DP_RHIKSIZ] > DP_STKBUFSIZ){
- if(!(tkey = dpreckey(depot, off, head))) return -1;
- kcmp = dpkeycmp(kbuf, ksiz, tkey, head[DP_RHIKSIZ]);
- free(tkey);
- } else {
- if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int), stkey, head[DP_RHIKSIZ]))
- return -1;
- kcmp = dpkeycmp(kbuf, ksiz, stkey, head[DP_RHIKSIZ]);
- }
- if(kcmp > 0){
- entoff = off + DP_RHILEFT * sizeof(int);
- off = head[DP_RHILEFT];
- } else if(kcmp < 0){
- entoff = off + DP_RHIRIGHT * sizeof(int);
- off = head[DP_RHIRIGHT];
- } else {
- if(!delhit && (head[DP_RHIFLAGS] & DP_RECFDEL)){
- entoff = off + DP_RHILEFT * sizeof(int);
- off = head[DP_RHILEFT];
- } else {
- *offp = off;
- *entp = entoff;
- return 0;
- }
- }
- }
- }
- *offp = off;
- *entp = entoff;
- return 1;
-}
-
-
-/* Overwrite a record.
- `depot' specifies a database handle.
- `off' specifies the offset of the database file.
- `rsiz' specifies the size of the existing record.
- `kbuf' specifies the pointer to the region of a key.
- `ksiz' specifies the size of the region.
- `vbuf' specifies the pointer to the region of a value.
- `vsiz' specifies the size of the region.
- `hash' specifies the second hash value of the key.
- `left' specifies the offset of the left child.
- `right' specifies the offset of the right child.
- The return value is true if successful, or, false on failure. */
-static int dprecrewrite(DEPOT *depot, int off, int rsiz, const char *kbuf, int ksiz,
- const char *vbuf, int vsiz, int hash, int left, int right){
- char ebuf[DP_WRTBUFSIZ];
- int i, head[DP_RHNUM], asiz, hoff, koff, voff, mi, min, size;
- assert(depot && off >= 1 && rsiz > 0 && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
- head[DP_RHIFLAGS] = 0;
- head[DP_RHIHASH] = hash;
- head[DP_RHIKSIZ] = ksiz;
- head[DP_RHIVSIZ] = vsiz;
- head[DP_RHIPSIZ] = rsiz - sizeof(head) - ksiz - vsiz;
- head[DP_RHILEFT] = left;
- head[DP_RHIRIGHT] = right;
- asiz = sizeof(head) + ksiz + vsiz;
- if(depot->fbpsiz > DP_FBPOOLSIZ * 4 && head[DP_RHIPSIZ] > asiz){
- rsiz = (head[DP_RHIPSIZ] - asiz) / 2 + asiz;
- head[DP_RHIPSIZ] -= rsiz;
- } else {
- rsiz = 0;
- }
- if(asiz <= DP_WRTBUFSIZ){
- memcpy(ebuf, head, sizeof(head));
- memcpy(ebuf + sizeof(head), kbuf, ksiz);
- memcpy(ebuf + sizeof(head) + ksiz, vbuf, vsiz);
- if(!dpseekwrite(depot->fd, off, ebuf, asiz)) return FALSE;
- } else {
- hoff = off;
- koff = hoff + sizeof(head);
- voff = koff + ksiz;
- if(!dpseekwrite(depot->fd, hoff, head, sizeof(head)) ||
- !dpseekwrite(depot->fd, koff, kbuf, ksiz) || !dpseekwrite(depot->fd, voff, vbuf, vsiz))
- return FALSE;
- }
- if(rsiz > 0){
- off += sizeof(head) + ksiz + vsiz + head[DP_RHIPSIZ];
- head[DP_RHIFLAGS] = DP_RECFDEL | DP_RECFREUSE;
- head[DP_RHIHASH] = hash;
- head[DP_RHIKSIZ] = ksiz;
- head[DP_RHIVSIZ] = vsiz;
- head[DP_RHIPSIZ] = rsiz - sizeof(head) - ksiz - vsiz;
- head[DP_RHILEFT] = 0;
- head[DP_RHIRIGHT] = 0;
- if(!dpseekwrite(depot->fd, off, head, sizeof(head))) return FALSE;
- size = dprecsize(head);
- mi = -1;
- min = -1;
- for(i = 0; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i] == -1){
- depot->fbpool[i] = off;
- depot->fbpool[i+1] = size;
- dpfbpoolcoal(depot);
- mi = -1;
- break;
- }
- if(mi == -1 || depot->fbpool[i+1] < min){
- mi = i;
- min = depot->fbpool[i+1];
- }
- }
- if(mi >= 0 && size > min){
- depot->fbpool[mi] = off;
- depot->fbpool[mi+1] = size;
- dpfbpoolcoal(depot);
- }
- }
- return TRUE;
-}
-
-
-/* Write a record at the end of a database file.
- `depot' specifies a database handle.
- `kbuf' specifies the pointer to the region of a key.
- `ksiz' specifies the size of the region.
- `vbuf' specifies the pointer to the region of a value.
- `vsiz' specifies the size of the region.
- `hash' specifies the second hash value of the key.
- `left' specifies the offset of the left child.
- `right' specifies the offset of the right child.
- The return value is the offset of the record, or, -1 on failure. */
-static int dprecappend(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
- int hash, int left, int right){
- char ebuf[DP_WRTBUFSIZ], *hbuf;
- int head[DP_RHNUM], asiz, psiz, off;
- assert(depot && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
- psiz = dppadsize(depot, ksiz, vsiz);
- head[DP_RHIFLAGS] = 0;
- head[DP_RHIHASH] = hash;
- head[DP_RHIKSIZ] = ksiz;
- head[DP_RHIVSIZ] = vsiz;
- head[DP_RHIPSIZ] = psiz;
- head[DP_RHILEFT] = left;
- head[DP_RHIRIGHT] = right;
- asiz = sizeof(head) + ksiz + vsiz + psiz;
- off = depot->fsiz;
- if(asiz <= DP_WRTBUFSIZ){
- memcpy(ebuf, head, sizeof(head));
- memcpy(ebuf + sizeof(head), kbuf, ksiz);
- memcpy(ebuf + sizeof(head) + ksiz, vbuf, vsiz);
- memset(ebuf + sizeof(head) + ksiz + vsiz, 0, psiz);
- if(!dpseekwrite(depot->fd, off, ebuf, asiz)) return -1;
- } else {
- if(!(hbuf = malloc(asiz))){
- dpecodeset(DP_EALLOC, __FILE__, __LINE__);
- return -1;
- }
- memcpy(hbuf, head, sizeof(head));
- memcpy(hbuf + sizeof(head), kbuf, ksiz);
- memcpy(hbuf + sizeof(head) + ksiz, vbuf, vsiz);
- memset(hbuf + sizeof(head) + ksiz + vsiz, 0, psiz);
- if(!dpseekwrite(depot->fd, off, hbuf, asiz)){
- free(hbuf);
- return -1;
- }
- free(hbuf);
- }
- depot->fsiz += asiz;
- return off;
-}
-
-
-/* Overwrite the value of a record.
- `depot' specifies a database handle.
- `off' specifies the offset of the database file.
- `head' specifies the header of the record.
- `vbuf' specifies the pointer to the region of a value.
- `vsiz' specifies the size of the region.
- `cat' specifies whether it is concatenate mode or not.
- The return value is true if successful, or, false on failure. */
-static int dprecover(DEPOT *depot, int off, int *head, const char *vbuf, int vsiz, int cat){
- int i, hsiz, hoff, voff;
- assert(depot && off >= 0 && head && vbuf && vsiz >= 0);
- for(i = 0; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i] == off){
- depot->fbpool[i] = -1;
- depot->fbpool[i+1] = -1;
- break;
- }
- }
- if(cat){
- head[DP_RHIFLAGS] = 0;
- head[DP_RHIPSIZ] -= vsiz;
- head[DP_RHIVSIZ] += vsiz;
- hsiz = DP_RHNUM * sizeof(int);
- hoff = off;
- voff = hoff + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] - vsiz;
- } else {
- head[DP_RHIFLAGS] = 0;
- head[DP_RHIPSIZ] += head[DP_RHIVSIZ] - vsiz;
- head[DP_RHIVSIZ] = vsiz;
- hsiz = DP_RHNUM * sizeof(int);
- hoff = off;
- voff = hoff + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ];
- }
- if(!dpseekwrite(depot->fd, hoff, head, hsiz) ||
- !dpseekwrite(depot->fd, voff, vbuf, vsiz)) return FALSE;
- return TRUE;
-}
-
-
-/* Delete a record.
- `depot' specifies a database handle.
- `off' specifies the offset of the database file.
- `head' specifies the header of the record.
- `reusable' specifies whether the region is reusable or not.
- The return value is true if successful, or, false on failure. */
-static int dprecdelete(DEPOT *depot, int off, int *head, int reusable){
- int i, mi, min, size;
- assert(depot && off >= 0 && head);
- if(reusable){
- size = dprecsize(head);
- mi = -1;
- min = -1;
- for(i = 0; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i] == -1){
- depot->fbpool[i] = off;
- depot->fbpool[i+1] = size;
- dpfbpoolcoal(depot);
- mi = -1;
- break;
- }
- if(mi == -1 || depot->fbpool[i+1] < min){
- mi = i;
- min = depot->fbpool[i+1];
- }
- }
- if(mi >= 0 && size > min){
- depot->fbpool[mi] = off;
- depot->fbpool[mi+1] = size;
- dpfbpoolcoal(depot);
- }
- }
- return dpseekwritenum(depot->fd, off + DP_RHIFLAGS * sizeof(int),
- DP_RECFDEL | (reusable ? DP_RECFREUSE : 0));
-}
-
-
-/* Make contiguous records of the free block pool coalesce.
- `depot' specifies a database handle. */
-static void dpfbpoolcoal(DEPOT *depot){
- int i;
- assert(depot);
- if(depot->fbpinc++ <= depot->fbpsiz / 4) return;
- depot->fbpinc = 0;
- qsort(depot->fbpool, depot->fbpsiz / 2, sizeof(int) * 2, dpfbpoolcmp);
- for(i = 2; i < depot->fbpsiz; i += 2){
- if(depot->fbpool[i-2] > 0 &&
- depot->fbpool[i-2] + depot->fbpool[i-1] - depot->fbpool[i] == 0){
- depot->fbpool[i] = depot->fbpool[i-2];
- depot->fbpool[i+1] += depot->fbpool[i-1];
- depot->fbpool[i-2] = -1;
- depot->fbpool[i-1] = -1;
- }
- }
-}
-
-
-/* Compare two records of the free block pool.
- `a' specifies the pointer to one record.
- `b' specifies the pointer to the other record.
- The return value is 0 if two equals, positive if the formar is big, else, negative. */
-static int dpfbpoolcmp(const void *a, const void *b){
- assert(a && b);
- return *(int *)a - *(int *)b;
-}
-
-
-
-/* END OF FILE */