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

📄 tcfdb.c

📁 Tokyo Cabinet的Tokyo Cabinet 是一个DBM的实现。这里的数据库由一系列key-value对的记录构成。key和value都可以是任意长度的字节序列,既可以是二进制也可以是字符
💻 C
📖 第 1 页 / 共 5 页
字号:
  return rv;}/* Begin the transaction of a fixed-length database object. */bool tcfdbtranbegin(TCFDB *fdb){  assert(fdb);  for(double wsec = 1.0 / sysconf(_SC_CLK_TCK); true; wsec *= 2){    if(!FDBLOCKMETHOD(fdb, true)) return false;    if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->fatal){      tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);      FDBUNLOCKMETHOD(fdb);      return false;    }    if(!fdb->tran) break;    FDBUNLOCKMETHOD(fdb);    if(wsec > 1.0) wsec = 1.0;    tcsleep(wsec);  }  fdb->flags &= ~FDBFOPEN;  if(!tcfdbmemsync(fdb, false)){    fdb->flags |= FDBFOPEN;    FDBUNLOCKMETHOD(fdb);    return false;  }  fdb->flags |= FDBFOPEN;  if((fdb->omode & FDBOTSYNC) && fsync(fdb->fd) == -1){    tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);    return false;  }  if(fdb->walfd < 0){    char *tpath = tcsprintf("%s%c%s", fdb->path, MYEXTCHR, FDBWALSUFFIX);    int walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, FDBFILEMODE);    TCFREE(tpath);    if(walfd < 0){      int ecode = TCEOPEN;      switch(errno){      case EACCES: ecode = TCENOPERM; break;      case ENOENT: ecode = TCENOFILE; break;      }      tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__);      FDBUNLOCKMETHOD(fdb);      return false;    }    fdb->walfd = walfd;  }  if(!tcfdbwalinit(fdb)){    FDBUNLOCKMETHOD(fdb);    return false;  }  fdb->tran = true;  FDBUNLOCKMETHOD(fdb);  return true;}/* Commit the transaction of a fixed-length database object. */bool tcfdbtrancommit(TCFDB *fdb){  assert(fdb);  if(!FDBLOCKMETHOD(fdb, true)) return false;  if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->fatal || !fdb->tran){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return false;  }  bool err = false;  if(!tcfdbmemsync(fdb, fdb->omode & FDBOTSYNC)) err = true;  if(!err && ftruncate(fdb->walfd, 0) == -1){    tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);    err = true;  }  fdb->tran = false;  FDBUNLOCKMETHOD(fdb);  return !err;}/* Abort the transaction of a fixed-length database object. */bool tcfdbtranabort(TCFDB *fdb){  assert(fdb);  if(!FDBLOCKMETHOD(fdb, true)) return false;  if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || !fdb->tran){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return false;  }  bool err = false;  if(!tcfdbmemsync(fdb, false)) err = true;  if(!tcfdbwalrestore(fdb, fdb->path)) err = true;  char hbuf[FDBHEADSIZ];  if(lseek(fdb->fd, 0, SEEK_SET) == -1){    tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);    err = false;  } else if(!tcread(fdb->fd, hbuf, FDBHEADSIZ)){    tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);    err = false;  } else {    tcfdbloadmeta(fdb, hbuf);  }  fdb->tran = false;  FDBUNLOCKMETHOD(fdb);  return !err;}/* Get the file path of a fixed-length database object. */const char *tcfdbpath(TCFDB *fdb){  assert(fdb);  if(!FDBLOCKMETHOD(fdb, false)) return NULL;  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return NULL;  }  const char *rv = fdb->path;  FDBUNLOCKMETHOD(fdb);  return rv;}/* Get the number of records of a fixed-length database object. */uint64_t tcfdbrnum(TCFDB *fdb){  assert(fdb);  if(!FDBLOCKMETHOD(fdb, false)) return 0;  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return 0;  }  uint64_t rv = fdb->rnum;  FDBUNLOCKMETHOD(fdb);  return rv;}/* Get the size of the database file of a fixed-length database object. */uint64_t tcfdbfsiz(TCFDB *fdb){  assert(fdb);  if(!FDBLOCKMETHOD(fdb, false)) return 0;  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return 0;  }  uint64_t rv = fdb->fsiz;  FDBUNLOCKMETHOD(fdb);  return rv;}/************************************************************************************************* * features for experts *************************************************************************************************//* Set the error code of a fixed-length database object. */void tcfdbsetecode(TCFDB *fdb, int ecode, const char *filename, int line, const char *func){  assert(fdb && filename && line >= 1 && func);  if(!fdb->fatal){    fdb->ecode = ecode;    if(fdb->mmtx) pthread_setspecific(*(pthread_key_t *)fdb->eckey, (void *)(intptr_t)ecode);  }  if(ecode != TCEINVALID && ecode != TCEKEEP && ecode != TCENOREC){    fdb->fatal = true;    if(fdb->fd >= 0 && (fdb->omode & FDBOWRITER)) tcfdbsetflag(fdb, FDBFFATAL, true);  }  if(fdb->dbgfd >= 0 && (fdb->dbgfd != UINT16_MAX || fdb->fatal)){    int dbgfd = (fdb->dbgfd == UINT16_MAX) ? 1 : fdb->dbgfd;    char obuf[FDBIOBUFSIZ];    int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s\n", filename, line, func,                       fdb->path ? fdb->path : "-", ecode, tcfdberrmsg(ecode));    tcwrite(dbgfd, obuf, osiz);  }}/* Set the file descriptor for debugging output. */void tcfdbsetdbgfd(TCFDB *fdb, int fd){  assert(fdb && fd >= 0);  fdb->dbgfd = fd;}/* Get the file descriptor for debugging output. */int tcfdbdbgfd(TCFDB *fdb){  assert(fdb);  return fdb->dbgfd;}/* Check whether mutual exclusion control is set to a fixed-length database object. */bool tcfdbhasmutex(TCFDB *fdb){  assert(fdb);  return fdb->mmtx != NULL;}/* Synchronize updating contents on memory of a fixed-length database object. */bool tcfdbmemsync(TCFDB *fdb, bool phys){  assert(fdb);  if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return false;  }  bool err = false;  char hbuf[FDBHEADSIZ];  tcfdbdumpmeta(fdb, hbuf);  memcpy(fdb->map, hbuf, FDBOPAQUEOFF);  if(phys){    if(msync(fdb->map, fdb->limsiz, MS_SYNC) == -1){      tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__);      err = true;    }    if(fsync(fdb->fd) == -1){      tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);      err = true;    }  }  return !err;}/* Get the minimum ID number of records of a fixed-length database object. */uint64_t tcfdbmin(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->min;}/* Get the maximum ID number of records of a fixed-length database object. */uint64_t tcfdbmax(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->max;}/* Get the width of the value of each record of a fixed-length database object. */uint32_t tcfdbwidth(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->width;}/* Get the limit file size of a fixed-length database object. */uint64_t tcfdblimsiz(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->limsiz;}/* Get the limit ID number of a fixed-length database object. */uint64_t tcfdblimid(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->limid;}/* Get the inode number of the database file of a fixed-length database object. */uint64_t tcfdbinode(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->inode;}/* Get the modification time of the database file of a fixed-length database object. */time_t tcfdbmtime(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->mtime;}/* Get the connection mode of a fixed-length database object. */int tcfdbomode(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->omode;}/* Get the database type of a fixed-length database object. */uint8_t tcfdbtype(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->type;}/* Get the additional flags of a fixed-length database object. */uint8_t tcfdbflags(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return 0;  }  return fdb->flags;}/* Get the pointer to the opaque field of a fixed-length database object. */char *tcfdbopaque(TCFDB *fdb){  assert(fdb);  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    return NULL;  }  return fdb->map + FDBOPAQUEOFF;}/* Store a record into a fixed-length database object with a duplication handler. */bool tcfdbputproc(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, TCPDPROC proc, void *op){  assert(fdb && proc);  if(!FDBLOCKMETHOD(fdb, id < 1)) return false;  if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return false;  }  if(id == FDBIDMIN){    id = fdb->min;  } else if(id == FDBIDPREV){    id = fdb->min - 1;  } else if(id == FDBIDMAX){    id = fdb->max;  } else if(id == FDBIDNEXT){    id = fdb->max + 1;  }  if(id < 1 || id > fdb->limid){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return false;  }  if(!FDBLOCKRECORD(fdb, true, id)){    FDBUNLOCKMETHOD(fdb);    return false;  }  FDBPDPROCOP procop;  procop.proc = proc;  procop.op = op;  FDBPDPROCOP *procptr = &procop;  char stack[FDBDEFWIDTH+TCNUMBUFSIZ];  char *rbuf;  if(vbuf){    if(vsiz <= sizeof(stack) - sizeof(procptr)){      rbuf = stack;    } else {      TCMALLOC(rbuf, vsiz + sizeof(procptr));    }    char *wp = rbuf;    memcpy(wp, &procptr, sizeof(procptr));    wp += sizeof(procptr);    memcpy(wp, vbuf, vsiz);    vbuf = rbuf + sizeof(procptr);  } else {    rbuf = stack;    memcpy(rbuf, &procptr, sizeof(procptr));    vbuf = rbuf + sizeof(procptr);    vsiz = -1;  }  bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDPROC);  if(rbuf != stack) TCFREE(rbuf);  FDBUNLOCKRECORD(fdb, id);  FDBUNLOCKMETHOD(fdb);  return rv;}/* Process each record atomically of a fixed-length database object. */bool tcfdbforeach(TCFDB *fdb, TCITER iter, void *op){  assert(fdb && iter);  if(!FDBLOCKMETHOD(fdb, false)) return false;  if(fdb->fd < 0){    tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);    FDBUNLOCKMETHOD(fdb);    return false;  }  if(!FDBLOCKALLRECORDS(fdb, false)){    FDBUNLOCKMETHOD(fdb);    return false;  }  FDBTHREADYIELD(fdb);  bool rv = tcfdbforeachimpl(fdb, iter, op);  FDBUNLOCKALLRECORDS(fdb);  FDBUNLOCKMETHOD(fdb);  return rv;}/* Generate the ID number from arbitrary binary data. */int64_t tcfdbkeytoid(const char *kbuf, int ksiz){  assert(kbuf && ksiz >= 0);  if(ksiz == 3 && !memcmp(kbuf, "min", 3)){    return FDBIDMIN;  } else if(ksiz == 4 && !memcmp(kbuf, "prev", 4)){    return FDBIDPREV;  } else if(ksiz == 3 && !memcmp(kbuf, "max", 3)){    return FDBIDMAX;  } else if(ksiz == 4 && !memcmp(kbuf, "next", 4)){    return FDBIDNEXT;  }  int64_t id = 0;  const char *end = kbuf + ksiz;  while(kbuf < end){    int c = *(unsigned char *)(kbuf++);    if(c >= '0' && c <= '9') id = id * 10 + c - '0';  }  return id;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -