📄 hash.c
字号:
fp = hashp->fp; whdrp = &hashp->hdr;#if BYTE_ORDER == LITTLE_ENDIAN 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)) return (-1); else if (wsize != sizeof(HASHHDR)) { errno = EFTYPE; hashp->errnum = errno; return (-1); } for (i = 0; i < NCACHED; i++) if (hashp->mapp[i]) if (__put_page(hashp, (char *)hashp->mapp[i], hashp->BITMAPS[i], 0, 1)) return (-1); return (0);}/*******************************SEARCH ROUTINES *****************************//* * All the access routines return * * Returns: * 0 on SUCCESS * 1 to indicate an external ERROR (i.e. key not found, etc) * -1 to indicate an internal ERROR (i.e. out of memory, etc) */static inthash_get(dbp, key, data, flag) const DB *dbp; const DBT *key; DBT *data; u_int32_t flag;{ HTAB *hashp; hashp = (HTAB *)dbp->internal; if (flag) { hashp->errnum = errno = EINVAL; return (ERROR); } return (hash_access(hashp, HASH_GET, (DBT *)key, data));}static inthash_put(dbp, key, data, flag) const DB *dbp; DBT *key; const DBT *data; u_int32_t flag;{ HTAB *hashp; hashp = (HTAB *)dbp->internal; if (flag && flag != R_NOOVERWRITE) { hashp->errnum = errno = EINVAL; return (ERROR); } if ((hashp->flags & O_ACCMODE) == O_RDONLY) { hashp->errnum = errno = EPERM; return (ERROR); } return (hash_access(hashp, flag == R_NOOVERWRITE ? HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));}static inthash_delete(dbp, key, flag) const DB *dbp; const DBT *key; u_int32_t flag; /* Ignored */{ HTAB *hashp; hashp = (HTAB *)dbp->internal; if (flag && flag != R_CURSOR) { hashp->errnum = errno = EINVAL; return (ERROR); } if ((hashp->flags & O_ACCMODE) == O_RDONLY) { hashp->errnum = errno = EPERM; return (ERROR); } return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));}/* * Assume that hashp has been set in wrapper routine. */static inthash_access(hashp, action, key, val) HTAB *hashp; ACTION action; DBT *key, *val;{ register BUFHEAD *rbufp; BUFHEAD *bufp, *save_bufp; register u_int16_t *bp; register int n, ndx, off, size; register char *kp; u_int16_t pageno;#ifdef HASH_STATISTICS hash_accesses++;#endif off = hashp->BSIZE; size = key->size; kp = (char *)key->data; rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0); if (!rbufp) return (ERROR); save_bufp = rbufp; /* Pin the bucket chain */ rbufp->flags |= BUF_PIN; for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;) if (bp[1] >= REAL_KEY) { /* Real key/data pair */ if (size == off - *bp && memcmp(kp, rbufp->page + *bp, size) == 0) goto found; off = bp[1];#ifdef HASH_STATISTICS hash_collisions++;#endif bp += 2; ndx += 2; } else if (bp[1] == OVFLPAGE) { rbufp = __get_buf(hashp, *bp, rbufp, 0); if (!rbufp) { save_bufp->flags &= ~BUF_PIN; return (ERROR); } /* FOR LOOP INIT */ bp = (u_int16_t *)rbufp->page; n = *bp++; ndx = 1; off = hashp->BSIZE; } else if (bp[1] < REAL_KEY) { if ((ndx = __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0) goto found; if (ndx == -2) { bufp = rbufp; if (!(pageno = __find_last_page(hashp, &bufp))) { ndx = 0; rbufp = bufp; break; /* FOR */ } rbufp = __get_buf(hashp, pageno, bufp, 0); if (!rbufp) { save_bufp->flags &= ~BUF_PIN; return (ERROR); } /* FOR LOOP INIT */ bp = (u_int16_t *)rbufp->page; n = *bp++; ndx = 1; off = hashp->BSIZE; } else { save_bufp->flags &= ~BUF_PIN; return (ERROR); } } /* Not found */ switch (action) { case HASH_PUT: case HASH_PUTNEW: if (__addel(hashp, rbufp, key, val)) { save_bufp->flags &= ~BUF_PIN; return (ERROR); } else { save_bufp->flags &= ~BUF_PIN; return (SUCCESS); } case HASH_GET: case HASH_DELETE: default: save_bufp->flags &= ~BUF_PIN; return (ABNORMAL); }found: switch (action) { case HASH_PUTNEW: save_bufp->flags &= ~BUF_PIN; return (ABNORMAL); case HASH_GET: bp = (u_int16_t *)rbufp->page; if (bp[ndx + 1] < REAL_KEY) { if (__big_return(hashp, rbufp, ndx, val, 0)) return (ERROR); } else { val->data = (u_char *)rbufp->page + (int)bp[ndx + 1]; val->size = bp[ndx] - bp[ndx + 1]; } break; case HASH_PUT: if ((__delpair(hashp, rbufp, ndx)) || (__addel(hashp, rbufp, key, val))) { save_bufp->flags &= ~BUF_PIN; return (ERROR); } break; case HASH_DELETE: if (__delpair(hashp, rbufp, ndx)) return (ERROR); break; default: abort(); } save_bufp->flags &= ~BUF_PIN; return (SUCCESS);}static inthash_seq(dbp, key, data, flag) const DB *dbp; DBT *key, *data; u_int32_t flag;{ register u_int32_t bucket; register BUFHEAD *bufp = NULL; HTAB *hashp; u_int16_t *bp, ndx; hashp = (HTAB *)dbp->internal; if (flag && flag != R_FIRST && flag != R_NEXT) { hashp->errnum = errno = EINVAL; return (ERROR); }#ifdef HASH_STATISTICS hash_accesses++;#endif if ((hashp->cbucket < 0) || (flag == R_FIRST)) { hashp->cbucket = 0; hashp->cndx = 1; hashp->cpage = NULL; } for (bp = NULL; !bp || !bp[0]; ) { if (!(bufp = hashp->cpage)) { for (bucket = hashp->cbucket; bucket <= (u_int32_t) hashp->MAX_BUCKET; bucket++, hashp->cndx = 1) { bufp = __get_buf(hashp, bucket, NULL, 0); if (!bufp) return (ERROR); hashp->cpage = bufp; bp = (u_int16_t *)bufp->page; if (bp[0]) break; } hashp->cbucket = bucket; if (hashp->cbucket > hashp->MAX_BUCKET) { hashp->cbucket = -1; return (ABNORMAL); } } else bp = (u_int16_t *)hashp->cpage->page;#ifdef DEBUG assert(bp); assert(bufp);#endif while (bp[hashp->cndx + 1] == OVFLPAGE) { bufp = hashp->cpage = __get_buf(hashp, bp[hashp->cndx], bufp, 0); if (!bufp) return (ERROR); bp = (u_int16_t *)(bufp->page); hashp->cndx = 1; } if (!bp[0]) { hashp->cpage = NULL; ++hashp->cbucket; } } ndx = hashp->cndx; if (bp[ndx + 1] < REAL_KEY) { if (__big_keydata(hashp, bufp, key, data, 1)) return (ERROR); } else { 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);}/********************************* UTILITIES ************************//* * Returns: * 0 ==> OK * -1 ==> Error */extern int__expand_table(hashp) HTAB *hashp;{ u_int32_t old_bucket, new_bucket; int dirsize, new_segnum, spare_ndx;#ifdef HASH_STATISTICS hash_expansions++;#endif new_bucket = ++hashp->MAX_BUCKET; old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK); new_segnum = new_bucket >> hashp->SSHIFT; /* Check if we need a new segment */ if (new_segnum >= hashp->nsegs) { /* Check if we need to expand directory */ if (new_segnum >= hashp->DSIZE) { /* Reallocate directory */ dirsize = hashp->DSIZE * sizeof(SEGMENT *); if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1)) return (-1); hashp->DSIZE = dirsize << 1; } if ((hashp->dir[new_segnum] = (SEGMENT)calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL) return (-1); hashp->exsegs++; hashp->nsegs++; } /* * If the split point is increasing (MAX_BUCKET's log base 2 * * increases), we need to copy the current contents of the spare * split bucket to the next bucket. */ spare_ndx = __hash_log2(hashp->MAX_BUCKET + 1); if (spare_ndx > hashp->OVFL_POINT) { hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT]; hashp->OVFL_POINT = spare_ndx; } if (new_bucket > (u_int32_t) hashp->HIGH_MASK) { /* Starting a new doubling */ hashp->LOW_MASK = hashp->HIGH_MASK; hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK; } /* Relocate records to the new bucket */ return (__split_page(hashp, old_bucket, new_bucket));}/* * If realloc guarantees that the pointer is not destroyed if the realloc * fails, then this routine can go away. */static void *hash_realloc(p_ptr, oldsize, newsize) SEGMENT **p_ptr; int oldsize, newsize;{ register void *p; if ((p = malloc(newsize))) { memmove(p, *p_ptr, oldsize); memset((char *)p + oldsize, 0, newsize - oldsize); free(*p_ptr); *p_ptr = p; } return (p);}extern u_int32_t__call_hash(hashp, k, len) HTAB *hashp; char *k; int len;{ int n, bucket; n = hashp->hash(k, len); bucket = n & hashp->HIGH_MASK; if (bucket > hashp->MAX_BUCKET) bucket = bucket & hashp->LOW_MASK; return (bucket);}/* * Allocate segment table. On error, destroy the table and set errno. * * Returns 0 on success */static intalloc_segs(hashp, nsegs) HTAB *hashp; int nsegs;{ register int i; register SEGMENT store; int save_errno; if ((hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) { save_errno = errno; (void)hdestroy(hashp); errno = save_errno; return (-1); } /* Allocate segments */ 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++) hashp->dir[i] = &store[i << hashp->SSHIFT]; return (0);}#if BYTE_ORDER == LITTLE_ENDIAN/* * Hashp->hdr needs to be byteswapped. */static voidswap_header_copy(srcp, destp) HASHHDR *srcp, *destp;{ int i; P_32_COPY(srcp->magic, destp->magic); P_32_COPY(srcp->version, destp->version); P_32_COPY(srcp->lorder, destp->lorder); P_32_COPY(srcp->bsize, destp->bsize); P_32_COPY(srcp->bshift, destp->bshift); P_32_COPY(srcp->dsize, destp->dsize); P_32_COPY(srcp->ssize, destp->ssize); P_32_COPY(srcp->sshift, destp->sshift); P_32_COPY(srcp->ovfl_point, destp->ovfl_point); P_32_COPY(srcp->last_freed, destp->last_freed); P_32_COPY(srcp->max_bucket, destp->max_bucket); P_32_COPY(srcp->high_mask, destp->high_mask); P_32_COPY(srcp->low_mask, destp->low_mask); P_32_COPY(srcp->ffactor, destp->ffactor); P_32_COPY(srcp->nkeys, destp->nkeys); P_32_COPY(srcp->hdrpages, destp->hdrpages); P_32_COPY(srcp->h_charkey, destp->h_charkey); for (i = 0; i < NCACHED; i++) { P_32_COPY(srcp->spares[i], destp->spares[i]); P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]); }}static voidswap_header(hashp) HTAB *hashp;{ HASHHDR *hdrp; int i; hdrp = &hashp->hdr; M_32_SWAP(hdrp->magic); M_32_SWAP(hdrp->version); M_32_SWAP(hdrp->lorder); M_32_SWAP(hdrp->bsize); M_32_SWAP(hdrp->bshift); M_32_SWAP(hdrp->dsize); M_32_SWAP(hdrp->ssize); M_32_SWAP(hdrp->sshift); M_32_SWAP(hdrp->ovfl_point); M_32_SWAP(hdrp->last_freed); M_32_SWAP(hdrp->max_bucket); M_32_SWAP(hdrp->high_mask); M_32_SWAP(hdrp->low_mask); M_32_SWAP(hdrp->ffactor); M_32_SWAP(hdrp->nkeys); M_32_SWAP(hdrp->hdrpages); M_32_SWAP(hdrp->h_charkey); for (i = 0; i < NCACHED; i++) { M_32_SWAP(hdrp->spares[i]); M_16_SWAP(hdrp->bitmaps[i]); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -