📄 tctdb.c
字号:
} tclistdel(paths); } TCLIST *paths = tcglobpat(tpath); int pnum = TCLISTNUM(paths); TCMALLOC(tdb->idxs, sizeof(tdb->idxs[0]) * pnum + 1); TDBIDX *idxs = tdb->idxs; int inum = 0; for(int i = 0; i < pnum; i++){ const char *ipath = TCLISTVALPTR(paths, i); if(!tcstrfwm(ipath, path)) continue; const char *rp = ipath + strlen(path); if(*rp != MYEXTCHR) continue; rp++; if(!tcstrfwm(rp, TDBIDXSUFFIX)) continue; rp += strlen(TDBIDXSUFFIX); if(*rp != MYEXTCHR) continue; rp++; char *stem = tcstrdup(rp); char *ep = strrchr(stem, MYEXTCHR); if(!ep) continue; *(ep++) = '\0'; int nsiz; char *name = tcurldecode(stem, &nsiz); if(!strcmp(ep, "lex") || !strcmp(ep, "dec")){ TCBDB *bdb = tcbdbnew(); if(tdb->mmtx) tcbdbsetmutex(bdb); if(enc && dec) tcbdbsetcodecfunc(bdb, enc, encop, dec, decop); tcbdbsetcache(bdb, tdb->lcnum, tdb->ncnum); tcbdbsetlsmax(bdb, TDBIDXLSMAX); if(tcbdbopen(bdb, ipath, bomode)){ idxs[inum].name = tcstrdup(name); idxs[inum].type = TDBITLEXICAL; if(!strcmp(ep, "dec")) idxs[inum].type = TDBITDECIMAL; idxs[inum].db = bdb; inum++; } else { tcbdbdel(bdb); } } TCFREE(name); TCFREE(stem); } tclistdel(paths); TCFREE(tpath); tdb->inum = inum; tdb->open = true; uint8_t hopts = tchdbopts(tdb->hdb); uint8_t opts = 0; if(hopts & HDBTLARGE) opts |= TDBTLARGE; if(hopts & HDBTDEFLATE) opts |= TDBTDEFLATE; if(hopts & HDBTBZIP) opts |= TDBTBZIP; if(hopts & HDBTTCBS) opts |= TDBTTCBS; if(hopts & HDBTEXCODEC) opts |= TDBTEXCODEC; tdb->opts = opts; tdb->tran = false; return true;}/* Close a table database object. `tdb' specifies the table database object. If successful, the return value is true, else, it is false. */static bool tctdbcloseimpl(TCTDB *tdb){ assert(tdb); bool err = false; if(tdb->tran && !tctdbtranabortimpl(tdb)) err = true; TDBIDX *idxs = tdb->idxs; int inum = tdb->inum; for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(!tcbdbclose(idx->db)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } tcbdbdel(idx->db); break; } TCFREE(idx->name); } TCFREE(idxs); if(!tchdbclose(tdb->hdb)) err = true; tdb->open = false; return !err;}/* Store a record into a table database object. `tdb' specifies the table database object. `pkbuf' specifies the pointer to the region of the primary key. `pksiz' specifies the size of the region of the primary key. `cols' specifies a map object containing columns. `dmode' specifies behavior when the key overlaps. If successful, the return value is true, else, it is false. */static bool tctdbputimpl(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols, int dmode){ assert(tdb && pkbuf && pksiz >= 0 && cols); bool err = false; int osiz; char *obuf = tchdbget(tdb->hdb, pkbuf, pksiz, &osiz); if(obuf){ if(dmode == TDBPDKEEP){ tctdbsetecode(tdb, TCEKEEP, __FILE__, __LINE__, __func__); TCFREE(obuf); return false; } TCMAP *ocols = tcmapload(obuf, osiz); if(dmode == TDBPDCAT){ TCMAP *ncols = tcmapnew2(tcmaprnum(cols) + 1); tcmapiterinit(cols); const char *kbuf; int ksiz; while((kbuf = tcmapiternext(cols, &ksiz)) != NULL){ int vsiz; const char *vbuf = tcmapiterval(kbuf, &vsiz); if(tcmapputkeep(ocols, kbuf, ksiz, vbuf, vsiz)) tcmapput(ncols, kbuf, ksiz, vbuf, vsiz); } if(!tctdbidxput(tdb, pkbuf, pksiz, ncols)) err = true; tcmapdel(ncols); int csiz; char *cbuf = tcmapdump(ocols, &csiz); if(!tchdbput(tdb->hdb, pkbuf, pksiz, cbuf, csiz)) err = true; TCFREE(cbuf); } else { TCMAP *ncols = tcmapnew2(tcmaprnum(cols) + 1); tcmapiterinit(cols); const char *kbuf; int ksiz; while((kbuf = tcmapiternext(cols, &ksiz)) != NULL){ int vsiz; const char *vbuf = tcmapiterval(kbuf, &vsiz); int osiz; const char *obuf = tcmapget(ocols, kbuf, ksiz, &osiz); if(obuf && osiz == vsiz && !memcmp(obuf, vbuf, osiz)){ tcmapout(ocols, kbuf, ksiz); } else { tcmapput(ncols, kbuf, ksiz, vbuf, vsiz); } } if(!tctdbidxout(tdb, pkbuf, pksiz, ocols)) err = true; if(!tctdbidxput(tdb, pkbuf, pksiz, ncols)) err = true; tcmapdel(ncols); int csiz; char *cbuf = tcmapdump(cols, &csiz); if(!tchdbput(tdb->hdb, pkbuf, pksiz, cbuf, csiz)) err = true; TCFREE(cbuf); } tcmapdel(ocols); TCFREE(obuf); } else { if(!tctdbidxput(tdb, pkbuf, pksiz, cols)) err = true; int csiz; char *cbuf = tcmapdump(cols, &csiz); if(!tchdbput(tdb->hdb, pkbuf, pksiz, cbuf, csiz)) err = true; TCFREE(cbuf); } return !err;}/* Remove a record of a table database object. `tdb' specifies the table database object. `pkbuf' specifies the pointer to the region of the primary key. `pksiz' specifies the size of the region of the primary key. If successful, the return value is true, else, it is false. */static bool tctdboutimpl(TCTDB *tdb, const char *pkbuf, int pksiz){ assert(tdb && pkbuf && pksiz >= 0); int csiz; char *cbuf = tchdbget(tdb->hdb, pkbuf, pksiz, &csiz); if(!cbuf) return false; bool err = false; TCMAP *cols = tcmapload(cbuf, csiz); if(!tctdbidxout(tdb, pkbuf, pksiz, cols)) err = true; if(!tchdbout(tdb->hdb, pkbuf, pksiz)) err = true; tcmapdel(cols); TCFREE(cbuf); return !err;}/* Retrieve a record in a table database object. `tdb' specifies the table database object. `pkbuf' specifies the pointer to the region of the primary key. `pksiz' specifies the size of the region of the primary key. If successful, the return value is a map object of the columns of the corresponding record. */static TCMAP *tctdbgetimpl(TCTDB *tdb, const void *pkbuf, int pksiz){ assert(tdb && pkbuf && pksiz >= 0); int csiz; char *cbuf = tchdbget(tdb->hdb, pkbuf, pksiz, &csiz); if(!cbuf) return false; TCMAP *cols = tcmapload(cbuf, csiz); TCFREE(cbuf); return cols;}/* Add a real number to a column of a record in a table database object. `tdb' specifies the table database object. `kbuf' specifies the pointer to the region of the primary key. `ksiz' specifies the size of the region of the primary key. `num' specifies the additional value. If successful, the return value is the summation value, else, it is Not-a-Number. */static double tctdbaddnumber(TCTDB *tdb, const void *pkbuf, int pksiz, double num){ assert(tdb && pkbuf && pksiz >= 0); int csiz; char *cbuf = tchdbget(tdb->hdb, pkbuf, pksiz, &csiz); TCMAP *cols = cbuf ? tcmapload(cbuf, csiz) : tcmapnew2(1); if(cbuf){ const char *vbuf = tcmapget2(cols, TDBNUMCNTCOL); if(vbuf) num += tcatof(vbuf); TCFREE(cbuf); } char numbuf[TDBCNTBUFSIZ]; int len = snprintf(numbuf, TDBCNTBUFSIZ - 1, "%f", num); if(len > TDBCNTBUFSIZ - 1){ tctdbsetecode(tdb, TCEMISC, __FILE__, __LINE__, __func__); num = nan(""); } else { while(--len > 0){ if(numbuf[len] != '0') break; numbuf[len] = '\0'; } if(numbuf[len] == '.') numbuf[len] = '\0'; tcmapput2(cols, TDBNUMCNTCOL, numbuf); if(!tctdbputimpl(tdb, pkbuf, pksiz, cols, TDBPDOVER)) num = nan(""); } tcmapdel(cols); return num;}/* Optimize the file of a table database object. `tdb' specifies the table database object. `bnum' specifies the number of elements of the bucket array. `apow' specifies the size of record alignment by power of 2. `fpow' specifies the maximum number of elements of the free block pool by power of 2. `opts' specifies options by bitwise-or. If successful, the return value is true, else, it is false. */static bool tctdboptimizeimpl(TCTDB *tdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ assert(tdb); bool err = false; TCHDB *hdb = tdb->hdb; TDBIDX *idxs = tdb->idxs; int inum = tdb->inum; for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(!tcbdbvanish(idx->db)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } break; } } const char *path = tchdbpath(tdb->hdb); char *tpath = tcsprintf("%s%ctmp%c%llu", path, MYEXTCHR, MYEXTCHR, tchdbinode(tdb->hdb)); TCHDB *thdb = tchdbnew(); tchdbsettype(thdb, TCDBTTABLE); TCCODEC enc, dec; void *encop, *decop; tchdbcodecfunc(hdb, &enc, &encop, &dec, &decop); if(enc && dec) tchdbsetcodecfunc(thdb, enc, encop, dec, decop); if(bnum < 1) bnum = tchdbrnum(hdb) * 2 + 1; if(apow < 0) apow = tclog2l(tchdbalign(hdb)); if(fpow < 0) fpow = tclog2l(tchdbfbpmax(hdb)); if(opts == UINT8_MAX) opts = tdb->opts; uint8_t hopts = 0; if(opts & TDBTLARGE) hopts |= HDBTLARGE; if(opts & TDBTDEFLATE) hopts |= HDBTDEFLATE; if(opts & TDBTBZIP) hopts |= HDBTBZIP; if(opts & TDBTTCBS) hopts |= HDBTTCBS; if(opts & TDBTEXCODEC) hopts |= HDBTEXCODEC; tchdbtune(thdb, bnum, apow, fpow, hopts); if(tchdbopen(thdb, tpath, HDBOWRITER | HDBOCREAT | HDBOTRUNC)){ memcpy(tchdbopaque(thdb), tchdbopaque(hdb), TDBOPAQUESIZ + TDBLEFTOPQSIZ); if(!tchdbiterinit(hdb)) err = true; TCXSTR *kxstr = tcxstrnew(); TCXSTR *vxstr = tcxstrnew(); while(tchdbiternext3(hdb, kxstr, vxstr)){ TCMAP *cols = tcmapload(TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr)); if(!tctdbidxput(tdb, TCXSTRPTR(kxstr), TCXSTRSIZE(kxstr), cols)) err = true; tcmapdel(cols); if(!tchdbput(thdb, TCXSTRPTR(kxstr), TCXSTRSIZE(kxstr), TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr))){ tctdbsetecode(tdb, tchdbecode(thdb), __FILE__, __LINE__, __func__); err = true; } } tcxstrdel(vxstr); tcxstrdel(kxstr); if(!tchdbclose(thdb)){ tctdbsetecode(tdb, tchdbecode(thdb), __FILE__, __LINE__, __func__); err = true; } if(!err){ if(unlink(path) == -1){ tctdbsetecode(tdb, TCEUNLINK, __FILE__, __LINE__, __func__); err = true; } if(rename(tpath, path) == -1){ tctdbsetecode(tdb, TCERENAME, __FILE__, __LINE__, __func__); err = true; } char *npath = tcstrdup(path); int omode = (tchdbomode(hdb) & ~HDBOCREAT) & ~HDBOTRUNC; if(!tchdbclose(hdb)) err = true; if(!tchdbopen(hdb, npath, omode)) err = true; TCFREE(npath); } } else { tctdbsetecode(tdb, tchdbecode(thdb), __FILE__, __LINE__, __func__); err = true; } tchdbdel(thdb); TCFREE(tpath); for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(!tcbdboptimize(idx->db, -1, -1, -1, -1, -1, UINT8_MAX)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } break; } } return !err;}/* Remove all records of a table database object. `tdb' specifies the table database object. If successful, the return value is true, else, it is false. */static bool tctdbvanishimpl(TCTDB *tdb){ assert(tdb); bool err = false; if(!tchdbvanish(tdb->hdb)) err = true; TDBIDX *idxs = tdb->idxs; int inum = tdb->inum; for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(!tcbdbvanish(idx->db)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } break; } } return !err;}/* Copy the database file of a table database object. `tdb' specifies the table database object. `path' specifies the path of the destination file. If successful, the return value is true, else, it is false. */static bool tctdbcopyimpl(TCTDB *tdb, const char *path){ assert(tdb); bool err = false; if(!tchdbcopy(tdb->hdb, path)) err = true; const char *opath = tchdbpath(tdb->hdb); TDBIDX *idxs = tdb->idxs; int inum = tdb->inum; for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; const char *ipath; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(*path == '@'){ if(!tcbdbcopy(idx->db, path)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } } else { ipath = tcbdbpath(idx->db); if(tcstrfwm(ipath, opath)){ char *tpath = tcsprintf("%s%s", path, ipath + strlen(opath)); if(!tcbdbcopy(idx->db, tpath)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } TCFREE(tpath); } else { tctdbsetecode(tdb, TCEMISC, __FILE__, __LINE__, __func__); err = true; } } break; } } return !err;}/* Begin the transaction of a table database object. `tdb' specifies the table database object. If successful, the return value is true, else, it is false. */static bool tctdbtranbeginimpl(TCTDB *tdb){ assert(tdb); if(!tctdbmemsync(tdb, false)) return false; if(!tchdbtranbegin(tdb->hdb)) return false; bool err = false; TDBIDX *idxs = tdb->idxs; int inum = tdb->inum; for(int i = 0; i < inum; i++){ TDBIDX *idx = idxs + i; switch(idx->type){ case TDBITLEXICAL: case TDBITDECIMAL: if(!tcbdbtranbegin(idx->db)){ tctdbsetecode(tdb, tcbdbecode(idx->db), __FILE__, __LINE__, __func__); err = true; } break; } } return !err;}/* Commit the transaction of a table database object. `tdb' specifies the table database object. If successful, the return value is true, else, it is false. */static bool tctdbtrancommitimpl(TCTDB *tdb){ assert(tdb); bool err = false; if(!tctdbmemsync(tdb, false)) err = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -