📄 tcfdb.c
字号:
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 + -