Index: include/mpool.h =================================================================== --- include/mpool.h (revision 189453) +++ include/mpool.h (working copy) @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mpool.h 8.2 (Berkeley) 7/14/94 + * @(#)mpool.h 8.4 (Berkeley) 11/2/95 * $FreeBSD$ */ @@ -47,7 +47,7 @@ * pool is handed an opaque MPOOL cookie which stores all of this information. */ #define HASHSIZE 128 -#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE) +#define HASHKEY(pgno) ((pgno - 1 + HASHSIZE) % HASHSIZE) /* The BKT structures are the elements of the queues. */ typedef struct _bkt { @@ -58,6 +58,7 @@ #define MPOOL_DIRTY 0x01 /* page needs to be written */ #define MPOOL_PINNED 0x02 /* page is pinned into memory */ +#define MPOOL_INUSE 0x04 /* page address is valid */ u_int8_t flags; /* flags */ } BKT; @@ -68,7 +69,7 @@ pgno_t curcache; /* current number of cached pages */ pgno_t maxcache; /* max number of cached pages */ pgno_t npages; /* number of pages in the file */ - u_long pagesize; /* file page size */ + unsigned long pagesize; /* file page size */ int fd; /* file descriptor */ /* page in conversion routine */ void (*pgin)(void *, pgno_t, void *); @@ -76,25 +77,32 @@ void (*pgout)(void *, pgno_t, void *); void *pgcookie; /* cookie for page in/out routines */ #ifdef STATISTICS - u_long cachehit; - u_long cachemiss; - u_long pagealloc; - u_long pageflush; - u_long pageget; - u_long pagenew; - u_long pageput; - u_long pageread; - u_long pagewrite; + unsigned long cachehit; + unsigned long cachemiss; + unsigned long pagealloc; + unsigned long pageflush; + unsigned long pageget; + unsigned long pagenew; + unsigned long pageput; + unsigned long pageread; + unsigned long pagewrite; #endif } MPOOL; +#define MPOOL_IGNOREPIN 0x01 /* Ignore if the page is pinned. */ +#define MPOOL_PAGE_REQUEST 0x01 /* Allocate a new page with a + specific page number. */ +#define MPOOL_PAGE_NEXT 0x02 /* Allocate a new page with the next + page number. */ + __BEGIN_DECLS MPOOL *mpool_open(void *, int, pgno_t, pgno_t); void mpool_filter(MPOOL *, void (*)(void *, pgno_t, void *), void (*)(void *, pgno_t, void *), void *); -void *mpool_new(MPOOL *, pgno_t *); -void *mpool_get(MPOOL *, pgno_t, u_int); -int mpool_put(MPOOL *, void *, u_int); +void *mpool_new(MPOOL *, pgno_t *, unsigned int); +void *mpool_get(MPOOL *, pgno_t, unsigned int); +int mpool_delete(MPOOL *, void *); +int mpool_put(MPOOL *, void *, unsigned int); int mpool_sync(MPOOL *); int mpool_close(MPOOL *); #ifdef STATISTICS Index: lib/libc/db/btree/bt_page.c =================================================================== --- lib/libc/db/btree/bt_page.c (revision 189453) +++ lib/libc/db/btree/bt_page.c (working copy) @@ -90,5 +90,5 @@ F_SET(t, B_METADIRTY); return (h); } - return (mpool_new(t->bt_mp, npg)); + return (mpool_new(t->bt_mp, npg, MPOOL_PAGE_NEXT)); } Index: lib/libc/db/btree/bt_debug.c =================================================================== --- lib/libc/db/btree/bt_debug.c (revision 189453) +++ lib/libc/db/btree/bt_debug.c (working copy) @@ -61,7 +61,7 @@ char *sep; t = dbp->internal; - (void)fprintf(stderr, "%s: pgsz %d", + (void)fprintf(stderr, "%s: pgsz %u", F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize); if (F_ISSET(t, R_RECNO)) (void)fprintf(stderr, " keys %u", t->bt_nrecs); @@ -83,10 +83,9 @@ } #undef X - for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) { + for (i = P_ROOT; + (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i) __bt_dpage(h); - (void)mpool_put(t->bt_mp, h, 0); - } } /* @@ -135,10 +134,8 @@ PAGE *h; t = dbp->internal; - if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) { + if ((h = mpool_get(t->bt_mp, pgno, MPOOL_IGNOREPIN)) != NULL) __bt_dpage(h); - (void)mpool_put(t->bt_mp, h, 0); - } } /* @@ -157,7 +154,7 @@ indx_t cur, top; char *sep; - (void)fprintf(stderr, " page %d: (", h->pgno); + (void)fprintf(stderr, " page %u: (", h->pgno); #undef X #define X(flag, name) \ if (h->flags & flag) { \ @@ -174,7 +171,7 @@ (void)fprintf(stderr, ")\n"); #undef X - (void)fprintf(stderr, "\tprev %2d next %2d", h->prevpg, h->nextpg); + (void)fprintf(stderr, "\tprev %2u next %2u", h->prevpg, h->nextpg); if (h->flags & P_OVERFLOW) return; @@ -257,7 +254,8 @@ t = dbp->internal; pcont = pinternal = pleaf = 0; nkeys = ifree = lfree = 0; - for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) { + for (i = P_ROOT; + (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i) switch (h->flags & P_TYPE) { case P_BINTERNAL: case P_RINTERNAL: @@ -274,45 +272,41 @@ ++pcont; break; } - (void)mpool_put(t->bt_mp, h, 0); - } /* Count the levels of the tree. */ for (i = P_ROOT, levels = 0 ;; ++levels) { - h = mpool_get(t->bt_mp, i, 0); + h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN); if (h->flags & (P_BLEAF|P_RLEAF)) { if (levels == 0) levels = 1; - (void)mpool_put(t->bt_mp, h, 0); break; } i = F_ISSET(t, R_RECNO) ? GETRINTERNAL(h, 0)->pgno : GETBINTERNAL(h, 0)->pgno; - (void)mpool_put(t->bt_mp, h, 0); } - (void)fprintf(stderr, "%d level%s with %ld keys", + (void)fprintf(stderr, "%d level%s with %lu keys", levels, levels == 1 ? "" : "s", nkeys); if (F_ISSET(t, R_RECNO)) - (void)fprintf(stderr, " (%d header count)", t->bt_nrecs); + (void)fprintf(stderr, " (%u header count)", t->bt_nrecs); (void)fprintf(stderr, - "\n%u pages (leaf %d, internal %d, overflow %d)\n", + "\n%u pages (leaf %u, internal %u, overflow %u)\n", pinternal + pleaf + pcont, pleaf, pinternal, pcont); - (void)fprintf(stderr, "%ld cache hits, %ld cache misses\n", + (void)fprintf(stderr, "%lu cache hits, %lu cache misses\n", bt_cache_hit, bt_cache_miss); (void)fprintf(stderr, "%lu splits (%lu root splits, %lu sort splits)\n", bt_split, bt_rootsplit, bt_sortsplit); pleaf *= t->bt_psize - BTDATAOFF; if (pleaf) (void)fprintf(stderr, - "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n", + "%.0f%% leaf fill (%lu bytes used, %lu bytes free)\n", ((double)(pleaf - lfree) / pleaf) * 100, pleaf - lfree, lfree); pinternal *= t->bt_psize - BTDATAOFF; if (pinternal) (void)fprintf(stderr, - "%.0f%% internal fill (%ld bytes used, %ld bytes free\n", + "%.0f%% internal fill (%lu bytes used, %lu bytes free\n", ((double)(pinternal - ifree) / pinternal) * 100, pinternal - ifree, ifree); if (bt_pfxsaved) Index: lib/libc/db/btree/bt_split.c =================================================================== --- lib/libc/db/btree/bt_split.c (revision 189453) +++ lib/libc/db/btree/bt_split.c (working copy) @@ -205,7 +205,7 @@ } /* Split the parent page if necessary or shift the indices. */ - if (h->upper - h->lower < nbytes + sizeof(indx_t)) { + if (h->upper - h->lower < (int32_t)(nbytes + sizeof(indx_t))) { sp = h; h = h->pgno == P_ROOT ? bt_root(t, h, &l, &r, &skip, nbytes) : @@ -372,13 +372,10 @@ } /* Put the new left page for the split into place. */ - if ((l = (PAGE *)malloc(t->bt_psize)) == NULL) { + if ((l = (PAGE *)calloc(1, t->bt_psize)) == NULL) { mpool_put(t->bt_mp, r, 0); return (NULL); } -#ifdef PURIFY - memset(l, 0xff, t->bt_psize); -#endif l->pgno = h->pgno; l->nextpg = r->pgno; l->prevpg = h->prevpg; Index: lib/libc/db/btree/bt_open.c =================================================================== --- lib/libc/db/btree/bt_open.c (revision 189453) +++ lib/libc/db/btree/bt_open.c (working copy) @@ -96,7 +96,7 @@ DB *dbp; pgno_t ncache; ssize_t nr; - int machine_lorder; + int machine_lorder, saved_errno; t = NULL; @@ -122,7 +122,7 @@ */ if (b.psize && (b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 || - b.psize & (sizeof(indx_t) - 1) )) + b.psize & (sizeof(indx_t) - 1))) goto einval; /* Minimum number of keys per page; absolute minimum is 2. */ @@ -156,9 +156,8 @@ goto einval; /* Allocate and initialize DB and BTREE structures. */ - if ((t = (BTREE *)malloc(sizeof(BTREE))) == NULL) + if ((t = (BTREE *)calloc(1, sizeof(BTREE))) == NULL) goto err; - memset(t, 0, sizeof(BTREE)); t->bt_fd = -1; /* Don't close unopened fd on error. */ t->bt_lorder = b.lorder; t->bt_order = NOT; @@ -166,9 +165,8 @@ t->bt_pfx = b.prefix; t->bt_rfd = -1; - if ((t->bt_dbp = dbp = (DB *)malloc(sizeof(DB))) == NULL) + if ((t->bt_dbp = dbp = (DB *)calloc(1, sizeof(DB))) == NULL) goto err; - memset(t->bt_dbp, 0, sizeof(DB)); if (t->bt_lorder != machine_lorder) F_SET(t, B_NEEDSWAP); @@ -242,7 +240,7 @@ if (m.magic != BTREEMAGIC || m.version != BTREEVERSION) goto eftype; if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 || - m.psize & (sizeof(indx_t) - 1) ) + m.psize & (sizeof(indx_t) - 1)) goto eftype; if (m.flags & ~SAVEMETA) goto eftype; @@ -275,8 +273,8 @@ t->bt_psize = b.psize; /* Set the cache size; must be a multiple of the page size. */ - if (b.cachesize && b.cachesize & (b.psize - 1) ) - b.cachesize += (~b.cachesize & (b.psize - 1) ) + 1; + if (b.cachesize && b.cachesize & (b.psize - 1)) + b.cachesize += (~b.cachesize & (b.psize - 1)) + 1; if (b.cachesize < b.psize * MINCACHE) b.cachesize = b.psize * MINCACHE; @@ -327,13 +325,15 @@ eftype: errno = EFTYPE; goto err; -err: if (t) { +err: saved_errno = errno; + if (t) { if (t->bt_dbp) free(t->bt_dbp); if (t->bt_fd != -1) (void)_close(t->bt_fd); free(t); } + errno = saved_errno; return (NULL); } @@ -352,18 +352,25 @@ PAGE *meta, *root; pgno_t npg; - if ((meta = mpool_get(t->bt_mp, 0, 0)) != NULL) { - mpool_put(t->bt_mp, meta, 0); - return (RET_SUCCESS); + if ((root = mpool_get(t->bt_mp, 1, 0)) != NULL) { + if (root->lower == 0 && + root->pgno == 0 && + root->linp[0] == 0) { + mpool_delete(t->bt_mp, root); + errno = EINVAL; + } else { + mpool_put(t->bt_mp, root, 0); + return (RET_SUCCESS); + } } if (errno != EINVAL) /* It's OK to not exist. */ return (RET_ERROR); errno = 0; - if ((meta = mpool_new(t->bt_mp, &npg)) == NULL) + if ((meta = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL) return (RET_ERROR); - if ((root = mpool_new(t->bt_mp, &npg)) == NULL) + if ((root = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL) return (RET_ERROR); if (npg != P_ROOT) @@ -383,14 +390,18 @@ tmp(void) { sigset_t set, oset; - int fd; + int fd, len; char *envtmp = NULL; char path[MAXPATHLEN]; if (issetugid() == 0) envtmp = getenv("TMPDIR"); - (void)snprintf(path, + len = snprintf(path, sizeof(path), "%s/bt.XXXXXXXXXX", envtmp ? envtmp : "/tmp"); + if (len < 0 || len >= (int)sizeof(path)) { + errno = ENAMETOOLONG; + return(-1); + } (void)sigfillset(&set); (void)_sigprocmask(SIG_BLOCK, &set, &oset); Index: lib/libc/db/btree/bt_put.c =================================================================== --- lib/libc/db/btree/bt_put.c (revision 189453) +++ lib/libc/db/btree/bt_put.c (working copy) @@ -197,7 +197,7 @@ * into the offset array, shift the pointers up. */ nbytes = NBLEAFDBT(key->size, data->size); - if (h->upper - h->lower < nbytes + sizeof(indx_t)) { + if (h->upper - h->lower < (int32_t)(nbytes + sizeof(indx_t))) { if ((status = __bt_split(t, h, key, data, dflags, nbytes, idx)) != RET_SUCCESS) return (status); @@ -278,7 +278,7 @@ * have to search to get split stack. */ nbytes = NBLEAFDBT(key->size, data->size); - if (h->upper - h->lower < nbytes + sizeof(indx_t)) + if (h->upper - h->lower < (int32_t)(nbytes + sizeof(indx_t))) goto miss; if (t->bt_order == FORWARD) { Index: lib/libc/db/Symbol.map =================================================================== --- lib/libc/db/Symbol.map (revision 189453) +++ lib/libc/db/Symbol.map (working copy) @@ -16,7 +16,6 @@ dbm_dirfno; mpool_open; mpool_filter; - mpool_new; mpool_get; mpool_put; mpool_close; @@ -24,6 +23,11 @@ mpool_stat; }; +FBSD_1.1 { + mpool_new; + mpool_delete; +}; + FBSDprivate_1.0 { __bt_open; __dbpanic; Index: lib/libc/db/hash/hash_func.c =================================================================== --- lib/libc/db/hash/hash_func.c (revision 189453) +++ lib/libc/db/hash/hash_func.c (working copy) @@ -43,60 +43,57 @@ #include "page.h" #include "extern.h" +#ifdef notdef static u_int32_t hash1(const void *, size_t) __unused; static u_int32_t hash2(const void *, size_t) __unused; static u_int32_t hash3(const void *, size_t) __unused; +#endif static u_int32_t hash4(const void *, size_t); -/* Global default hash function */ +/* Default hash function. */ u_int32_t (*__default_hash)(const void *, size_t) = hash4; +#ifdef notdef /* - * HASH FUNCTIONS - * * Assume that we've already split the bucket to which this key hashes, * calculate that bucket, and check that in fact we did already split it. * - * This came from ejb's hsearch. + * EJB's original hsearch hash. */ - #define PRIME1 37 #define PRIME2 1048583 -static u_int32_t -hash1(keyarg, len) - const void *keyarg; - size_t len; +u_int32_t +hash1(const void *key, size_t len) { - const u_char *key; u_int32_t h; + u_int8_t *k; + h = 0; + k = (u_int8_t *)key; /* Convert string to integer */ - for (key = keyarg, h = 0; len--;) - h = h * PRIME1 ^ (*key++ - ' '); + while (len--) + h = h * PRIME1 ^ (*k++ - ' '); h %= PRIME2; return (h); } /* - * Phong's linear congruential hash + * Phong Vo's linear congruential hash */ #define dcharhash(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c)) -static u_int32_t -hash2(keyarg, len) - const void *keyarg; - size_t len; +u_int32_t +hash2(const void *key, size_t len) { - const u_char *e, *key; u_int32_t h; - u_char c; + u_int8_t *e, c, *k; - key = keyarg; - e = key + len; - for (h = 0; key != e;) { - c = *key++; - if (!c && key > e) + k = (u_int8_t *)key; + e = k + len; + for (h = 0; k != e;) { + c = *k++; + if (!c && k > e) break; dcharhash(h, c); } @@ -110,101 +107,84 @@ * all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If * this routine is heavily used enough, it's worth the ugly coding. * - * OZ's original sdbm hash + * Ozan Yigit's original sdbm hash. */ -static u_int32_t -hash3(keyarg, len) - const void *keyarg; - size_t len; +u_int32_t +hash3(const void *key, size_t len) { - const u_char *key; - size_t loop; - u_int32_t h; + u_int32_t n, loop; + u_int8_t *k; -#define HASHC h = *key++ + 65599 * h +#define HASHC n = *k++ + 65599 * n - h = 0; - key = keyarg; + n = 0; + k = (u_int8_t *)key; if (len > 0) { loop = (len + 8 - 1) >> 3; switch (len & (8 - 1)) { case 0: - do { + do { /* All fall throughs */ HASHC; - /* FALLTHROUGH */ case 7: HASHC; - /* FALLTHROUGH */ case 6: HASHC; - /* FALLTHROUGH */ case 5: HASHC; - /* FALLTHROUGH */ case 4: HASHC; - /* FALLTHROUGH */ case 3: HASHC; - /* FALLTHROUGH */ case 2: HASHC; - /* FALLTHROUGH */ case 1: HASHC; } while (--loop); } + } - return (h); + return (n); } +#endif /* notdef */ -/* Hash function from Chris Torek. */ -static u_int32_t -hash4(keyarg, len) - const void *keyarg; - size_t len; +/* Chris Torek's hash function. */ +u_int32_t +hash4(const void *key, size_t len) { - const u_char *key; - size_t loop; - u_int32_t h; + u_int32_t h, loop; + const u_int8_t *k; -#define HASH4a h = (h << 5) - h + *key++; -#define HASH4b h = (h << 5) + h + *key++; +#define HASH4a h = (h << 5) - h + *k++; +#define HASH4b h = (h << 5) + h + *k++; #define HASH4 HASH4b h = 0; - key = keyarg; + k = key; if (len > 0) { loop = (len + 8 - 1) >> 3; switch (len & (8 - 1)) { case 0: - do { + do { /* All fall throughs */ HASH4; - /* FALLTHROUGH */ case 7: HASH4; - /* FALLTHROUGH */ case 6: HASH4; - /* FALLTHROUGH */ case 5: HASH4; - /* FALLTHROUGH */ case 4: HASH4; - /* FALLTHROUGH */ case 3: HASH4; - /* FALLTHROUGH */ case 2: HASH4; - /* FALLTHROUGH */ case 1: HASH4; } while (--loop); } + } return (h); } Index: lib/libc/db/hash/hash_buf.c =================================================================== --- lib/libc/db/hash/hash_buf.c (revision 189453) +++ lib/libc/db/hash/hash_buf.c (working copy) @@ -57,6 +57,7 @@ #include #include #include +#include #ifdef DEBUG #include @@ -163,24 +164,38 @@ oaddr = 0; bp = LRU; + + /* It is bad to overwrite the page under the cursor. */ + if (bp == hashp->cpage) { + BUF_REMOVE(bp); + MRU_INSERT(bp); + bp = LRU; + } + + /* If prev_bp is part of bp overflow, create a new buffer. */ + if (hashp->nbufs == 0 && prev_bp && bp->ovfl) { + BUFHEAD *ovfl; + + for (ovfl = bp->ovfl; ovfl ; ovfl = ovfl->ovfl) { + if (ovfl == prev_bp) { + hashp->nbufs++; + break; + } + } + } + /* * If LRU buffer is pinned, the buffer pool is too small. We need to * allocate more buffers. */ - if (hashp->nbufs || (bp->flags & BUF_PIN)) { + if (hashp->nbufs || (bp->flags & BUF_PIN) || bp == hashp->cpage) { /* Allocate a new one */ - if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL) + if ((bp = (BUFHEAD *)calloc(1, sizeof(BUFHEAD))) == NULL) return (NULL); -#ifdef PURIFY - memset(bp, 0xff, sizeof(BUFHEAD)); -#endif - if ((bp->page = (char *)malloc(hashp->BSIZE)) == NULL) { + if ((bp->page = (char *)calloc(1, hashp->BSIZE)) == NULL) { free(bp); return (NULL); } -#ifdef PURIFY - memset(bp->page, 0xff, hashp->BSIZE); -#endif if (hashp->nbufs) hashp->nbufs--; } else { @@ -267,7 +282,7 @@ */ #ifdef DEBUG1 (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n", - prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0), + prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0), (bp ? bp->addr : 0)); #endif prev_bp->ovfl = bp; @@ -319,8 +334,10 @@ } /* Check if we are freeing stuff */ if (do_free) { - if (bp->page) + if (bp->page) { + (void)memset(bp->page, 0, hashp->BSIZE); free(bp->page); + } BUF_REMOVE(bp); free(bp); bp = LRU; Index: lib/libc/db/hash/hash_page.c =================================================================== --- lib/libc/db/hash/hash_page.c (revision 189453) +++ lib/libc/db/hash/hash_page.c (working copy) @@ -53,7 +53,7 @@ */ #include "namespace.h" -#include +#include #include #include @@ -124,9 +124,8 @@ int __delpair(HTAB *hashp, BUFHEAD *bufp, int ndx) { - u_int16_t *bp, newoff; + u_int16_t *bp, newoff, pairlen; int n; - u_int16_t pairlen; bp = (u_int16_t *)bufp->page; n = bp[0]; @@ -156,6 +155,14 @@ bp[i - 1] = bp[i + 1] + pairlen; } } + if (ndx == hashp->cndx) { + /* + * We just removed pair we were "pointing" to. + * By moving back the cndx we ensure subsequent + * hash_seq() calls won't skip over any entries. + */ + hashp->cndx -= 2; + } } /* Finally adjust the page data */ bp[n] = OFFSET(bp) + pairlen; @@ -405,17 +412,22 @@ if (!bufp) return (-1); bp = (u_int16_t *)bufp->page; - } else + } else if (bp[bp[0]] != OVFLPAGE) { + /* Short key/data pairs, no more pages */ + break; + } else { /* Try to squeeze key on this page */ - if (FREESPACE(bp) > PAIRSIZE(key, val)) { + if (bp[2] >= REAL_KEY && + FREESPACE(bp) >= PAIRSIZE(key, val)) { squeeze_key(bp, key, val); - return (0); + goto stats; } else { bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); if (!bufp) return (-1); bp = (u_int16_t *)bufp->page; } + } if (PAIRFITS(bp, key, val)) putpair(bufp->page, key, val); @@ -432,6 +444,7 @@ if (__big_insert(hashp, bufp, key, val)) return (-1); } +stats: bufp->flags |= BUF_MOD; /* * If the average number of keys per bucket exceeds the fill factor, @@ -453,8 +466,7 @@ BUFHEAD * __add_ovflpage(HTAB *hashp, BUFHEAD *bufp) { - u_int16_t *sp; - u_int16_t ndx, ovfl_num; + u_int16_t *sp, ndx, ovfl_num; #ifdef DEBUG1 int tmp1, tmp2; #endif @@ -505,8 +517,7 @@ __get_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_disk, int is_bitmap) { - int fd, page, size; - int rsize; + int fd, page, size, rsize; u_int16_t *bp; fd = hashp->fp; @@ -520,8 +531,7 @@ page = BUCKET_TO_PAGE(bucket); else page = OADDR_TO_PAGE(bucket); - if ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) || - ((rsize = _read(fd, p, size)) == -1)) + if ((rsize = pread(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1) return (-1); bp = (u_int16_t *)p; if (!rsize) @@ -561,8 +571,7 @@ int __put_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_bitmap) { - int fd, page, size; - int wsize; + int fd, page, size, wsize; size = hashp->BSIZE; if ((hashp->fp == -1) && open_temp(hashp)) @@ -570,8 +579,7 @@ fd = hashp->fp; if (hashp->LORDER != BYTE_ORDER) { - int i; - int max; + int i, max; if (is_bitmap) { max = hashp->BSIZE >> 2; /* divide by 4 */ @@ -587,8 +595,7 @@ page = BUCKET_TO_PAGE(bucket); else page = OADDR_TO_PAGE(bucket); - if ((lseek(fd, (off_t)page << hashp->BSHIFT, SEEK_SET) == -1) || - ((wsize = _write(fd, p, size)) == -1)) + if ((wsize = pwrite(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1) /* Errno is set */ return (-1); if (wsize != size) { @@ -664,7 +671,7 @@ in_use_bits = free_bit; else in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1; - + if (i == first_page) { bit = hashp->LAST_FREED & ((hashp->BSIZE << BYTE_SHIFT) - 1); @@ -689,6 +696,7 @@ if (offset > SPLITMASK) { if (++splitnum >= NCACHED) { (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); + errno = EFBIG; return (0); } hashp->OVFL_POINT = splitnum; @@ -702,6 +710,7 @@ free_page++; if (free_page >= NCACHED) { (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); + errno = EFBIG; return (0); } /* @@ -727,6 +736,7 @@ if (++splitnum >= NCACHED) { (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); + errno = EFBIG; return (0); } hashp->OVFL_POINT = splitnum; @@ -770,8 +780,11 @@ /* Calculate the split number for this page */ for (i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++); offset = (i ? bit - hashp->SPARES[i - 1] : bit); - if (offset >= SPLITMASK) + if (offset >= SPLITMASK) { + (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1); + errno = EFBIG; return (0); /* Out of overflow pages */ + } addr = OADDR_OF(i, offset); #ifdef DEBUG2 (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n", @@ -833,13 +846,24 @@ open_temp(HTAB *hashp) { sigset_t set, oset; - static char namestr[] = "_hashXXXXXX"; + int len; + char *envtmp = NULL; + char path[MAXPATHLEN]; + if (issetugid() == 0) + envtmp = getenv("TMPDIR"); + len = snprintf(path, + sizeof(path), "%s/_hash.XXXXXX", envtmp ? envtmp : "/tmp"); + if (len < 0 || len >= sizeof(path)) { + errno = ENAMETOOLONG; + return (-1); + } + /* Block signals; make sure file goes away at process exit. */ (void)sigfillset(&set); (void)_sigprocmask(SIG_BLOCK, &set, &oset); - if ((hashp->fp = mkstemp(namestr)) != -1) { - (void)unlink(namestr); + if ((hashp->fp = mkstemp(path)) != -1) { + (void)unlink(path); (void)_fcntl(hashp->fp, F_SETFD, 1); } (void)_sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); Index: lib/libc/db/hash/hash.c =================================================================== --- lib/libc/db/hash/hash.c (revision 189453) +++ lib/libc/db/hash/hash.c (working copy) @@ -120,25 +120,15 @@ */ hashp->flags = flags; - new_table = 0; - if (!file || (flags & O_TRUNC) || - (stat(file, &statbuf) && (errno == ENOENT))) { - if (errno == ENOENT) - errno = 0; /* Just in case someone looks at errno */ - new_table = 1; - } if (file) { if ((hashp->fp = _open(file, flags, mode)) == -1) RETURN_ERROR(errno, error0); - - /* if the .db file is empty, and we had permission to create - a new .db file, then reinitialize the database */ - if ((flags & O_CREAT) && - _fstat(hashp->fp, &statbuf) == 0 && statbuf.st_size == 0) - new_table = 1; - (void)_fcntl(hashp->fp, F_SETFD, 1); - } + new_table = _fstat(hashp->fp, &statbuf) == 0 && + statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY; + } else + new_table = 1; + if (new_table) { if (!(hashp = init_hash(hashp, file, info))) RETURN_ERROR(errno, error1); @@ -164,7 +154,7 @@ if (hashp->VERSION != HASHVERSION && hashp->VERSION != OLDHASHVERSION) RETURN_ERROR(EFTYPE, error1); - if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY) + if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY) RETURN_ERROR(EFTYPE, error1); /* * Figure out how many segments we need. Max_Bucket is the @@ -173,7 +163,6 @@ */ nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) / hashp->SGSIZE; - hashp->nsegs = 0; if (alloc_segs(hashp, nsegs)) /* * If alloc_segs fails, table will have been destroyed @@ -230,8 +219,8 @@ "LAST FREED ", hashp->LAST_FREED, "HIGH MASK ", hashp->HIGH_MASK, "LOW MASK ", hashp->LOW_MASK, - "NSEGS ", hashp->nsegs, - "NKEYS ", hashp->NKEYS); + "NSEGS ", hashp->nsegs, + "NKEYS ", hashp->NKEYS); #endif #ifdef HASH_STATISTICS hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0; @@ -347,8 +336,7 @@ static int init_htab(HTAB *hashp, int nelem) { - int nbuckets, nsegs; - int l2; + int nbuckets, nsegs, l2; /* * Divide number of elements by the fill factor and determine a @@ -428,6 +416,10 @@ for (i = 0; i < hashp->nmaps; i++) if (hashp->mapp[i]) free(hashp->mapp[i]); + if (hashp->tmp_key) + free(hashp->tmp_key); + if (hashp->tmp_buf) + free(hashp->tmp_buf); if (hashp->fp != -1) (void)_close(hashp->fp); @@ -495,8 +487,7 @@ whdrp = &whdr; swap_header_copy(&hashp->hdr, whdrp); #endif - if ((lseek(fp, (off_t)0, SEEK_SET) == -1) || - ((wsize = _write(fp, whdrp, sizeof(HASHHDR))) == -1)) + if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1) return (-1); else if (wsize != sizeof(HASHHDR)) { @@ -541,8 +532,7 @@ hashp = (HTAB *)dbp->internal; if (flag && flag != R_NOOVERWRITE) { - hashp->error = EINVAL; - errno = EINVAL; + hashp->error = errno = EINVAL; return (ERROR); } if ((hashp->flags & O_ACCMODE) == O_RDONLY) { @@ -721,7 +711,7 @@ hashp->cndx = 1; hashp->cpage = NULL; } - + next_bucket: for (bp = NULL; !bp || !bp[0]; ) { if (!(bufp = hashp->cpage)) { for (bucket = hashp->cbucket; @@ -740,8 +730,18 @@ hashp->cbucket = -1; return (ABNORMAL); } - } else + } else { bp = (u_int16_t *)hashp->cpage->page; + if (flag == R_NEXT) { + hashp->cndx += 2; + if (hashp->cndx > bp[0]) { + hashp->cpage = NULL; + hashp->cbucket++; + hashp->cndx = 1; + goto next_bucket; + } + } + } #ifdef DEBUG assert(bp); @@ -765,17 +765,12 @@ if (__big_keydata(hashp, bufp, key, data, 1)) return (ERROR); } else { + if (hashp->cpage == 0) + return (ERROR); key->data = (u_char *)hashp->cpage->page + bp[ndx]; key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx]; data->data = (u_char *)hashp->cpage->page + bp[ndx + 1]; data->size = bp[ndx] - bp[ndx + 1]; - ndx += 2; - if (ndx > bp[0]) { - hashp->cpage = NULL; - hashp->cbucket++; - hashp->cndx = 1; - } else - hashp->cndx = ndx; } return (SUCCESS); } @@ -887,15 +882,18 @@ errno = save_errno; return (-1); } + hashp->nsegs = nsegs; + if (nsegs == 0) + return (0); /* Allocate segments */ - if ((store = - (SEGMENT)calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) { + if ((store = (SEGMENT)calloc(nsegs << hashp->SSHIFT, + sizeof(SEGMENT))) == NULL) { save_errno = errno; (void)hdestroy(hashp); errno = save_errno; return (-1); } - for (i = 0; i < nsegs; i++, hashp->nsegs++) + for (i = 0; i < nsegs; i++) hashp->dir[i] = &store[i << hashp->SSHIFT]; return (0); } Index: lib/libc/db/hash/hash_log2.c =================================================================== --- lib/libc/db/hash/hash_log2.c (revision 189453) +++ lib/libc/db/hash/hash_log2.c (working copy) @@ -36,9 +36,10 @@ #include __FBSDID("$FreeBSD$"); -#include - #include +#include "hash.h" +#include "page.h" +#include "extern.h" u_int32_t __log2(u_int32_t num) Index: lib/libc/db/hash/README =================================================================== --- lib/libc/db/hash/README (revision 189453) +++ lib/libc/db/hash/README (working copy) @@ -44,10 +44,6 @@ NOTES: -The file search.h is provided for using the hsearch compatible interface -on BSD systems. On System V derived systems, search.h should appear in -/usr/include. - The man page ../man/db.3 explains the interface to the hashing system. The file hash.ps is a postscript copy of a paper explaining the history, implementation, and performance of the hash package. Index: lib/libc/db/hash/hash_bigkey.c =================================================================== --- lib/libc/db/hash/hash_bigkey.c (revision 189453) +++ lib/libc/db/hash/hash_bigkey.c (working copy) @@ -117,18 +117,30 @@ return (-1); n = p[0]; if (!key_size) { - if (FREESPACE(p)) { - move_bytes = MIN(FREESPACE(p), val_size); + space = FREESPACE(p); + if (space) { + move_bytes = MIN(space, val_size); + /* + * If the data would fit exactly in the + * remaining space, we must overflow it to the + * next page; otherwise the invariant that the + * data must end on a page with FREESPACE + * non-zero would fail. + */ + if (space == val_size && val_size == val->size) + goto toolarge; off = OFFSET(p) - move_bytes; - p[n] = off; memmove(cp + off, val_data, move_bytes); val_data += move_bytes; val_size -= move_bytes; + p[n] = off; p[n - 2] = FULL_KEY_DATA; FREESPACE(p) = FREESPACE(p) - move_bytes; OFFSET(p) = off; - } else + } else { + toolarge: p[n - 2] = FULL_KEY; + } } p = (u_int16_t *)bufp->page; cp = bufp->page; @@ -238,12 +250,12 @@ n -= 2; bp[0] = n; FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); - OFFSET(bp) = hashp->BSIZE - 1; + OFFSET(bp) = hashp->BSIZE; bufp->flags |= BUF_MOD; if (rbufp) __free_ovflpage(hashp, rbufp); - if (last_bfp != rbufp) + if (last_bfp && last_bfp != rbufp) __free_ovflpage(hashp, last_bfp); hashp->NKEYS--; Index: lib/libc/db/db/db.c =================================================================== --- lib/libc/db/db/db.c (revision 189453) +++ lib/libc/db/db/db.c (working copy) @@ -50,8 +50,8 @@ #define DB_FLAGS (DB_LOCK | DB_SHMEM | DB_TXN) #define USE_OPEN_FLAGS \ - (O_CREAT | O_EXCL | O_EXLOCK | O_NONBLOCK | O_RDONLY | \ - O_RDWR | O_SHLOCK | O_TRUNC) + (O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW | O_NONBLOCK | \ + O_RDONLY | O_RDWR | O_SHLOCK | O_SYNC | O_TRUNC) if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0) switch (type) { Index: lib/libc/db/mpool/Makefile.inc =================================================================== --- lib/libc/db/mpool/Makefile.inc (revision 189453) +++ lib/libc/db/mpool/Makefile.inc (working copy) @@ -3,4 +3,4 @@ .PATH: ${.CURDIR}/db/mpool -SRCS+= mpool.c +SRCS+= mpool.c mpool-compat.c Index: lib/libc/db/mpool/mpool.c =================================================================== --- lib/libc/db/mpool/mpool.c (revision 189453) +++ lib/libc/db/mpool/mpool.c (working copy) @@ -110,9 +110,7 @@ * Get a new page of memory. */ void * -mpool_new(mp, pgnoaddr) - MPOOL *mp; - pgno_t *pgnoaddr; +mpool_new(MPOOL *mp, pgno_t *pgnoaddr, u_int flags) { struct _hqh *head; BKT *bp; @@ -131,15 +129,46 @@ */ if ((bp = mpool_bkt(mp)) == NULL) return (NULL); - *pgnoaddr = bp->pgno = mp->npages++; - bp->flags = MPOOL_PINNED; + if (flags == MPOOL_PAGE_REQUEST) { + mp->npages++; + bp->pgno = *pgnoaddr; + } else + bp->pgno = *pgnoaddr = mp->npages++; + bp->flags = MPOOL_PINNED | MPOOL_INUSE; + head = &mp->hqh[HASHKEY(bp->pgno)]; TAILQ_INSERT_HEAD(head, bp, hq); TAILQ_INSERT_TAIL(&mp->lqh, bp, q); return (bp->page); } +int +mpool_delete(MPOOL *mp, void *page) +{ + struct _hqh *head; + BKT *bp; + + bp = (BKT *)((char *)page - sizeof(BKT)); + +#ifdef DEBUG + if (!(bp->flags & MPOOL_PINNED)) { + (void)fprintf(stderr, + "mpool_delete: page %d not pinned\n", bp->pgno); + abort(); + } +#endif + + /* Remove from the hash and lru queues. */ + head = &mp->hqh[HASHKEY(bp->pgno)]; + TAILQ_REMOVE(head, bp, hq); + TAILQ_REMOVE(&mp->lqh, bp, q); + + free(bp); + mp->curcache--; + return (RET_SUCCESS); +} + /* * mpool_get * Get a page. @@ -154,12 +183,6 @@ off_t off; int nr; - /* Check for attempt to retrieve a non-existent page. */ - if (pgno >= mp->npages) { - errno = EINVAL; - return (NULL); - } - #ifdef STATISTICS ++mp->pageget; #endif @@ -167,7 +190,7 @@ /* Check for a page that is cached. */ if ((bp = mpool_look(mp, pgno)) != NULL) { #ifdef DEBUG - if (bp->flags & MPOOL_PINNED) { + if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) { (void)fprintf(stderr, "mpool_get: page %d already pinned\n", bp->pgno); abort(); @@ -193,20 +216,38 @@ return (NULL); /* Read in the contents. */ + off = mp->pagesize * pgno; + if ((nr = pread(mp->fd, bp->page, mp->pagesize, off)) != mp->pagesize) { + switch (nr) { + case -1: + /* errno is set for us by pread(). */ + free(bp); + mp->curcache--; + return (NULL); + case 0: + /* + * A zero-length read means you need to create a + * new page. + */ + memset(bp->page, 0, mp->pagesize); + break; + default: + /* A partial read is definitely bad. */ + free(bp); + mp->curcache--; + errno = EINVAL; + return (NULL); + } + } #ifdef STATISTICS ++mp->pageread; #endif - off = mp->pagesize * pgno; - nr = pread(mp->fd, bp->page, mp->pagesize, off); - if (nr != mp->pagesize) { - if (nr >= 0) - errno = EFTYPE; - return (NULL); - } /* Set the page number, pin the page. */ bp->pgno = pgno; - bp->flags = MPOOL_PINNED; + if (!(flags & MPOOL_IGNOREPIN)) + bp->flags = MPOOL_PINNED; + bp->flags |= MPOOL_INUSE; /* * Add the page to the head of the hash chain and the tail @@ -245,7 +286,8 @@ } #endif bp->flags &= ~MPOOL_PINNED; - bp->flags |= flags & MPOOL_DIRTY; + if (flags & MPOOL_DIRTY) + bp->flags |= flags & MPOOL_DIRTY; return (RET_SUCCESS); } @@ -329,18 +371,17 @@ bp->page = spage; } #endif + bp->flags = 0; return (bp); } -new: if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL) +new: if ((bp = (BKT *)calloc(1, sizeof(BKT) + mp->pagesize)) == NULL) return (NULL); #ifdef STATISTICS ++mp->pagealloc; #endif -#if defined(DEBUG) || defined(PURIFY) - memset(bp, 0xff, sizeof(BKT) + mp->pagesize); -#endif bp->page = (char *)bp + sizeof(BKT); + bp->flags = 0; ++mp->curcache; return (bp); } @@ -366,6 +407,15 @@ if (pwrite(mp->fd, bp->page, mp->pagesize, off) != mp->pagesize) return (RET_ERROR); + /* + * Re-run through the input filter since this page may soon be + * accessed via the cache, and whatever the user's output filter + * did may screw things up if we don't let the input filter + * restore the in-core copy. + */ + if (mp->pgin) + (mp->pgin)(mp->pgcookie, bp->pgno, bp->page); + bp->flags &= ~MPOOL_DIRTY; return (RET_SUCCESS); } @@ -382,7 +432,8 @@ head = &mp->hqh[HASHKEY(pgno)]; TAILQ_FOREACH(bp, head, hq) - if (bp->pgno == pgno) { + if ((bp->pgno == pgno) && + ((bp->flags & MPOOL_INUSE) == MPOOL_INUSE)) { #ifdef STATISTICS ++mp->cachehit; #endif @@ -406,9 +457,9 @@ int cnt; char *sep; - (void)fprintf(stderr, "%u pages in the file\n", mp->npages); + (void)fprintf(stderr, "%lu pages in the file\n", mp->npages); (void)fprintf(stderr, - "page size %lu, cacheing %u pages of %u page max cache\n", + "page size %lu, cacheing %lu pages of %lu page max cache\n", mp->pagesize, mp->curcache, mp->maxcache); (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n", mp->pageput, mp->pageget, mp->pagenew); Index: lib/libc/db/mpool/mpool-compat.c =================================================================== --- lib/libc/db/mpool/mpool-compat.c (revision 0) +++ lib/libc/db/mpool/mpool-compat.c (revision 0) @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2009 Xin LI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +void *__mpool_new__44bsd(MPOOL *, pgno_t *); + +void * +__mpool_new__44bsd(MPOOL *mp, pgno_t *pgnoaddr) +{ + + return (mpool_new(mp, pgnoaddr, MPOOL_PAGE_NEXT)); +} + +__sym_compat(mpool_new, __mpool_new_44bsd, FBSD_1.0); Index: lib/libc/db/recno/rec_put.c =================================================================== --- lib/libc/db/recno/rec_put.c (revision 189453) +++ lib/libc/db/recno/rec_put.c (working copy) @@ -63,6 +63,7 @@ DBT fdata, tdata; recno_t nrec; int status; + void *tp; t = dbp->internal; @@ -82,10 +83,10 @@ goto einval; if (t->bt_rdata.size < t->bt_reclen) { - t->bt_rdata.data = - reallocf(t->bt_rdata.data, t->bt_reclen); - if (t->bt_rdata.data == NULL) + tp = realloc(t->bt_rdata.data, t->bt_reclen); + if (tp == NULL) return (RET_ERROR); + t->bt_rdata.data = tp; t->bt_rdata.size = t->bt_reclen; } memmove(t->bt_rdata.data, data->data, data->size); Index: lib/libc/db/man/mpool.3 =================================================================== --- lib/libc/db/man/mpool.3 (revision 189453) +++ lib/libc/db/man/mpool.3 (working copy) @@ -28,7 +28,7 @@ .\" @(#)mpool.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd February 25, 1999 .Dt MPOOL 3 .Os .Sh NAME @@ -47,7 +47,9 @@ .Fa "void *pgcookie" .Fc .Ft void * -.Fn mpool_new "MPOOL *mp" "pgno_t *pgnoaddr" +.Fn mpool_new "MPOOL *mp" "pgno_t *pgnoaddr" "u_int flags" +.Ft int +.Fn mpool_delete "MPOOL *mp" "void *page" .Ft void * .Fn mpool_get "MPOOL *mp" "pgno_t pgno" "u_int flags" .Ft int @@ -99,11 +101,11 @@ .Fa pgcookie pointer, the page number and a pointer to the page to being read or written. .Pp -The +The function .Fn mpool_new -function takes an -.Ft MPOOL -pointer and an address as arguments. +takes an +.Dv MPOOL +pointer, an address, and a set of flags as arguments. If a new page can be allocated, a pointer to the page is returned and the page number is stored into the .Fa pgnoaddr @@ -113,7 +115,25 @@ is returned and .Va errno is set. +The flags value is formed by +.Tn OR Ns 'ing +the following values: +.Bl -tag -width Ds +.It Dv MPOOL_PAGE_REQUEST +Allocate a new page with a specific page number. +.It Dv MPOOL_PAGE_NEXT +Allocate a new page with the next page number. +.El .Pp +The function +.Fn mpool_delete +deletes the specified page from a pool and frees the page. +It takes an +.Dv MPOOL +pointer and a page as arguments. +The page must have been generated by +.Fn mpool_new . +.Pp The .Fn mpool_get function takes a Index: lib/libc/db/README =================================================================== --- lib/libc/db/README (revision 189453) +++ lib/libc/db/README (working copy) @@ -31,10 +31,3 @@ recno The fixed/variable length record routines. test Test package. -============================================ -Debugging: - -If you're running a memory checker (e.g. Purify) on DB, make sure that -you recompile it with "-DPURIFY" in the CFLAGS, first. By default, -allocated pages are not initialized by the DB code, and they will show -up as reads of uninitialized memory in the buffer write routines.