📄 tchdb.c
字号:
1399, 1531, 1663, 1789, 1913, 2039, 2297, 2557, 2803, 3067, 3323, 3583, 3833, 4093, 4603, 5119, 5623, 6143, 6653, 7159, 7673, 8191, 9209, 10223, 11261, 12281, 13309, 14327, 15359, 16381, 18427, 20479, 22511, 24571, 26597, 28669, 30713, 32749, 36857, 40949, 45053, 49139, 53239, 57331, 61417, 65521, 73727, 81919, 90107, 98299, 106487, 114679, 122869, 131071, 147451, 163819, 180221, 196597, 212987, 229373, 245759, 262139, 294911, 327673, 360439, 393209, 425977, 458747, 491503, 524287, 589811, 655357, 720887, 786431, 851957, 917503, 982981, 1048573, 1179641, 1310719, 1441771, 1572853, 1703903, 1835003, 1966079, 2097143, 2359267, 2621431, 2883577, 3145721, 3407857, 3670013, 3932153, 4194301, 4718579, 5242877, 5767129, 6291449, 6815741, 7340009, 7864301, 8388593, 9437179, 10485751, 11534329, 12582893, 13631477, 14680063, 15728611, 16777213, 18874367, 20971507, 23068667, 25165813, 27262931, 29360087, 31457269, 33554393, 37748717, 41943023, 46137319, 50331599, 54525917, 58720253, 62914549, 67108859, 75497467, 83886053, 92274671, 100663291, 109051903, 117440509, 125829103, 134217689, 150994939, 167772107, 184549373, 201326557, 218103799, 234881011, 251658227, 268435399, 301989881, 335544301, 369098707, 402653171, 436207613, 469762043, 503316469, 536870909, 603979769, 671088637, 738197503, 805306357, 872415211, 939524087, 1006632947, 1073741789, 1207959503, 1342177237, 1476394991, 1610612711, 1744830457, 1879048183, 2013265907, 2576980349, 3092376431, 3710851741, 4718021527, 6133428047, 7973456459, 10365493393, 13475141413, 17517683831, 22772988923, 29604885677, 38486351381, 50032256819, 65041933867, 84554514043, 109920868241, 153889215497, 0 }; int i; for(i = 0; primes[i] > 0; i++){ if(num <= primes[i]) return primes[i]; } return primes[i-1];}/* Seek and read data from a file. `hdb' specifies the hash database object. `off' specifies the offset of the region to seek. `buf' specifies the buffer to store into. `size' specifies the size of the buffer. The return value is true if successful, else, it is false. */static bool tchdbseekwrite(TCHDB *hdb, off_t off, const void *buf, size_t size){ assert(hdb && off >= 0 && buf && size >= 0); if(hdb->tran && !tchdbwalwrite(hdb, off, size)) return false; off_t end = off + size; if(end <= hdb->xmsiz){ if(end >= hdb->fsiz && end >= hdb->xfsiz){ uint64_t xfsiz = end + HDBXFSIZINC; if(ftruncate(hdb->fd, xfsiz) == -1){ tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); return false; } hdb->xfsiz = xfsiz; } memcpy(hdb->map + off, buf, size); return true; } if(!TCUBCACHE && off < hdb->xmsiz){ int head = hdb->xmsiz - off; memcpy(hdb->map + off, buf, head); off += head; buf = (char *)buf + head; size -= head; } while(true){ int wb = pwrite(hdb->fd, buf, size, off); if(wb >= size){ return true; } else if(wb > 0){ buf = (char *)buf + wb; size -= wb; off += wb; } else if(wb == -1){ if(errno != EINTR){ tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); return false; } } else { if(size > 0){ tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); return false; } } } return true;}/* Seek and read data from a file. `hdb' specifies the hash database object. `off' specifies the offset of the region to seek. `buf' specifies the buffer to store into. `size' specifies the size of the buffer. The return value is true if successful, else, it is false. */static bool tchdbseekread(TCHDB *hdb, off_t off, void *buf, size_t size){ assert(hdb && off >= 0 && buf && size >= 0); if(off + size <= hdb->xmsiz){ memcpy(buf, hdb->map + off, size); return true; } if(!TCUBCACHE && off < hdb->xmsiz){ int head = hdb->xmsiz - off; memcpy(buf, hdb->map + off, head); off += head; buf = (char *)buf + head; size -= head; } while(true){ int rb = pread(hdb->fd, buf, size, off); if(rb >= size){ break; } else if(rb > 0){ buf = (char *)buf + rb; size -= rb; off += rb; } else if(rb == -1){ if(errno != EINTR){ tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); return false; } } else { if(size > 0){ tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); return false; } } } return true;}/* Try to seek and read data from a file. `hdb' specifies the hash database object. `off' specifies the offset of the region to seek. `buf' specifies the buffer to store into. `size' specifies the size of the buffer. The return value is true if successful, else, it is false. */static bool tchdbseekreadtry(TCHDB *hdb, off_t off, void *buf, size_t size){ assert(hdb && off >= 0 && buf && size >= 0); off_t end = off + size; if(end > hdb->fsiz) return false; if(end <= hdb->xmsiz){ memcpy(buf, hdb->map + off, size); return true; } if(!TCUBCACHE && off < hdb->xmsiz){ int head = hdb->xmsiz - off; memcpy(buf, hdb->map + off, head); off += head; buf = (char *)buf + head; size -= head; } int rb = pread(hdb->fd, buf, size, off); if(rb == size) return true; if(rb == -1) tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); return false;}/* Serialize meta data into a buffer. `hdb' specifies the hash database object. `hbuf' specifies the buffer. */static void tchdbdumpmeta(TCHDB *hdb, char *hbuf){ memset(hbuf, 0, HDBHEADSIZ); sprintf(hbuf, "%s\n%s:%d\n", HDBMAGICDATA, _TC_FORMATVER, _TC_LIBVER); memcpy(hbuf + HDBTYPEOFF, &(hdb->type), sizeof(hdb->type)); memcpy(hbuf + HDBFLAGSOFF, &(hdb->flags), sizeof(hdb->flags)); memcpy(hbuf + HDBAPOWOFF, &(hdb->apow), sizeof(hdb->apow)); memcpy(hbuf + HDBFPOWOFF, &(hdb->fpow), sizeof(hdb->fpow)); memcpy(hbuf + HDBOPTSOFF, &(hdb->opts), sizeof(hdb->opts)); uint64_t llnum; llnum = hdb->bnum; llnum = TCHTOILL(llnum); memcpy(hbuf + HDBBNUMOFF, &llnum, sizeof(llnum)); llnum = hdb->rnum; llnum = TCHTOILL(llnum); memcpy(hbuf + HDBRNUMOFF, &llnum, sizeof(llnum)); llnum = hdb->fsiz; llnum = TCHTOILL(llnum); memcpy(hbuf + HDBFSIZOFF, &llnum, sizeof(llnum)); llnum = hdb->frec; llnum = TCHTOILL(llnum); memcpy(hbuf + HDBFRECOFF, &llnum, sizeof(llnum));}/* Deserialize meta data from a buffer. `hdb' specifies the hash database object. `hbuf' specifies the buffer. */static void tchdbloadmeta(TCHDB *hdb, const char *hbuf){ memcpy(&(hdb->type), hbuf + HDBTYPEOFF, sizeof(hdb->type)); memcpy(&(hdb->flags), hbuf + HDBFLAGSOFF, sizeof(hdb->flags)); memcpy(&(hdb->apow), hbuf + HDBAPOWOFF, sizeof(hdb->apow)); memcpy(&(hdb->fpow), hbuf + HDBFPOWOFF, sizeof(hdb->fpow)); memcpy(&(hdb->opts), hbuf + HDBOPTSOFF, sizeof(hdb->opts)); uint64_t llnum; memcpy(&llnum, hbuf + HDBBNUMOFF, sizeof(llnum)); hdb->bnum = TCITOHLL(llnum); memcpy(&llnum, hbuf + HDBRNUMOFF, sizeof(llnum)); hdb->rnum = TCITOHLL(llnum); memcpy(&llnum, hbuf + HDBFSIZOFF, sizeof(llnum)); hdb->fsiz = TCITOHLL(llnum); memcpy(&llnum, hbuf + HDBFRECOFF, sizeof(llnum)); hdb->frec = TCITOHLL(llnum);}/* Clear all members. `hdb' specifies the hash database object. */static void tchdbclear(TCHDB *hdb){ assert(hdb); hdb->mmtx = NULL; hdb->rmtxs = NULL; hdb->dmtx = NULL; hdb->tmtx = NULL; hdb->wmtx = NULL; hdb->eckey = NULL; hdb->type = TCDBTHASH; hdb->flags = 0; hdb->bnum = HDBDEFBNUM; hdb->apow = HDBDEFAPOW; hdb->fpow = HDBDEFFPOW; hdb->opts = 0; hdb->path = NULL; hdb->fd = -1; hdb->omode = 0; hdb->rnum = 0; hdb->fsiz = 0; hdb->frec = 0; hdb->iter = 0; hdb->map = NULL; hdb->msiz = 0; hdb->xmsiz = HDBDEFXMSIZ; hdb->xfsiz = 0; hdb->ba32 = NULL; hdb->ba64 = NULL; hdb->align = 0; hdb->runit = 0; hdb->zmode = false; hdb->fbpmax = 0; hdb->fbpool = NULL; hdb->fbpnum = 0; hdb->fbpmis = 0; hdb->async = false; hdb->drpool = NULL; hdb->drpdef = NULL; hdb->drpoff = 0; hdb->recc = NULL; hdb->rcnum = 0; hdb->enc = NULL; hdb->encop = NULL; hdb->dec = NULL; hdb->decop = NULL; hdb->ecode = TCESUCCESS; hdb->fatal = false; hdb->inode = 0; hdb->mtime = 0; hdb->tran = false; hdb->walfd = -1; hdb->walend = 0; hdb->dbgfd = -1; hdb->cnt_writerec = -1; hdb->cnt_reuserec = -1; hdb->cnt_moverec = -1; hdb->cnt_readrec = -1; hdb->cnt_searchfbp = -1; hdb->cnt_insertfbp = -1; hdb->cnt_splicefbp = -1; hdb->cnt_dividefbp = -1; hdb->cnt_mergefbp = -1; hdb->cnt_reducefbp = -1; hdb->cnt_appenddrp = -1; hdb->cnt_deferdrp = -1; hdb->cnt_flushdrp = -1; hdb->cnt_adjrecc = -1; TCDODEBUG(hdb->cnt_writerec = 0); TCDODEBUG(hdb->cnt_reuserec = 0); TCDODEBUG(hdb->cnt_moverec = 0); TCDODEBUG(hdb->cnt_readrec = 0); TCDODEBUG(hdb->cnt_searchfbp = 0); TCDODEBUG(hdb->cnt_insertfbp = 0); TCDODEBUG(hdb->cnt_splicefbp = 0); TCDODEBUG(hdb->cnt_dividefbp = 0); TCDODEBUG(hdb->cnt_mergefbp = 0); TCDODEBUG(hdb->cnt_reducefbp = 0); TCDODEBUG(hdb->cnt_appenddrp = 0); TCDODEBUG(hdb->cnt_deferdrp = 0); TCDODEBUG(hdb->cnt_flushdrp = 0); TCDODEBUG(hdb->cnt_adjrecc = 0);}/* Get the padding size to record alignment. `hdb' specifies the hash database object. `off' specifies the current offset. The return value is the padding size. */static int32_t tchdbpadsize(TCHDB *hdb, uint64_t off){ assert(hdb); int32_t diff = off & (hdb->align - 1); return (diff > 0) ? hdb->align - diff : 0;}/* Set the open flag. `hdb' specifies the hash database object. `flag' specifies the flag value. `sign' specifies the sign. */static void tchdbsetflag(TCHDB *hdb, int flag, bool sign){ assert(hdb); char *fp = (char *)hdb->map + HDBFLAGSOFF; if(sign){ *fp |= (uint8_t)flag; } else { *fp &= ~(uint8_t)flag; } hdb->flags = *fp;}/* Get the bucket index of a record. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. `hp' specifies the pointer to the variable into which the second hash value is assigned. The return value is the bucket index. */static uint64_t tchdbbidx(TCHDB *hdb, const char *kbuf, int ksiz, uint8_t *hp){ assert(hdb && kbuf && ksiz >= 0 && hp); uint64_t idx = 19780211; uint32_t hash = 751; const char *rp = kbuf + ksiz; while(ksiz--){ idx = idx * 37 + *(uint8_t *)kbuf++; hash = (hash * 31) ^ *(uint8_t *)--rp; } *hp = hash; return idx % hdb->bnum;}/* Get the offset of the record of a bucket element. `hdb' specifies the hash database object. `bidx' specifies the index of the bucket. The return value is the offset of the record. */static off_t tchdbgetbucket(TCHDB *hdb, uint64_t bidx){ assert(hdb && bidx >= 0); if(hdb->ba64){ uint64_t llnum = hdb->ba64[bidx]; return TCITOHLL(llnum) << hdb->apow; } uint32_t lnum = hdb->ba32[bidx]; return (off_t)TCITOHL(lnum) << hdb->apow;}/* Get the offset of the record of a bucket element. `hdb' specifies the hash database object. `bidx' specifies the index of the record. `off' specifies the offset of the record. */static void tchdbsetbucket(TCHDB *hdb, uint64_t bidx, uint64_t off){ assert(hdb && bidx >= 0); if(hdb->ba64){ uint64_t llnum = off >> hdb->apow; if(hdb->tran) tchdbwalwrite(hdb, HDBHEADSIZ + bidx * sizeof(llnum), sizeof(llnum)); hdb->ba64[bidx] = TCHTOILL(llnum); } else { uint32_t lnum = off >> hdb->apow; if(hdb->tran) tchdbwalwrite(hdb, HDBHEADSIZ + bidx * sizeof(lnum), sizeof(lnum)); hdb->ba32[bidx] = TCHTOIL(lnum); }}/* Load the free block pool from the file. The return value is true if successful, else, it is false. */static bool tchdbsavefbp(TCHDB *hdb){ assert(hdb); if(hdb->fbpnum > hdb->fbpmax){ tchdbfbpmerge(hdb); } else if(hdb->fbpnum > 1){ tcfbpsortbyoff(hdb->fbpool, hdb->fbpnum); } int bsiz = hdb->frec - hdb->msiz; char *buf; TCMALLOC(buf, bsiz); char *wp = buf; HDBFB *cur = hdb->fbpool; HDBFB *end = cur + hdb->fbpnum; uint64_t base = 0; bsiz -= sizeof(HDBFB) + sizeof(uint8_t) + sizeof(uint8_t); while(cur < end && bsiz > 0){ uint64_t noff = cur->off >> hdb->apow; int step; uint64_t llnum = noff - base; TCSETVNUMBUF64(step, wp, llnum); wp += step; bsiz -= step; uint32_t lnum = cur->rsiz >> hdb->apow; TCSETVNUMBUF(step, wp, lnum); wp += step; bsiz -= step; base = noff; cur++; } *(wp++) = '\0'; *(wp++) = '\0'; if(!tchdbseekwrite(hdb, hdb->msiz, buf, wp - buf)){ TCFREE(buf); return false; } TCFREE(buf); return true;}/* Save the free block pool into the file. The ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -