diff options
Diffstat (limited to 'qdbm/relic.c')
-rw-r--r-- | qdbm/relic.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/qdbm/relic.c b/qdbm/relic.c new file mode 100644 index 00000000..31bbbde2 --- /dev/null +++ b/qdbm/relic.c @@ -0,0 +1,266 @@ +/************************************************************************************************* + * Implementation of Relic + * 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 "relic.h" +#include "myconf.h" + +#define RL_NAMEMAX 512 /* max size of a database name */ +#define RL_DIRFSUF MYEXTSTR "dir" /* suffix of a directory file */ +#define RL_DATAFSUF MYEXTSTR "pag" /* suffix of a page file */ +#define RL_PATHBUFSIZ 1024 /* size of a path buffer */ +#define RL_INITBNUM 1913 /* initial bucket number */ +#define RL_ALIGNSIZ 16 /* size of alignment */ +#define RL_MAXLOAD 1.25 /* max ratio of bucket loading */ +#define RL_DIRMAGIC "[depot]\0\v" /* magic number of a directory file */ + + +/* private function prototypes */ +static void dbm_writedummy(int fd); +static int dbm_writestr(int fd, const char *str); + + + +/************************************************************************************************* + * public objects + *************************************************************************************************/ + + +/* Get a database handle. */ +DBM *dbm_open(char *name, int flags, int mode){ + DBM *db; + DEPOT *depot; + int dpomode; + char path[RL_PATHBUFSIZ]; + int dfd, fd; + assert(name); + if(strlen(name) > RL_NAMEMAX) return NULL; + dpomode = DP_OREADER; + if((flags & O_WRONLY) || (flags & O_RDWR)){ + dpomode = DP_OWRITER; + if(flags & O_CREAT) dpomode |= DP_OCREAT; + if(flags & O_TRUNC) dpomode |= DP_OTRUNC; + } + mode |= 00600; + sprintf(path, "%s%s", name, RL_DIRFSUF); + if((dfd = open(path, flags, mode)) == -1) return NULL; + dbm_writedummy(dfd); + sprintf(path, "%s%s", name, RL_DATAFSUF); + if((fd = open(path, flags, mode)) == -1 || close(fd) == -1){ + close(dfd); + return NULL; + } + if(!(depot = dpopen(path, dpomode, RL_INITBNUM))){ + close(dfd); + return NULL; + } + if(dpomode & DP_OWRITER){ + if(!dpsetalign(depot, RL_ALIGNSIZ)){ + close(dfd); + dpclose(depot); + return NULL; + } + } + if(!(db = malloc(sizeof(DBM)))){ + close(dfd); + dpclose(depot); + return NULL; + } + db->depot = depot; + db->dfd = dfd; + db->dbm_fetch_vbuf = NULL; + db->dbm_nextkey_kbuf = NULL; + return db; +} + + +/* Close a database handle. */ +void dbm_close(DBM *db){ + assert(db); + free(db->dbm_fetch_vbuf); + free(db->dbm_nextkey_kbuf); + close(db->dfd); + dpclose(db->depot); + free(db); +} + + +/* Store a record. */ +int dbm_store(DBM *db, datum key, datum content, int flags){ + int dmode; + int bnum, rnum; + assert(db); + if(!key.dptr || key.dsize < 0 || !content.dptr || content.dsize < 0) return -1; + dmode = (flags == DBM_INSERT) ? DP_DKEEP : DP_DOVER; + if(!dpput(db->depot, key.dptr, key.dsize, content.dptr, content.dsize, dmode)){ + if(dpecode == DP_EKEEP) return 1; + return -1; + } + bnum = dpbnum(db->depot); + rnum = dprnum(db->depot); + if(bnum > 0 && rnum > 0 && ((double)rnum / (double)bnum > RL_MAXLOAD)){ + if(!dpoptimize(db->depot, -1)) return -1; + } + return 0; +} + + +/* Delete a record. */ +int dbm_delete(DBM *db, datum key){ + assert(db); + if(!key.dptr || key.dsize < 0) return -1; + if(!dpout(db->depot, key.dptr, key.dsize)) return -1; + return 0; +} + + +/* Retrieve a record. */ +datum dbm_fetch(DBM *db, datum key){ + datum content; + char *vbuf; + int vsiz; + assert(db); + if(!key.dptr || key.dsize < 0 || + !(vbuf = dpget(db->depot, key.dptr, key.dsize, 0, -1, &vsiz))){ + content.dptr = NULL; + content.dsize = 0; + return content; + } + free(db->dbm_fetch_vbuf); + db->dbm_fetch_vbuf = vbuf; + content.dptr = vbuf; + content.dsize = vsiz; + return content; +} + + +/* Get the first key of a database. */ +datum dbm_firstkey(DBM *db){ + assert(db); + dpiterinit(db->depot); + return dbm_nextkey(db); +} + + +/* Get the next key of a database. */ +datum dbm_nextkey(DBM *db){ + datum key; + char *kbuf; + int ksiz; + if(!(kbuf = dpiternext(db->depot, &ksiz))){ + key.dptr = NULL; + key.dsize = 0; + return key; + } + free(db->dbm_nextkey_kbuf); + db->dbm_nextkey_kbuf = kbuf; + key.dptr = kbuf; + key.dsize = ksiz; + return key; +} + + +/* Check whether a database has a fatal error or not. */ +int dbm_error(DBM *db){ + assert(db); + return dpfatalerror(db->depot) ? TRUE : FALSE; +} + + +/* No effect. */ +int dbm_clearerr(DBM *db){ + assert(db); + return 0; +} + + +/* Check whether a handle is read-only or not. */ +int dbm_rdonly(DBM *db){ + assert(db); + return dpwritable(db->depot) ? FALSE : TRUE; +} + + +/* Get the file descriptor of a directory file. */ +int dbm_dirfno(DBM *db){ + assert(db); + return db->dfd; +} + + +/* Get the file descriptor of a data file. */ +int dbm_pagfno(DBM *db){ + assert(db); + return dpfdesc(db->depot); +} + + + +/************************************************************************************************* + * private objects + *************************************************************************************************/ + + +/* Write dummy data into a dummy file. + `fd' specifies a file descriptor. */ +static void dbm_writedummy(int fd){ + struct stat sbuf; + if(fstat(fd, &sbuf) == -1 || sbuf.st_size > 0) return; + write(fd, RL_DIRMAGIC, sizeof(RL_DIRMAGIC) - 1); + dbm_writestr(fd, "\n\n"); + dbm_writestr(fd, "\x20\x20\xa2\xca\xa1\xb2\xa2\xca\x20\x20\x20\x20\x20\xa1\xbf\xa1"); + dbm_writestr(fd, "\xb1\xa1\xb1\xa1\xb1\xa1\xb1\xa1\xb1\xa1\xb1\xa1\xb1\xa1\xb1\xa1"); + dbm_writestr(fd, "\xb1\x0a\xa1\xca\x20\xa1\xad\xa2\xcf\xa1\xae\xa1\xcb\xa1\xe3\x20"); + dbm_writestr(fd, "\x20\x4e\x44\x42\x4d\x20\x43\x6f\x6d\x70\x61\x74\x69\x62\x69\x6c"); + dbm_writestr(fd, "\x69\x74\x79\x0a\xa1\xca\x20\x20\x20\x20\x20\x20\x20\xa1\xcb\x20"); + dbm_writestr(fd, "\x20\xa1\xc0\xa1\xb2\xa1\xb2\xa1\xb2\xa1\xb2\xa1\xb2\xa1\xb2\xa1"); + dbm_writestr(fd, "\xb2\xa1\xb2\xa1\xb2\x0a\x20\xa1\xc3\x20\x20\xa1\xc3\x20\xa1\xc3"); + dbm_writestr(fd, "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"); + dbm_writestr(fd, "\x20\x20\x20\x20\x20\x20\x20\x0a\xa1\xca\x5f\x5f\xa1\xb2\xa1\xcb"); + dbm_writestr(fd, "\x5f\xa1\xcb\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"); + dbm_writestr(fd, "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a"); +} + + +/* Write a string into a file. + `fd' specifies a file descriptor. + `str' specifies a string. */ +static int dbm_writestr(int fd, const char *str){ + const char *lbuf; + int size, rv, wb; + assert(fd >= 0 && str); + lbuf = str; + size = strlen(str); + 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; +} + + + +/* END OF FILE */ |