📄 sdbm.c
字号:
(void) apr_sdbm_unlock(db); return status;}/* * makroom - make room by splitting the overfull page * this routine will attempt to make room for SPLTMAX times before * giving up. */static apr_status_t makroom(apr_sdbm_t *db, long hash, int need){ long newp; char twin[PBLKSIZ]; char *pag = db->pagbuf; char *new = twin; register int smax = SPLTMAX; apr_status_t status; do { /* * split the current page */ (void) splpage(pag, new, db->hmask + 1); /* * address of the new page */ newp = (hash & db->hmask) | (db->hmask + 1); /* * write delay, read avoidence/cache shuffle: * select the page for incoming pair: if key is to go to the new page, * write out the previous one, and copy the new one over, thus making * it the current page. If not, simply write the new page, and we are * still looking at the page of interest. current page is not updated * here, as sdbm_store will do so, after it inserts the incoming pair. */ if (hash & (db->hmask + 1)) { if ((status = write_page(db, db->pagbuf, db->pagbno)) != APR_SUCCESS) return status; db->pagbno = newp; (void) memcpy(pag, new, PBLKSIZ); } else { if ((status = write_page(db, new, newp)) != APR_SUCCESS) return status; } if ((status = setdbit(db, db->curbit)) != APR_SUCCESS) return status; /* * see if we have enough room now */ if (fitpair(pag, need)) return APR_SUCCESS; /* * try again... update curbit and hmask as getpage would have * done. because of our update of the current page, we do not * need to read in anything. BUT we have to write the current * [deferred] page out, as the window of failure is too great. */ db->curbit = 2 * db->curbit + ((hash & (db->hmask + 1)) ? 2 : 1); db->hmask |= db->hmask + 1; if ((status = write_page(db, db->pagbuf, db->pagbno)) != APR_SUCCESS) return status; } while (--smax); /* * if we are here, this is real bad news. After SPLTMAX splits, * we still cannot fit the key. say goodnight. */#if 0 (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);#endif /* ### ENOSPC not really appropriate but better than nothing */ return APR_ENOSPC;}/* Reads 'len' bytes from file 'f' at offset 'off' into buf. * 'off' is given relative to the start of the file. * If EOF is returned while reading, this is taken as success. */static apr_status_t read_from(apr_file_t *f, void *buf, apr_off_t off, apr_size_t len){ apr_status_t status; if ((status = apr_file_seek(f, APR_SET, &off)) != APR_SUCCESS || ((status = apr_file_read_full(f, buf, len, NULL)) != APR_SUCCESS)) { /* if EOF is reached, pretend we read all zero's */ if (status == APR_EOF) { memset(buf, 0, len); status = APR_SUCCESS; } } return status;}/* * the following two routines will break if * deletions aren't taken into account. (ndbm bug) */APU_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, apr_sdbm_datum_t *key){ apr_status_t status; if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS) return status; /* * start at page 0 */ if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(0), PBLKSIZ)) == APR_SUCCESS) { db->pagbno = 0; db->blkptr = 0; db->keyptr = 0; status = getnext(key, db); } (void) apr_sdbm_unlock(db); return status;}APU_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, apr_sdbm_datum_t *key){ apr_status_t status; if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS) return status; status = getnext(key, db); (void) apr_sdbm_unlock(db); return status;}/* * all important binary tree traversal */static apr_status_t getpage(apr_sdbm_t *db, long hash){ register int hbit; register long dbit; register long pagb; apr_status_t status; dbit = 0; hbit = 0; while (dbit < db->maxbno && getdbit(db, dbit)) dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1); debug(("dbit: %d...", dbit)); db->curbit = dbit; db->hmask = masks[hbit]; pagb = hash & db->hmask; /* * see if the block we need is already in memory. * note: this lookaside cache has about 10% hit rate. */ if (pagb != db->pagbno) { /* * note: here, we assume a "hole" is read as 0s. * if not, must zero pagbuf first. * ### joe: this assumption was surely never correct? but * ### we make it so in read_from anyway. */ if ((status = read_from(db->pagf, db->pagbuf, OFF_PAG(pagb), PBLKSIZ)) != APR_SUCCESS) return status; if (!chkpage(db->pagbuf)) return APR_ENOSPC; /* ### better error? */ db->pagbno = pagb; debug(("pag read: %d\n", pagb)); } return APR_SUCCESS;}static int getdbit(apr_sdbm_t *db, long dbit){ register long c; register long dirb; c = dbit / BYTESIZ; dirb = c / DBLKSIZ; if (dirb != db->dirbno) { if (read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ) != APR_SUCCESS) return 0; db->dirbno = dirb; debug(("dir read: %d\n", dirb)); } return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ);}static apr_status_t setdbit(apr_sdbm_t *db, long dbit){ register long c; register long dirb; apr_status_t status; apr_off_t off; c = dbit / BYTESIZ; dirb = c / DBLKSIZ; if (dirb != db->dirbno) { if ((status = read_from(db->dirf, db->dirbuf, OFF_DIR(dirb), DBLKSIZ)) != APR_SUCCESS) return status; db->dirbno = dirb; debug(("dir read: %d\n", dirb)); } db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); if (dbit >= db->maxbno) db->maxbno += DBLKSIZ * BYTESIZ; off = OFF_DIR(dirb); if ((status = apr_file_seek(db->dirf, APR_SET, &off)) == APR_SUCCESS) status = apr_file_write_full(db->dirf, db->dirbuf, DBLKSIZ, NULL); return status;}/** getnext - get the next key in the page, and if done with* the page, try the next page in sequence*/static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db){ apr_status_t status; for (;;) { db->keyptr++; *key = getnkey(db->pagbuf, db->keyptr); if (key->dptr != NULL) return APR_SUCCESS; /* * we either run out, or there is nothing on this page.. * try the next one... If we lost our position on the * file, we will have to seek. */ db->keyptr = 0; if (db->pagbno != db->blkptr++) { apr_off_t off = OFF_PAG(db->blkptr); if ((status = apr_file_seek(db->pagf, APR_SET, &off) != APR_SUCCESS)) return status; } db->pagbno = db->blkptr; /* ### EOF acceptable here too? */ if ((status = apr_file_read_full(db->pagf, db->pagbuf, PBLKSIZ, NULL)) != APR_SUCCESS) return status; if (!chkpage(db->pagbuf)) return APR_EGENERAL; /* ### need better error */ } /* NOTREACHED */}APU_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db){ /* ### Should we return true if the first lock is a share lock, * to reflect that apr_sdbm_store and apr_sdbm_delete will fail? */ return (db->flags & SDBM_RDONLY) != 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -