⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tctdb.c

📁 Tokyo Cabinet的Tokyo Cabinet 是一个DBM的实现。这里的数据库由一系列key-value对的记录构成。key和value都可以是任意长度的字节序列,既可以是二进制也可以是字符
💻 C
📖 第 1 页 / 共 5 页
字号:
    }    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 + -