/* * Copyright (C) 1991, Marcus J. Ranum. All rights reserved. * * $Id: udb_ochunk.c,v 1.2 1995/11/22 23:33:17 root Exp $ */ /* * configure all options BEFORE including system stuff. */ #include "autoconf.h" #include "udb_defs.h" #ifdef VMS #include <malloc.h> #include <types.h> #include <file.h> #include <unixio.h> #include "vms_dbm.h" #else #ifndef NEXT #include <malloc.h> #endif /* * NEXT */ #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #include "gdbm.h" #endif /* * VMS */ #include "udb.h" #include "config.h" #include "alloc.h" /* * #define DBMCHUNK_DEBUG */ /* * default block size to use for bitmapped chunks */ #define DDDB_BLOCK 256 /* * bitmap growth increment in BLOCKS not bytes (512 is 64 BYTES) */ #define DDDB_BITBLOCK 512 #define LOGICAL_BLOCK(off) (off/bsiz) #define BLOCK_OFFSET(block) (block*bsiz) #define BLOCKS_NEEDED(siz) (siz % bsiz ? (siz / bsiz) + 1 : (siz / bsiz)) #define BLOCKS_TO_ALLOC(siz) BLOCKS_NEEDED(siz) + (BLOCKS_NEEDED(siz) >> 3) /* * dbm-based object storage routines. Somewhat trickier than the default * directory hash. a free space list is maintained as a bitmap of free * blocks, and an object-pointer list is maintained in a dbm database. */ struct hrec { off_t off; /* * Where it lives in the chunk file */ int siz; /* * How long it really is, in bytes */ unsigned int blox; /* * How many blocks it owns */ }; static int dddb_mark(); #define DEFAULT_DBMCHUNKFILE "mudDB" static char *dbfile = DEFAULT_DBMCHUNKFILE; static int bsiz = DDDB_BLOCK; static int db_initted = 0; static int last_free = 0; /* * last known or suspected free block */ static GDBM_FILE dbp = (GDBM_FILE) 0; static FILE *dbf = (FILE *) 0; static struct hrec hbuf; static char *bitm = (char *)0; static int bm_top = 0; static datum dat; static datum key; static void growbit(); /* * gdbm_reorganize compresses unused space in the db */ int dddb_optimize() { return (gdbm_reorganize(dbp)); } static void gdbm_panic(mesg) char *mesg; { log_text(tprintf("GDBM panic: %s\n", mesg)); } int dddb_init() { static char *copen = "db_init cannot open "; char fnam[MAXPATHLEN]; struct stat sbuf; int fxp, block_size; /* * now open chunk file */ sprintf(fnam, "%s.db", dbfile); /* * Bah. Posix-y systems break "a+", so use this gore instead */ if (((dbf = fopen(fnam, "r+")) == (FILE *) 0) && ((dbf = fopen(fnam, "w+")) == (FILE *) 0)) { logf(copen, fnam, " ", (char *)-1, "\n", (char *)0); return (1); } /* * open hash table */ for (block_size = 1; block_size < LBUF_SIZE; block_size = block_size << 1) ; if ((dbp = gdbm_open(dbfile, block_size, GDBM_WRCREAT, 0600, gdbm_panic)) == (GDBM_FILE) 0) { logf(copen, dbfile, " ", (char *)-1, "\n", (char *)0); return (1); } /* * determine size of chunk file for allocation bitmap */ sprintf(fnam, "%s.db", dbfile); if (stat(fnam, &sbuf)) { logf("db_init cannot stat ", fnam, " ", (char *)-1, "\n", (char *)0); return (1); } /* * allocate bitmap */ growbit(LOGICAL_BLOCK(sbuf.st_size) + DDDB_BITBLOCK); key = gdbm_firstkey(dbp); while (key.dptr != (char *)0) { dat = gdbm_fetch(dbp, key); if (dat.dptr == (char *)0) { logf("db_init index inconsistent\n", (char *)0); return (1); } bcopy(dat.dptr, (char *)&hbuf, sizeof(hbuf)); /* * alignment */ /* * mark it as busy in the bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off), hbuf.blox, 1); key = gdbm_nextkey(dbp, key); } db_initted = 1; return (0); } dddb_initted() { return (db_initted); } dddb_setbsiz(nbsiz) int nbsiz; { return (bsiz = nbsiz); } dddb_setfile(fil) char *fil; { char *xp; if (db_initted) return (1); /* * KNOWN memory leak. can't help it. it's small */ xp = (char *)malloc((unsigned)strlen(fil) + 1); if (xp == (char *)0) return (1); (void)StringCopy(xp, fil); dbfile = xp; return (0); } int dddb_close() { if (dbf != (FILE *) 0) { fclose(dbf); dbf = (FILE *) 0; } if (dbp != (GDBM_FILE) 0) { gdbm_close(dbp); dbp = (GDBM_FILE) 0; } if (bitm != (char *)0) { free((mall_t) bitm); bitm = (char *)0; bm_top = 0; } db_initted = 0; return (0); } /* * grow the bitmap to given size */ static void growbit(maxblok) int maxblok; { int newtop, newbytes, topbytes; char *nbit; /* * round up to eight and then some */ newtop = (maxblok + 15) & 0xfffffff8; if (newtop <= bm_top) return; newbytes = newtop / 8; topbytes = bm_top / 8; nbit = (char *)malloc(newbytes); if (bitm != (char *)0) { bcopy(bitm, (char *)nbit, topbytes); free((mall_t) bitm); } bitm = nbit; if (bitm == (char *)0) fatal("db_init cannot grow bitmap ", (char *)-1, "\n", (char *)0); bzero(bitm + topbytes, (newbytes - topbytes)); bm_top = newtop; } static int dddb_mark(lbn, siz, taken) off_t lbn; int siz; int taken; { int bcnt; bcnt = siz; /* * remember a free block was here */ if (!taken) last_free = lbn; while (bcnt--) { if (lbn >= bm_top - 32) growbit(lbn + DDDB_BITBLOCK); if (taken) bitm[lbn >> 3] |= (1 << (lbn & 7)); else bitm[lbn >> 3] &= ~(1 << (lbn & 7)); lbn++; } } static int dddb_alloc(siz) int siz; { int bcnt; /* * # of blocks to operate on */ int lbn; /* * logical block offset */ int tbcnt; int slbn; int overthetop = 0; int offend = 0; lbn = last_free; bcnt = BLOCKS_TO_ALLOC(siz); while (1) { if (lbn >= bm_top - 32) { /* * only check here. can't break around the top */ if (!overthetop) { lbn = 0; overthetop++; } else { growbit(lbn + DDDB_BITBLOCK); } } slbn = lbn; tbcnt = bcnt; while (1) { if ((bitm[lbn >> 3] & (1 << (lbn & 7))) != 0) break; /* * enough free blocks - mark and done */ if (--tbcnt == 0) { for (tbcnt = slbn; bcnt > 0; tbcnt++, bcnt--) bitm[tbcnt >> 3] |= (1 << (tbcnt & 7)); if (offend) { last_free = 0; } else { last_free = lbn; } return (slbn); } lbn++; if (lbn >= bm_top - 32) { offend++; growbit(lbn + DDDB_BITBLOCK); } } lbn++; } } Obj * dddb_get(nam) Objname *nam; { Obj *ret; if (!db_initted) return ((Obj *) 0); key.dptr = (char *)nam; key.dsize = sizeof(Objname); dat = gdbm_fetch(dbp, key); if (dat.dptr == (char *)0) return ((Obj *) 0); bcopy(dat.dptr, (char *)&hbuf, sizeof(hbuf)); /* * seek to location */ if (fseek(dbf, (long)hbuf.off, 0)) return ((Obj *) 0); /* * if the file is badly formatted, ret == Obj * 0 */ if ((ret = objfromFILE(dbf)) == (Obj *) 0) logf("db_get: cannot decode ", nam, "\n", (char *)0); return (ret); } int dddb_put(obj, nam) Obj *obj; Objname *nam; { int nsiz; if (!db_initted) return (1); nsiz = obj_siz(obj); key.dptr = (char *)nam; key.dsize = sizeof(Objname); dat = gdbm_fetch(dbp, key); if (dat.dptr != (char *)0) { bcopy(dat.dptr, (char *)&hbuf, sizeof(hbuf)); /* * align */ if (BLOCKS_NEEDED(nsiz) > hbuf.blox) { #ifdef DBMCHUNK_DEBUG printf("put: moving obj %d, owned %d blox, required %d, siz %d\n", *(unsigned int *)nam, hbuf.blox, BLOCKS_NEEDED(nsiz), nsiz); #endif /* * mark free in bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off), hbuf.blox, 0); hbuf.off = BLOCK_OFFSET(dddb_alloc(nsiz)); hbuf.siz = nsiz; hbuf.blox = BLOCKS_TO_ALLOC(nsiz); #ifdef DBMCHUNK_DEBUG printf("put: %s moved to offset %d, size %d\n", *(unsigned int *)nam, hbuf.off, hbuf.siz); #endif } else { hbuf.siz = nsiz; #ifdef DBMCHUNK_DEBUG printf("put: %s replaced within offset %d, size %d owns %d blox\n", *(unsigned int *)nam, hbuf.off, hbuf.siz, hbuf.blox); #endif } } else { hbuf.off = BLOCK_OFFSET(dddb_alloc(nsiz)); hbuf.siz = nsiz; hbuf.blox = BLOCKS_TO_ALLOC(nsiz); #ifdef DBMCHUNK_DEBUG printf("put: %s (new) at offset %d, size %d owns %d blox\n", *(unsigned int *)nam, hbuf.off, hbuf.siz, hbuf.blox); #endif } /* * make table entry */ dat.dptr = (char *)&hbuf; dat.dsize = sizeof(hbuf); if (gdbm_store(dbp, key, dat, GDBM_REPLACE)) { logf("db_put: can't gdbm_store ", nam, " ", (char *)-1, "\n", (char *)0); return (1); } #ifdef DBMCHUNK_DEBUG printf("%s offset %d size %d owns %d blox\n", *(unsigned int *)nam, hbuf.off, hbuf.siz, hbuf.blox); #endif if (fseek(dbf, (long)hbuf.off, 0)) { logf("db_put: can't seek ", nam, " ", (char *)-1, "\n", (char *)0); return (1); } if (objtoFILE(obj, dbf) != 0 || fflush(dbf) != 0) { logf("db_put: can't save ", nam, " ", (char *)-1, "\n", (char *)0); return (1); } return (0); } int dddb_check(nam) char *nam; { if (!db_initted) return (0); key.dptr = nam; key.dsize = strlen(nam) + 1; dat = gdbm_fetch(dbp, key); if (dat.dptr == (char *)0) return (0); return (1); } int dddb_del(nam) Objname *nam; { if (!db_initted) return (-1); key.dptr = (char *)nam; key.dsize = sizeof(Objname); dat = gdbm_fetch(dbp, key); /* * not there? */ if (dat.dptr == (char *)0) return (0); bcopy(dat.dptr, (char *)&hbuf, sizeof(hbuf)); /* * drop key from db */ if (gdbm_delete(dbp, key)) { logf("db_del: can't delete key ", nam, "\n", (char *)0); return (1); } /* * mark free space in bitmap */ dddb_mark(LOGICAL_BLOCK(hbuf.off), hbuf.blox, 0); #ifdef DBMCHUNK_DEBUG printf("del: %s free offset %d, size %d owned %d blox\n", *(unsigned int *)nam, hbuf.off, hbuf.siz, hbuf.blox); #endif /* * mark object dead in file */ if (fseek(dbf, (long)hbuf.off, 0)) logf("db_del: can't seek ", nam, " ", (char *)-1, "\n", (char *)0); else { fprintf(dbf, "delobj"); fflush(dbf); } return (0); }