From b7cbfde4ad5aea538796b0d6e7f02b94a1f80b2d Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 19 Apr 2013 22:16:29 +0700 Subject: [PATCH] #12 All TCFDB tests passed + unified project code style --- tcejdb/myconf.h | 6 + tcejdb/tcbdb.c | 6439 +++++++++++++++++++-------------------- tcejdb/tcbdb.h | 141 +- tcejdb/tcbmgr.c | 4 + tcejdb/tcfdb.c | 4628 +++++++++++++++------------- tcejdb/tcfdb.h | 135 +- tcejdb/tcfmttest.c | 5 +- tcejdb/tcftest.c | 4 +- tcejdb/tchdb.c | 8612 ++++++++++++++++++++++++++-------------------------- tcejdb/tchdb.h | 184 +- tcejdb/tchmttest.c | 4 +- tcejdb/tchtest.c | 2 + tcejdb/tctmgr.c | 2 + 13 files changed, 10117 insertions(+), 10049 deletions(-) diff --git a/tcejdb/myconf.h b/tcejdb/myconf.h index a125808..e77ac75 100644 --- a/tcejdb/myconf.h +++ b/tcejdb/myconf.h @@ -225,6 +225,12 @@ #define sysconf_SC_CLK_TCK sysconf(_SC_CLK_TCK) #endif +#define CLOSEFH2(_fd) \ + do { \ + CLOSEFH(_fd); \ + (_fd) = INVALID_HANDLE_VALUE; \ + } while(0) + #include #include #include diff --git a/tcejdb/tcbdb.c b/tcejdb/tcbdb.c index c19a542..82f01c6 100644 --- a/tcejdb/tcbdb.c +++ b/tcejdb/tcbdb.c @@ -38,49 +38,49 @@ #define BDBDEFLSMAX 16384 // default maximum size of each leaf #define BDBMINLSMAX 512 // minimum maximum size of each leaf -typedef struct { // type of structure for a record - int ksiz; // size of the key region - int vsiz; // size of the value region - TCLIST *rest; // list of value objects +typedef struct { // type of structure for a record + int ksiz; // size of the key region + int vsiz; // size of the value region + TCLIST *rest; // list of value objects } BDBREC; -typedef struct { // type of structure for a leaf page - uint64_t id; // ID number of the leaf - TCPTRLIST *recs; // list of records - int size; // predicted size of serialized buffer - uint64_t prev; // ID number of the previous leaf - uint64_t next; // ID number of the next leaf - bool dirty; // whether to be written back - bool dead; // whether to be removed +typedef struct { // type of structure for a leaf page + uint64_t id; // ID number of the leaf + TCPTRLIST *recs; // list of records + int size; // predicted size of serialized buffer + uint64_t prev; // ID number of the previous leaf + uint64_t next; // ID number of the next leaf + bool dirty; // whether to be written back + bool dead; // whether to be removed } BDBLEAF; -typedef struct { // type of structure for a page index - uint64_t pid; // ID number of the referring page - int ksiz; // size of the key region +typedef struct { // type of structure for a page index + uint64_t pid; // ID number of the referring page + int ksiz; // size of the key region } BDBIDX; -typedef struct { // type of structure for a node page - uint64_t id; // ID number of the node - uint64_t heir; // ID of the child before the first index - TCPTRLIST *idxs; // list of indices - bool dirty; // whether to be written back - bool dead; // whether to be removed +typedef struct { // type of structure for a node page + uint64_t id; // ID number of the node + uint64_t heir; // ID of the child before the first index + TCPTRLIST *idxs; // list of indices + bool dirty; // whether to be written back + bool dead; // whether to be removed } BDBNODE; -enum { // enumeration for duplication behavior - BDBPDOVER, // overwrite an existing value - BDBPDKEEP, // keep the existing value - BDBPDCAT, // concatenate values - BDBPDDUP, // allow duplication of keys - BDBPDDUPB, // allow backward duplication - BDBPDADDINT, // add an integer - BDBPDADDDBL, // add a real number - BDBPDPROC // process by a callback function +enum { // enumeration for duplication behavior + BDBPDOVER, // overwrite an existing value + BDBPDKEEP, // keep the existing value + BDBPDCAT, // concatenate values + BDBPDDUP, // allow duplication of keys + BDBPDDUPB, // allow backward duplication + BDBPDADDINT, // add an integer + BDBPDADDDBL, // add a real number + BDBPDPROC // process by a callback function }; -typedef struct { // type of structure for a duplication callback - TCPDPROC proc; // function pointer - void *op; // opaque pointer +typedef struct { // type of structure for a duplication callback + TCPDPROC proc; // function pointer + void *op; // opaque pointer } BDBPDPROCOP; @@ -108,7 +108,7 @@ static BDBLEAF *tcbdbleafload(TCBDB *bdb, uint64_t id); static bool tcbdbleafcheck(TCBDB *bdb, uint64_t id); static BDBLEAF *tcbdbgethistleaf(TCBDB *bdb, const char *kbuf, int ksiz, uint64_t id); static bool tcbdbleafaddrec(TCBDB *bdb, BDBLEAF *leaf, int dmode, - const char *kbuf, int ksiz, const char *vbuf, int vsiz); + const char *kbuf, int ksiz, const char *vbuf, int vsiz); static BDBLEAF *tcbdbleafdivide(TCBDB *bdb, BDBLEAF *leaf); static bool tcbdbleafkill(TCBDB *bdb, BDBLEAF *leaf); static BDBNODE *tcbdbnodenew(TCBDB *bdb, uint64_t heir); @@ -116,7 +116,7 @@ static bool tcbdbnodecacheout(TCBDB *bdb, BDBNODE *node); static bool tcbdbnodesave(TCBDB *bdb, BDBNODE *node); static BDBNODE *tcbdbnodeload(TCBDB *bdb, uint64_t id); static void tcbdbnodeaddidx(TCBDB *bdb, BDBNODE *node, bool order, uint64_t pid, - const char *kbuf, int ksiz); + const char *kbuf, int ksiz); static bool tcbdbnodesubidx(TCBDB *bdb, BDBNODE *node, uint64_t pid); static uint64_t tcbdbsearchleaf(TCBDB *bdb, const char *kbuf, int ksiz); static BDBREC *tcbdbsearchrec(TCBDB *bdb, BDBLEAF *leaf, const char *kbuf, int ksiz, int *ip); @@ -126,17 +126,17 @@ static void tcbdbcachepurge(TCBDB *bdb); static bool tcbdbopenimpl(TCBDB *bdb, const char *path, int omode); static bool tcbdbcloseimpl(TCBDB *bdb); static bool tcbdbputimpl(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - int dmode); + int dmode); static bool tcbdboutimpl(TCBDB *bdb, const char *kbuf, int ksiz); static bool tcbdboutlist(TCBDB *bdb, const char *kbuf, int ksiz); static const char *tcbdbgetimpl(TCBDB *bdb, const char *kbuf, int ksiz, int *sp); static int tcbdbgetnum(TCBDB *bdb, const char *kbuf, int ksiz); static TCLIST *tcbdbgetlist(TCBDB *bdb, const char *kbuf, int ksiz); static bool tcbdbrangeimpl(TCBDB *bdb, const char *bkbuf, int bksiz, bool binc, - const char *ekbuf, int eksiz, bool einc, int max, TCLIST *keys); + const char *ekbuf, int eksiz, bool einc, int max, TCLIST *keys); static bool tcbdbrangefwm(TCBDB *bdb, const char *pbuf, int psiz, int max, TCLIST *keys); static bool tcbdboptimizeimpl(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); static bool tcbdbvanishimpl(TCBDB *bdb); static bool tcbdblockmethod(TCBDB *bdb, bool wr); static bool tcbdbunlockmethod(TCBDB *bdb); @@ -165,1135 +165,1069 @@ void tcbdbprintnode(TCBDB *bdb, BDBNODE *node); * API *************************************************************************************************/ - /* Get the message string corresponding to an error code. */ -const char *tcbdberrmsg(int ecode){ - return tcerrmsg(ecode); +const char *tcbdberrmsg(int ecode) { + return tcerrmsg(ecode); } - /* Create a B+ tree database object. */ -TCBDB *tcbdbnew(void){ - TCBDB *bdb; - TCMALLOC(bdb, sizeof(*bdb)); - tcbdbclear(bdb); - bdb->hdb = tchdbnew(); - TCMALLOC(bdb->hist, sizeof(*bdb->hist) * BDBLEVELMAX); - tchdbtune(bdb->hdb, BDBDEFBNUM, BDBDEFAPOW, BDBDEFFPOW, 0); - tchdbsetxmsiz(bdb->hdb, 0); - return bdb; +TCBDB *tcbdbnew(void) { + TCBDB *bdb; + TCMALLOC(bdb, sizeof (*bdb)); + tcbdbclear(bdb); + bdb->hdb = tchdbnew(); + TCMALLOC(bdb->hist, sizeof (*bdb->hist) * BDBLEVELMAX); + tchdbtune(bdb->hdb, BDBDEFBNUM, BDBDEFAPOW, BDBDEFFPOW, 0); + tchdbsetxmsiz(bdb->hdb, 0); + return bdb; } - /* Delete a B+ tree database object. */ -void tcbdbdel(TCBDB *bdb){ - assert(bdb); - if(bdb->open) tcbdbclose(bdb); - TCFREE(bdb->hist); - tchdbdel(bdb->hdb); - if(bdb->mmtx){ - pthread_mutex_destroy(bdb->cmtx); - pthread_rwlock_destroy(bdb->mmtx); - TCFREE(bdb->cmtx); - TCFREE(bdb->mmtx); - } - TCFREE(bdb); +void tcbdbdel(TCBDB *bdb) { + assert(bdb); + if (bdb->open) tcbdbclose(bdb); + TCFREE(bdb->hist); + tchdbdel(bdb->hdb); + if (bdb->mmtx) { + pthread_mutex_destroy(bdb->cmtx); + pthread_rwlock_destroy(bdb->mmtx); + TCFREE(bdb->cmtx); + TCFREE(bdb->mmtx); + } + TCFREE(bdb); } - /* Get the last happened error code of a B+ tree database object. */ -int tcbdbecode(TCBDB *bdb){ - assert(bdb); - return tchdbecode(bdb->hdb); +int tcbdbecode(TCBDB *bdb) { + assert(bdb); + return tchdbecode(bdb->hdb); } - /* Set mutual exclusion control of a B+ tree database object for threading. */ -bool tcbdbsetmutex(TCBDB *bdb){ - assert(bdb); - if(bdb->mmtx || bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - TCMALLOC(bdb->mmtx, sizeof(pthread_rwlock_t)); - TCMALLOC(bdb->cmtx, sizeof(pthread_mutex_t)); - bool err = false; - if(pthread_rwlock_init(bdb->mmtx, NULL) != 0) err = true; - if(pthread_mutex_init(bdb->cmtx, NULL) != 0) err = true; - if(err){ - TCFREE(bdb->cmtx); - TCFREE(bdb->mmtx); - bdb->cmtx = NULL; - bdb->mmtx = NULL; - return false; - } - return tchdbsetmutex(bdb->hdb); +bool tcbdbsetmutex(TCBDB *bdb) { + assert(bdb); + if (bdb->mmtx || bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + TCMALLOC(bdb->mmtx, sizeof (pthread_rwlock_t)); + TCMALLOC(bdb->cmtx, sizeof (pthread_mutex_t)); + bool err = false; + if (pthread_rwlock_init(bdb->mmtx, NULL) != 0) err = true; + if (pthread_mutex_init(bdb->cmtx, NULL) != 0) err = true; + if (err) { + TCFREE(bdb->cmtx); + TCFREE(bdb->mmtx); + bdb->cmtx = NULL; + bdb->mmtx = NULL; + return false; + } + return tchdbsetmutex(bdb->hdb); } - /* Set the custom comparison function of a B+ tree database object. */ -bool tcbdbsetcmpfunc(TCBDB *bdb, TCCMP cmp, void *cmpop){ - assert(bdb && cmp); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - bdb->cmp = cmp; - bdb->cmpop = cmpop; - return true; +bool tcbdbsetcmpfunc(TCBDB *bdb, TCCMP cmp, void *cmpop) { + assert(bdb && cmp); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + bdb->cmp = cmp; + bdb->cmpop = cmpop; + return true; } - /* Set the tuning parameters of a B+ tree database object. */ bool tcbdbtune(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - bdb->lmemb = (lmemb > 0) ? tclmax(lmemb, BDBMINLMEMB) : BDBDEFLMEMB; - bdb->nmemb = (nmemb > 0) ? tclmax(nmemb, BDBMINNMEMB) : BDBDEFNMEMB; - bdb->opts = opts; - uint8_t hopts = 0; - if(opts & BDBTLARGE) hopts |= HDBTLARGE; - if(opts & BDBTDEFLATE) hopts |= HDBTDEFLATE; - if(opts & BDBTBZIP) hopts |= HDBTBZIP; - if(opts & BDBTTCBS) hopts |= HDBTTCBS; - if(opts & BDBTEXCODEC) hopts |= HDBTEXCODEC; - bnum = (bnum > 0) ? bnum : BDBDEFBNUM; - apow = (apow >= 0) ? apow : BDBDEFAPOW; - fpow = (fpow >= 0) ? fpow : BDBDEFFPOW; - return tchdbtune(bdb->hdb, bnum, apow, fpow, hopts); + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + bdb->lmemb = (lmemb > 0) ? tclmax(lmemb, BDBMINLMEMB) : BDBDEFLMEMB; + bdb->nmemb = (nmemb > 0) ? tclmax(nmemb, BDBMINNMEMB) : BDBDEFNMEMB; + bdb->opts = opts; + uint8_t hopts = 0; + if (opts & BDBTLARGE) hopts |= HDBTLARGE; + if (opts & BDBTDEFLATE) hopts |= HDBTDEFLATE; + if (opts & BDBTBZIP) hopts |= HDBTBZIP; + if (opts & BDBTTCBS) hopts |= HDBTTCBS; + if (opts & BDBTEXCODEC) hopts |= HDBTEXCODEC; + bnum = (bnum > 0) ? bnum : BDBDEFBNUM; + apow = (apow >= 0) ? apow : BDBDEFAPOW; + fpow = (fpow >= 0) ? fpow : BDBDEFFPOW; + return tchdbtune(bdb->hdb, bnum, apow, fpow, hopts); } - /* Set the caching parameters of a B+ tree database object. */ -bool tcbdbsetcache(TCBDB *bdb, int32_t lcnum, int32_t ncnum){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - if(lcnum > 0) bdb->lcnum = tclmax(lcnum, BDBLEVELMAX); - if(ncnum > 0) bdb->ncnum = tclmax(ncnum, BDBLEVELMAX); - return true; +bool tcbdbsetcache(TCBDB *bdb, int32_t lcnum, int32_t ncnum) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + if (lcnum > 0) bdb->lcnum = tclmax(lcnum, BDBLEVELMAX); + if (ncnum > 0) bdb->ncnum = tclmax(ncnum, BDBLEVELMAX); + return true; } - /* Set the size of the extra mapped memory of a B+ tree database object. */ -bool tcbdbsetxmsiz(TCBDB *bdb, int64_t xmsiz){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - return tchdbsetxmsiz(bdb->hdb, xmsiz); +bool tcbdbsetxmsiz(TCBDB *bdb, int64_t xmsiz) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + return tchdbsetxmsiz(bdb->hdb, xmsiz); } - /* Set the unit step number of auto defragmentation of a B+ tree database object. */ -bool tcbdbsetdfunit(TCBDB *bdb, int32_t dfunit){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - return tchdbsetdfunit(bdb->hdb, dfunit); +bool tcbdbsetdfunit(TCBDB *bdb, int32_t dfunit) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + return tchdbsetdfunit(bdb->hdb, dfunit); } - /* Open a database file and connect a B+ tree database object. */ -bool tcbdbopen(TCBDB *bdb, const char *path, int omode){ - assert(bdb && path); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbopen(TCBDB *bdb, const char *path, int omode) { + assert(bdb && path); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbopenimpl(bdb, path, omode); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbopenimpl(bdb, path, omode); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Close a B+ tree database object. */ -bool tcbdbclose(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbclose(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcloseimpl(bdb); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcloseimpl(bdb); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a record into a B+ tree database object. */ -bool tcbdbput(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbput(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDOVER); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDOVER); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a string record into a B+ tree database object. */ -bool tcbdbput2(TCBDB *bdb, const char *kstr, const char *vstr){ - assert(bdb && kstr && vstr); - return tcbdbput(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tcbdbput2(TCBDB *bdb, const char *kstr, const char *vstr) { + assert(bdb && kstr && vstr); + return tcbdbput(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Store a new record into a B+ tree database object. */ -bool tcbdbputkeep(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbputkeep(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDKEEP); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDKEEP); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a new string record into a B+ tree database object. */ -bool tcbdbputkeep2(TCBDB *bdb, const char *kstr, const char *vstr){ - assert(bdb && kstr && vstr); - return tcbdbputkeep(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tcbdbputkeep2(TCBDB *bdb, const char *kstr, const char *vstr) { + assert(bdb && kstr && vstr); + return tcbdbputkeep(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Concatenate a value at the end of the existing record in a B+ tree database object. */ -bool tcbdbputcat(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbputcat(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDCAT); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDCAT); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Concatenate a string value at the end of the existing record in a B+ tree database object. */ -bool tcbdbputcat2(TCBDB *bdb, const char *kstr, const char *vstr){ - assert(bdb && kstr && vstr); - return tcbdbputcat(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tcbdbputcat2(TCBDB *bdb, const char *kstr, const char *vstr) { + assert(bdb && kstr && vstr); + return tcbdbputcat(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Store a record into a B+ tree database object with allowing duplication of keys. */ -bool tcbdbputdup(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbputdup(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUP); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUP); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a string record into a B+ tree database object with allowing duplication of keys. */ -bool tcbdbputdup2(TCBDB *bdb, const char *kstr, const char *vstr){ - assert(bdb && kstr && vstr); - return tcbdbputdup(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tcbdbputdup2(TCBDB *bdb, const char *kstr, const char *vstr) { + assert(bdb && kstr && vstr); + return tcbdbputdup(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Store records into a B+ tree database object with allowing duplication of keys. */ -bool tcbdbputdup3(TCBDB *bdb, const void *kbuf, int ksiz, const TCLIST *vals){ - assert(bdb && kbuf && ksiz >= 0 && vals); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbputdup3(TCBDB *bdb, const void *kbuf, int ksiz, const TCLIST *vals) { + assert(bdb && kbuf && ksiz >= 0 && vals); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool err = false; + int ln = TCLISTNUM(vals); + for (int i = 0; i < ln; i++) { + const char *vbuf; + int vsiz; + TCLISTVAL(vbuf, vals, i, vsiz); + if (!tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUP)) err = true; + } BDBUNLOCKMETHOD(bdb); - return false; - } - bool err = false; - int ln = TCLISTNUM(vals); - for(int i = 0; i < ln; i++){ - const char *vbuf; - int vsiz; - TCLISTVAL(vbuf, vals, i, vsiz); - if(!tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUP)) err = true; - } - BDBUNLOCKMETHOD(bdb); - return !err; + return !err; } - /* Remove a record of a B+ tree database object. */ -bool tcbdbout(TCBDB *bdb, const void *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbout(TCBDB *bdb, const void *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdboutimpl(bdb, kbuf, ksiz); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdboutimpl(bdb, kbuf, ksiz); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Remove a string record of a B+ tree database object. */ -bool tcbdbout2(TCBDB *bdb, const char *kstr){ - assert(bdb && kstr); - return tcbdbout(bdb, kstr, strlen(kstr)); +bool tcbdbout2(TCBDB *bdb, const char *kstr) { + assert(bdb && kstr); + return tcbdbout(bdb, kstr, strlen(kstr)); } - /* Remove records of a B+ tree database object. */ -bool tcbdbout3(TCBDB *bdb, const void *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbout3(TCBDB *bdb, const void *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdboutlist(bdb, kbuf, ksiz); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdboutlist(bdb, kbuf, ksiz); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Retrieve a record in a B+ tree database object. */ -void *tcbdbget(TCBDB *bdb, const void *kbuf, int ksiz, int *sp){ - assert(bdb && kbuf && ksiz >= 0 && sp); - if(!BDBLOCKMETHOD(bdb, false)) return NULL; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return NULL; - } - const char *vbuf = tcbdbgetimpl(bdb, kbuf, ksiz, sp); - char *rv; - if(vbuf){ - TCMEMDUP(rv, vbuf, *sp); - } else { - rv = NULL; - } - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)){ - TCFREE(rv); - rv = NULL; +void *tcbdbget(TCBDB *bdb, const void *kbuf, int ksiz, int *sp) { + assert(bdb && kbuf && ksiz >= 0 && sp); + if (!BDBLOCKMETHOD(bdb, false)) return NULL; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return NULL; + } + const char *vbuf = tcbdbgetimpl(bdb, kbuf, ksiz, sp); + char *rv; + if (vbuf) { + TCMEMDUP(rv, vbuf, *sp); + } else { + rv = NULL; } + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) { + TCFREE(rv); + rv = NULL; + } + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Retrieve a string record in a B+ tree database object. */ -char *tcbdbget2(TCBDB *bdb, const char *kstr){ - assert(bdb && kstr); - int vsiz; - return tcbdbget(bdb, kstr, strlen(kstr), &vsiz); +char *tcbdbget2(TCBDB *bdb, const char *kstr) { + assert(bdb && kstr); + int vsiz; + return tcbdbget(bdb, kstr, strlen(kstr), &vsiz); } - /* Retrieve a record in a B+ tree database object and write the value into a buffer. */ -const void *tcbdbget3(TCBDB *bdb, const void *kbuf, int ksiz, int *sp){ - assert(bdb && kbuf && ksiz >= 0 && sp); - if(!BDBLOCKMETHOD(bdb, false)) return NULL; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return NULL; - } - const char *rv = tcbdbgetimpl(bdb, kbuf, ksiz, sp); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = NULL; +const void *tcbdbget3(TCBDB *bdb, const void *kbuf, int ksiz, int *sp) { + assert(bdb && kbuf && ksiz >= 0 && sp); + if (!BDBLOCKMETHOD(bdb, false)) return NULL; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return NULL; + } + const char *rv = tcbdbgetimpl(bdb, kbuf, ksiz, sp); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = NULL; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Retrieve records in a B+ tree database object. */ -TCLIST *tcbdbget4(TCBDB *bdb, const void *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, false)) return NULL; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return NULL; - } - TCLIST *rv = tcbdbgetlist(bdb, kbuf, ksiz); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)){ - if(rv) tclistdel(rv); - rv = NULL; +TCLIST *tcbdbget4(TCBDB *bdb, const void *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, false)) return NULL; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return NULL; + } + TCLIST *rv = tcbdbgetlist(bdb, kbuf, ksiz); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; + BDBUNLOCKMETHOD(bdb); + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) { + if (rv) tclistdel(rv); + rv = NULL; + } + BDBUNLOCKMETHOD(bdb); } - BDBUNLOCKMETHOD(bdb); - } - return rv; + return rv; } - /* Get the number of records corresponding a key in a B+ tree database object. */ -int tcbdbvnum(TCBDB *bdb, const void *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, false)) return 0; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return 0; - } - int rv = tcbdbgetnum(bdb, kbuf, ksiz); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = 0; +int tcbdbvnum(TCBDB *bdb, const void *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, false)) return 0; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return 0; + } + int rv = tcbdbgetnum(bdb, kbuf, ksiz); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = 0; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Get the number of records corresponding a string key in a B+ tree database object. */ -int tcbdbvnum2(TCBDB *bdb, const char *kstr){ - assert(bdb && kstr); - return tcbdbvnum(bdb, kstr, strlen(kstr)); +int tcbdbvnum2(TCBDB *bdb, const char *kstr) { + assert(bdb && kstr); + return tcbdbvnum(bdb, kstr, strlen(kstr)); } - /* Get the size of the value of a record in a B+ tree database object. */ -int tcbdbvsiz(TCBDB *bdb, const void *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - int vsiz; - if(!tcbdbget3(bdb, kbuf, ksiz, &vsiz)) return -1; - return vsiz; +int tcbdbvsiz(TCBDB *bdb, const void *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + int vsiz; + if (!tcbdbget3(bdb, kbuf, ksiz, &vsiz)) return -1; + return vsiz; } - /* Get the size of the value of a string record in a B+ tree database object. */ -int tcbdbvsiz2(TCBDB *bdb, const char *kstr){ - assert(bdb && kstr); - return tcbdbvsiz(bdb, kstr, strlen(kstr)); +int tcbdbvsiz2(TCBDB *bdb, const char *kstr) { + assert(bdb && kstr); + return tcbdbvsiz(bdb, kstr, strlen(kstr)); } - /* Get keys of ranged records in a B+ tree database object. */ TCLIST *tcbdbrange(TCBDB *bdb, const void *bkbuf, int bksiz, bool binc, - const void *ekbuf, int eksiz, bool einc, int max){ - assert(bdb); - TCLIST *keys = tclistnew(); - if(!BDBLOCKMETHOD(bdb, false)) return keys; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); + const void *ekbuf, int eksiz, bool einc, int max) { + assert(bdb); + TCLIST *keys = tclistnew(); + if (!BDBLOCKMETHOD(bdb, false)) return keys; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return keys; + } + tcbdbrangeimpl(bdb, bkbuf, bksiz, binc, ekbuf, eksiz, einc, max, keys); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; + BDBUNLOCKMETHOD(bdb); + if (adj && BDBLOCKMETHOD(bdb, true)) { + tcbdbcacheadjust(bdb); + BDBUNLOCKMETHOD(bdb); + } return keys; - } - tcbdbrangeimpl(bdb, bkbuf, bksiz, binc, ekbuf, eksiz, einc, max, keys); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - tcbdbcacheadjust(bdb); - BDBUNLOCKMETHOD(bdb); - } - return keys; } - /* Get string keys of ranged records in a B+ tree database object. */ TCLIST *tcbdbrange2(TCBDB *bdb, const char *bkstr, bool binc, - const char *ekstr, bool einc, int max){ - assert(bdb); - return tcbdbrange(bdb, bkstr, bkstr ? strlen(bkstr) : 0, binc, - ekstr, ekstr ? strlen(ekstr) : 0, einc, max); + const char *ekstr, bool einc, int max) { + assert(bdb); + return tcbdbrange(bdb, bkstr, bkstr ? strlen(bkstr) : 0, binc, + ekstr, ekstr ? strlen(ekstr) : 0, einc, max); } - /* Get forward matching keys in a B+ tree database object. */ -TCLIST *tcbdbfwmkeys(TCBDB *bdb, const void *pbuf, int psiz, int max){ - assert(bdb && pbuf && psiz >= 0); - TCLIST *keys = tclistnew(); - if(!BDBLOCKMETHOD(bdb, false)) return keys; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); +TCLIST *tcbdbfwmkeys(TCBDB *bdb, const void *pbuf, int psiz, int max) { + assert(bdb && pbuf && psiz >= 0); + TCLIST *keys = tclistnew(); + if (!BDBLOCKMETHOD(bdb, false)) return keys; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return keys; + } + tcbdbrangefwm(bdb, pbuf, psiz, max, keys); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; + BDBUNLOCKMETHOD(bdb); + if (adj && BDBLOCKMETHOD(bdb, true)) { + tcbdbcacheadjust(bdb); + BDBUNLOCKMETHOD(bdb); + } return keys; - } - tcbdbrangefwm(bdb, pbuf, psiz, max, keys); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - tcbdbcacheadjust(bdb); - BDBUNLOCKMETHOD(bdb); - } - return keys; } - /* Get forward matching string keys in a B+ tree database object. */ -TCLIST *tcbdbfwmkeys2(TCBDB *bdb, const char *pstr, int max){ - assert(bdb && pstr); - return tcbdbfwmkeys(bdb, pstr, strlen(pstr), max); +TCLIST *tcbdbfwmkeys2(TCBDB *bdb, const char *pstr, int max) { + assert(bdb && pstr); + return tcbdbfwmkeys(bdb, pstr, strlen(pstr), max); } - /* Add an integer to a record in a B+ tree database object. */ -int tcbdbaddint(TCBDB *bdb, const void *kbuf, int ksiz, int num){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return INT_MIN; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +int tcbdbaddint(TCBDB *bdb, const void *kbuf, int ksiz, int num) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return INT_MIN; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return INT_MIN; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, (char *) &num, sizeof (num), BDBPDADDINT); BDBUNLOCKMETHOD(bdb); - return INT_MIN; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, (char *)&num, sizeof(num), BDBPDADDINT); - BDBUNLOCKMETHOD(bdb); - return rv ? num : INT_MIN; + return rv ? num : INT_MIN; } - /* Add a real number to a record in a B+ tree database object. */ -double tcbdbadddouble(TCBDB *bdb, const void *kbuf, int ksiz, double num){ - assert(bdb && kbuf && ksiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return nan(""); - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +double tcbdbadddouble(TCBDB *bdb, const void *kbuf, int ksiz, double num) { + assert(bdb && kbuf && ksiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return nan(""); + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return nan(""); + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, (char *) &num, sizeof (num), BDBPDADDDBL); BDBUNLOCKMETHOD(bdb); - return nan(""); - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, (char *)&num, sizeof(num), BDBPDADDDBL); - BDBUNLOCKMETHOD(bdb); - return rv ? num : nan(""); + return rv ? num : nan(""); } - /* Synchronize updated contents of a B+ tree database object with the file and the device. */ -bool tcbdbsync(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode || bdb->tran){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbsync(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode || bdb->tran) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbmemsync(bdb, true); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbmemsync(bdb, true); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Optimize the file of a B+ tree database object. */ bool tcbdboptimize(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode || bdb->tran){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode || bdb->tran) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBTHREADYIELD(bdb); + bool rv = tcbdboptimizeimpl(bdb, lmemb, nmemb, bnum, apow, fpow, opts); BDBUNLOCKMETHOD(bdb); - return false; - } - BDBTHREADYIELD(bdb); - bool rv = tcbdboptimizeimpl(bdb, lmemb, nmemb, bnum, apow, fpow, opts); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Remove all records of a B+ tree database object. */ -bool tcbdbvanish(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode || bdb->tran){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbvanish(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode || bdb->tran) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBTHREADYIELD(bdb); + bool rv = tcbdbvanishimpl(bdb); BDBUNLOCKMETHOD(bdb); - return false; - } - BDBTHREADYIELD(bdb); - bool rv = tcbdbvanishimpl(bdb); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Copy the database file of a B+ tree database object. */ -bool tcbdbcopy(TCBDB *bdb, const char *path){ - assert(bdb && path); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - BDBTHREADYIELD(bdb); - TCLIST *lids = tclistnew(); - TCLIST *nids = tclistnew(); - const char *vbuf; - int vsiz; - TCMAP *leafc = bdb->leafc; - tcmapiterinit(leafc); - while((vbuf = tcmapiternext(leafc, &vsiz)) != NULL){ - TCLISTPUSH(lids, vbuf, vsiz); - } - TCMAP *nodec = bdb->nodec; - tcmapiterinit(nodec); - while((vbuf = tcmapiternext(nodec, &vsiz)) != NULL){ - TCLISTPUSH(nids, vbuf, vsiz); - } - BDBUNLOCKMETHOD(bdb); - bool err = false; - int ln = TCLISTNUM(lids); - for(int i = 0; i < ln; i++){ - vbuf = TCLISTVALPTR(lids, i); - if(BDBLOCKMETHOD(bdb, true)){ - BDBTHREADYIELD(bdb); - if(bdb->open){ - int rsiz; - BDBLEAF *leaf = (BDBLEAF *)tcmapget(bdb->leafc, vbuf, sizeof(leaf->id), &rsiz); - if(leaf && leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; - } else { - err = true; - } - BDBUNLOCKMETHOD(bdb); +bool tcbdbcopy(TCBDB *bdb, const char *path) { + assert(bdb && path); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBTHREADYIELD(bdb); + TCLIST *lids = tclistnew(); + TCLIST *nids = tclistnew(); + const char *vbuf; + int vsiz; + TCMAP *leafc = bdb->leafc; + tcmapiterinit(leafc); + while ((vbuf = tcmapiternext(leafc, &vsiz)) != NULL) { + TCLISTPUSH(lids, vbuf, vsiz); + } + TCMAP *nodec = bdb->nodec; + tcmapiterinit(nodec); + while ((vbuf = tcmapiternext(nodec, &vsiz)) != NULL) { + TCLISTPUSH(nids, vbuf, vsiz); + } + BDBUNLOCKMETHOD(bdb); + bool err = false; + int ln = TCLISTNUM(lids); + for (int i = 0; i < ln; i++) { + vbuf = TCLISTVALPTR(lids, i); + if (BDBLOCKMETHOD(bdb, true)) { + BDBTHREADYIELD(bdb); + if (bdb->open) { + int rsiz; + BDBLEAF *leaf = (BDBLEAF *) tcmapget(bdb->leafc, vbuf, sizeof (leaf->id), &rsiz); + if (leaf && leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; + } else { + err = true; + } + BDBUNLOCKMETHOD(bdb); + } else { + err = true; + } + } + ln = TCLISTNUM(nids); + for (int i = 0; i < ln; i++) { + vbuf = TCLISTVALPTR(nids, i); + if (BDBLOCKMETHOD(bdb, true)) { + if (bdb->open) { + int rsiz; + BDBNODE *node = (BDBNODE *) tcmapget(bdb->nodec, vbuf, sizeof (node->id), &rsiz); + if (node && node->dirty && !tcbdbnodesave(bdb, node)) err = true; + } else { + err = true; + } + BDBUNLOCKMETHOD(bdb); + } else { + err = true; + } + } + tclistdel(nids); + tclistdel(lids); + if (!tcbdbtranbegin(bdb)) err = true; + if (BDBLOCKMETHOD(bdb, false)) { + BDBTHREADYIELD(bdb); + if (!tchdbcopy(bdb->hdb, path)) err = true; + BDBUNLOCKMETHOD(bdb); } else { - err = true; - } - } - ln = TCLISTNUM(nids); - for(int i = 0; i < ln; i++){ - vbuf = TCLISTVALPTR(nids, i); - if(BDBLOCKMETHOD(bdb, true)){ - if(bdb->open){ - int rsiz; - BDBNODE *node = (BDBNODE *)tcmapget(bdb->nodec, vbuf, sizeof(node->id), &rsiz); - if(node && node->dirty && !tcbdbnodesave(bdb, node)) err = true; - } else { err = true; - } - BDBUNLOCKMETHOD(bdb); - } else { - err = true; } - } - tclistdel(nids); - tclistdel(lids); - if(!tcbdbtranbegin(bdb)) err = true; - if(BDBLOCKMETHOD(bdb, false)){ - BDBTHREADYIELD(bdb); - if(!tchdbcopy(bdb->hdb, path)) err = true; - BDBUNLOCKMETHOD(bdb); - } else { - err = true; - } - if(!tcbdbtrancommit(bdb)) err = true; - return !err; + if (!tcbdbtrancommit(bdb)) err = true; + return !err; } - /* Begin the transaction of a B+ tree database object. */ -bool tcbdbtranbegin(TCBDB *bdb){ - assert(bdb); - for(double wsec = 1.0 / sysconf_SC_CLK_TCK; true; wsec *= 2){ - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(!bdb->tran) break; - BDBUNLOCKMETHOD(bdb); - if(wsec > 1.0) wsec = 1.0; - tcsleep(wsec); - } - if(!tcbdbmemsync(bdb, false)){ - BDBUNLOCKMETHOD(bdb); - return false; - } - if(!tchdbtranbegin(bdb->hdb)){ +bool tcbdbtranbegin(TCBDB *bdb) { + assert(bdb); + for (double wsec = 1.0 / sysconf_SC_CLK_TCK; true; wsec *= 2) { + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (!bdb->tran) break; + BDBUNLOCKMETHOD(bdb); + if (wsec > 1.0) wsec = 1.0; + tcsleep(wsec); + } + if (!tcbdbmemsync(bdb, false)) { + BDBUNLOCKMETHOD(bdb); + return false; + } + if (!tchdbtranbegin(bdb->hdb)) { + BDBUNLOCKMETHOD(bdb); + return false; + } + bdb->tran = true; + TCMALLOC(bdb->rbopaque, BDBOPAQUESIZ); + tchdbreadopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); BDBUNLOCKMETHOD(bdb); - return false; - } - bdb->tran = true; - TCMALLOC(bdb->rbopaque, BDBOPAQUESIZ); - tchdbreadopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); - BDBUNLOCKMETHOD(bdb); - return true; + return true; } - /* Commit the transaction of a B+ tree database object. */ -bool tcbdbtrancommit(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode || !bdb->tran){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbtrancommit(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode || !bdb->tran) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + TCFREE(bdb->rbopaque); + bdb->tran = false; + bdb->rbopaque = NULL; + bool err = false; + if (!tcbdbmemsync(bdb, false)) err = true; + if (!tcbdbcacheadjust(bdb)) err = true; + if (err) { + tchdbtranabort(bdb->hdb); + } else if (!tchdbtrancommit(bdb->hdb)) { + err = true; + } BDBUNLOCKMETHOD(bdb); - return false; - } - TCFREE(bdb->rbopaque); - bdb->tran = false; - bdb->rbopaque = NULL; - bool err = false; - if(!tcbdbmemsync(bdb, false)) err = true; - if(!tcbdbcacheadjust(bdb)) err = true; - if(err){ - tchdbtranabort(bdb->hdb); - } else if(!tchdbtrancommit(bdb->hdb)){ - err = true; - } - BDBUNLOCKMETHOD(bdb); - return !err; + return !err; } - /* Abort the transaction of a B+ tree database object. */ -bool tcbdbtranabort(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode || !bdb->tran || !bdb->rbopaque){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbtranabort(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode || !bdb->tran || !bdb->rbopaque) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + tcbdbcachepurge(bdb); + tchdbwriteopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); + tcbdbloadmeta(bdb); + TCFREE(bdb->rbopaque); + bdb->tran = false; + bdb->rbopaque = NULL; + bdb->hleaf = 0; + bdb->lleaf = 0; + bdb->clock++; + bool err = false; + if (!tcbdbcacheadjust(bdb)) err = true; + if (!tchdbtranvoid(bdb->hdb)) err = true; BDBUNLOCKMETHOD(bdb); - return false; - } - tcbdbcachepurge(bdb); - tchdbwriteopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); - tcbdbloadmeta(bdb); - TCFREE(bdb->rbopaque); - bdb->tran = false; - bdb->rbopaque = NULL; - bdb->hleaf = 0; - bdb->lleaf = 0; - bdb->clock++; - bool err = false; - if(!tcbdbcacheadjust(bdb)) err = true; - if(!tchdbtranvoid(bdb->hdb)) err = true; - BDBUNLOCKMETHOD(bdb); - return !err; + return !err; } - /* Get the file path of a B+ tree database object. */ -const char *tcbdbpath(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, false)) return NULL; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +const char *tcbdbpath(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, false)) return NULL; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return NULL; + } + const char *rv = tchdbpath(bdb->hdb); BDBUNLOCKMETHOD(bdb); - return NULL; - } - const char *rv = tchdbpath(bdb->hdb); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the number of records of a B+ tree database object. */ -uint64_t tcbdbrnum(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, false)) return 0; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tcbdbrnum(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, false)) return 0; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return 0; + } + uint64_t rv = bdb->rnum; BDBUNLOCKMETHOD(bdb); - return 0; - } - uint64_t rv = bdb->rnum; - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the size of the database file of a B+ tree database object. */ -uint64_t tcbdbfsiz(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, false)) return 0; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tcbdbfsiz(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, false)) return 0; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return 0; + } + uint64_t rv = tchdbfsiz(bdb->hdb); BDBUNLOCKMETHOD(bdb); - return 0; - } - uint64_t rv = tchdbfsiz(bdb->hdb); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Create a cursor object. */ -BDBCUR *tcbdbcurnew(TCBDB *bdb){ - assert(bdb); - BDBCUR *cur; - TCMALLOC(cur, sizeof(*cur)); - cur->bdb = bdb; - cur->clock = 0; - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return cur; +BDBCUR *tcbdbcurnew(TCBDB *bdb) { + assert(bdb); + BDBCUR *cur; + TCMALLOC(cur, sizeof (*cur)); + cur->bdb = bdb; + cur->clock = 0; + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return cur; } - /* Delete a cursor object. */ -void tcbdbcurdel(BDBCUR *cur){ - assert(cur); - TCFREE(cur); +void tcbdbcurdel(BDBCUR *cur) { + assert(cur); + TCFREE(cur); } - /* Move a cursor object to the first record. */ -bool tcbdbcurfirst(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurfirstimpl(cur); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; +bool tcbdbcurfirst(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurfirstimpl(cur); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Move a cursor object to the last record. */ -bool tcbdbcurlast(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurlastimpl(cur); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; +bool tcbdbcurlast(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurlastimpl(cur); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Move a cursor object to the front of records corresponding a key. */ -bool tcbdbcurjump(BDBCUR *cur, const void *kbuf, int ksiz){ - assert(cur && kbuf && ksiz >= 0); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurjumpimpl(cur, kbuf, ksiz, true); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; +bool tcbdbcurjump(BDBCUR *cur, const void *kbuf, int ksiz) { + assert(cur && kbuf && ksiz >= 0); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurjumpimpl(cur, kbuf, ksiz, true); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Move a cursor object to the front of records corresponding a key string. */ -bool tcbdbcurjump2(BDBCUR *cur, const char *kstr){ - assert(cur && kstr); - return tcbdbcurjump(cur, kstr, strlen(kstr)); +bool tcbdbcurjump2(BDBCUR *cur, const char *kstr) { + assert(cur && kstr); + return tcbdbcurjump(cur, kstr, strlen(kstr)); } - /* Move a cursor object to the previous record. */ -bool tcbdbcurprev(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurprevimpl(cur); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; +bool tcbdbcurprev(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurprevimpl(cur); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Move a cursor object to the next record. */ -bool tcbdbcurnext(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurnextimpl(cur); - bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; - BDBUNLOCKMETHOD(bdb); - if(adj && BDBLOCKMETHOD(bdb, true)){ - if(!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; +bool tcbdbcurnext(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurnextimpl(cur); + bool adj = TCMAPRNUM(bdb->leafc) > bdb->lcnum || TCMAPRNUM(bdb->nodec) > bdb->ncnum; BDBUNLOCKMETHOD(bdb); - } - return rv; + if (adj && BDBLOCKMETHOD(bdb, true)) { + if (!bdb->tran && !tcbdbcacheadjust(bdb)) rv = false; + BDBUNLOCKMETHOD(bdb); + } + return rv; } - /* Insert a record around a cursor object. */ -bool tcbdbcurput(BDBCUR *cur, const void *vbuf, int vsiz, int cpmode){ - assert(cur && vbuf && vsiz >= 0); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +bool tcbdbcurput(BDBCUR *cur, const void *vbuf, int vsiz, int cpmode) { + assert(cur && vbuf && vsiz >= 0); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurputimpl(cur, vbuf, vsiz, cpmode); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurputimpl(cur, vbuf, vsiz, cpmode); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Insert a string record around a cursor object. */ -bool tcbdbcurput2(BDBCUR *cur, const char *vstr, int cpmode){ - assert(cur && vstr); - return tcbdbcurput(cur, vstr, strlen(vstr), cpmode); +bool tcbdbcurput2(BDBCUR *cur, const char *vstr, int cpmode) { + assert(cur && vstr); + return tcbdbcurput(cur, vstr, strlen(vstr), cpmode); } - /* Delete the record where a cursor object is. */ -bool tcbdbcurout(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +bool tcbdbcurout(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcuroutimpl(cur); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcuroutimpl(cur); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the key of the record where the cursor object is. */ -void *tcbdbcurkey(BDBCUR *cur, int *sp){ - assert(cur && sp); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +void *tcbdbcurkey(BDBCUR *cur, int *sp) { + assert(cur && sp); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + const char *kbuf, *vbuf; + int ksiz, vsiz; + char *rv; + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + TCMEMDUP(rv, kbuf, ksiz); + *sp = ksiz; + } else { + rv = NULL; + } BDBUNLOCKMETHOD(bdb); - return false; - } - const char *kbuf, *vbuf; - int ksiz, vsiz; - char *rv; - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - TCMEMDUP(rv, kbuf, ksiz); - *sp = ksiz; - } else { - rv = NULL; - } - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the key string of the record where the cursor object is. */ -char *tcbdbcurkey2(BDBCUR *cur){ - assert(cur); - int ksiz; - return tcbdbcurkey(cur, &ksiz); +char *tcbdbcurkey2(BDBCUR *cur) { + assert(cur); + int ksiz; + return tcbdbcurkey(cur, &ksiz); } - /* Get the key of the record where the cursor object is, as a volatile buffer. */ -const void *tcbdbcurkey3(BDBCUR *cur, int *sp){ - assert(cur && sp); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +const void *tcbdbcurkey3(BDBCUR *cur, int *sp) { + assert(cur && sp); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + const char *kbuf, *vbuf; + int ksiz, vsiz; + const char *rv; + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + rv = kbuf; + *sp = ksiz; + } else { + rv = NULL; + } BDBUNLOCKMETHOD(bdb); - return false; - } - const char *kbuf, *vbuf; - int ksiz, vsiz; - const char *rv; - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - rv = kbuf; - *sp = ksiz; - } else { - rv = NULL; - } - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the value of the record where the cursor object is. */ -void *tcbdbcurval(BDBCUR *cur, int *sp){ - assert(cur && sp); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +void *tcbdbcurval(BDBCUR *cur, int *sp) { + assert(cur && sp); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + const char *kbuf, *vbuf; + int ksiz, vsiz; + char *rv; + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + TCMEMDUP(rv, vbuf, vsiz); + *sp = vsiz; + } else { + rv = NULL; + } BDBUNLOCKMETHOD(bdb); - return false; - } - const char *kbuf, *vbuf; - int ksiz, vsiz; - char *rv; - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - TCMEMDUP(rv, vbuf, vsiz); - *sp = vsiz; - } else { - rv = NULL; - } - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the value string of the record where the cursor object is. */ -char *tcbdbcurval2(BDBCUR *cur){ - assert(cur); - int vsiz; - return tcbdbcurval(cur, &vsiz); +char *tcbdbcurval2(BDBCUR *cur) { + assert(cur); + int vsiz; + return tcbdbcurval(cur, &vsiz); } - /* Get the value of the record where the cursor object is, as a volatile buffer. */ -const void *tcbdbcurval3(BDBCUR *cur, int *sp){ - assert(cur && sp); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +const void *tcbdbcurval3(BDBCUR *cur, int *sp) { + assert(cur && sp); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + const char *kbuf, *vbuf; + int ksiz, vsiz; + const char *rv; + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + rv = vbuf; + *sp = vsiz; + } else { + rv = NULL; + } BDBUNLOCKMETHOD(bdb); - return false; - } - const char *kbuf, *vbuf; - int ksiz, vsiz; - const char *rv; - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - rv = vbuf; - *sp = vsiz; - } else { - rv = NULL; - } - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the key and the value of the record where the cursor object is. */ -bool tcbdbcurrec(BDBCUR *cur, TCXSTR *kxstr, TCXSTR *vxstr){ - assert(cur && kxstr && vxstr); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); +bool tcbdbcurrec(BDBCUR *cur, TCXSTR *kxstr, TCXSTR *vxstr) { + assert(cur && kxstr && vxstr); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + const char *kbuf, *vbuf; + int ksiz, vsiz; + bool rv; + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + tcxstrclear(kxstr); + TCXSTRCAT(kxstr, kbuf, ksiz); + tcxstrclear(vxstr); + TCXSTRCAT(vxstr, vbuf, vsiz); + rv = true; + } else { + rv = false; + } BDBUNLOCKMETHOD(bdb); - return false; - } - const char *kbuf, *vbuf; - int ksiz, vsiz; - bool rv; - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - tcxstrclear(kxstr); - TCXSTRCAT(kxstr, kbuf, ksiz); - tcxstrclear(vxstr); - TCXSTRCAT(vxstr, vbuf, vsiz); - rv = true; - } else { - rv = false; - } - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } @@ -1302,398 +1236,367 @@ bool tcbdbcurrec(BDBCUR *cur, TCXSTR *kxstr, TCXSTR *vxstr){ * features for experts *************************************************************************************************/ - /* Set the error code of a B+ tree database object. */ -void tcbdbsetecode(TCBDB *bdb, int ecode, const char *filename, int line, const char *func){ - assert(bdb && filename && line >= 1 && func); - tchdbsetecode(bdb->hdb, ecode, filename, line, func); +void tcbdbsetecode(TCBDB *bdb, int ecode, const char *filename, int line, const char *func) { + assert(bdb && filename && line >= 1 && func); + tchdbsetecode(bdb->hdb, ecode, filename, line, func); } - /* Set the file descriptor for debugging output. */ -void tcbdbsetdbgfd(TCBDB *bdb, HANDLE fd){ - assert(bdb && !INVALIDHANDLE(fd)); - tchdbsetdbgfd(bdb->hdb, fd); +void tcbdbsetdbgfd(TCBDB *bdb, HANDLE fd) { + assert(bdb && !INVALIDHANDLE(fd)); + tchdbsetdbgfd(bdb->hdb, fd); } - /* Get the file descriptor for debugging output. */ -HANDLE tcbdbdbgfd(TCBDB *bdb){ - assert(bdb); - return tchdbdbgfd(bdb->hdb); +HANDLE tcbdbdbgfd(TCBDB *bdb) { + assert(bdb); + return tchdbdbgfd(bdb->hdb); } - /* Check whether mutual exclusion control is set to a B+ tree database object. */ -bool tcbdbhasmutex(TCBDB *bdb){ - assert(bdb); - return bdb->mmtx != NULL; +bool tcbdbhasmutex(TCBDB *bdb) { + assert(bdb); + return bdb->mmtx != NULL; } - /* Synchronize updating contents on memory of a B+ tree database object. */ -bool tcbdbmemsync(TCBDB *bdb, bool phys){ - assert(bdb); - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - bool err = false; - bool clk = BDBLOCKCACHE(bdb); - const char *vbuf; - int vsiz; - TCMAP *leafc = bdb->leafc; - tcmapiterinit(leafc); - while((vbuf = tcmapiternext(leafc, &vsiz)) != NULL){ - int rsiz; - BDBLEAF *leaf = (BDBLEAF *)tcmapiterval(vbuf, &rsiz); - if(leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; - } - TCMAP *nodec = bdb->nodec; - tcmapiterinit(nodec); - while((vbuf = tcmapiternext(nodec, &vsiz)) != NULL){ - int rsiz; - BDBNODE *node = (BDBNODE *)tcmapiterval(vbuf, &rsiz); - if(node->dirty && !tcbdbnodesave(bdb, node)) err = true; - } - if(clk) BDBUNLOCKCACHE(bdb); - tcbdbdumpmeta(bdb); - if(!tchdbmemsync(bdb->hdb, phys)) err = true; - return !err; +bool tcbdbmemsync(TCBDB *bdb, bool phys) { + assert(bdb); + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + bool err = false; + bool clk = BDBLOCKCACHE(bdb); + const char *vbuf; + int vsiz; + TCMAP *leafc = bdb->leafc; + tcmapiterinit(leafc); + while ((vbuf = tcmapiternext(leafc, &vsiz)) != NULL) { + int rsiz; + BDBLEAF *leaf = (BDBLEAF *) tcmapiterval(vbuf, &rsiz); + if (leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; + } + TCMAP *nodec = bdb->nodec; + tcmapiterinit(nodec); + while ((vbuf = tcmapiternext(nodec, &vsiz)) != NULL) { + int rsiz; + BDBNODE *node = (BDBNODE *) tcmapiterval(vbuf, &rsiz); + if (node->dirty && !tcbdbnodesave(bdb, node)) err = true; + } + if (clk) BDBUNLOCKCACHE(bdb); + tcbdbdumpmeta(bdb); + if (!tchdbmemsync(bdb->hdb, phys)) err = true; + return !err; } - /* Get the comparison function of a B+ tree database object. */ -TCCMP tcbdbcmpfunc(TCBDB *bdb){ - assert(bdb); - return bdb->cmp; +TCCMP tcbdbcmpfunc(TCBDB *bdb) { + assert(bdb); + return bdb->cmp; } - /* Get the opaque object for the comparison function of a B+ tree database object. */ -void *tcbdbcmpop(TCBDB *bdb){ - assert(bdb); - return bdb->cmpop; +void *tcbdbcmpop(TCBDB *bdb) { + assert(bdb); + return bdb->cmpop; } - /* Get the maximum number of cached leaf nodes of a B+ tree database object. */ -uint32_t tcbdblmemb(TCBDB *bdb){ - assert(bdb); - return bdb->lmemb; +uint32_t tcbdblmemb(TCBDB *bdb) { + assert(bdb); + return bdb->lmemb; } - /* Get the maximum number of cached non-leaf nodes of a B+ tree database object. */ -uint32_t tcbdbnmemb(TCBDB *bdb){ - assert(bdb); - return bdb->nmemb; +uint32_t tcbdbnmemb(TCBDB *bdb) { + assert(bdb); + return bdb->nmemb; } - /* Get the number of the leaf nodes of B+ tree database object. */ -uint64_t tcbdblnum(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return bdb->lnum; +uint64_t tcbdblnum(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return bdb->lnum; } - /* Get the number of the non-leaf nodes of B+ tree database object. */ -uint64_t tcbdbnnum(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return bdb->nnum; +uint64_t tcbdbnnum(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return bdb->nnum; } - /* Get the number of elements of the bucket array of a B+ tree database object. */ -uint64_t tcbdbbnum(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbbnum(bdb->hdb); +uint64_t tcbdbbnum(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbbnum(bdb->hdb); } - /* Get the record alignment of a B+ tree database object. */ -uint32_t tcbdbalign(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbalign(bdb->hdb); +uint32_t tcbdbalign(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbalign(bdb->hdb); } - /* Get the maximum number of the free block pool of a B+ tree database object. */ -uint32_t tcbdbfbpmax(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbfbpmax(bdb->hdb); +uint32_t tcbdbfbpmax(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbfbpmax(bdb->hdb); } - /* Get the inode number of the database file of a B+ tree database object. */ -uint64_t tcbdbinode(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbinode(bdb->hdb); +uint64_t tcbdbinode(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbinode(bdb->hdb); } - /* Get the modification time of the database file of a B+ tree database object. */ -time_t tcbdbmtime(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbmtime(bdb->hdb); +time_t tcbdbmtime(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbmtime(bdb->hdb); } - /* Get the additional flags of a B+ tree database object. */ -uint8_t tcbdbflags(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbflags(bdb->hdb); +uint8_t tcbdbflags(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbflags(bdb->hdb); } - /* Get the options of a B+ tree database object. */ -uint8_t tcbdbopts(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return bdb->opts; +uint8_t tcbdbopts(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return bdb->opts; } - /* Get the number of used elements of the bucket array of a B+ tree database object. */ -uint64_t tcbdbbnumused(TCBDB *bdb){ - assert(bdb); - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return tchdbbnumused(bdb->hdb); +uint64_t tcbdbbnumused(TCBDB *bdb) { + assert(bdb); + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return tchdbbnumused(bdb->hdb); } - /* Set the maximum size of each leaf node. */ -bool tcbdbsetlsmax(TCBDB *bdb, uint32_t lsmax){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - bdb->lsmax = (lsmax > 0) ? tclmax(lsmax, BDBMINLSMAX) : BDBDEFLSMAX; - return true; +bool tcbdbsetlsmax(TCBDB *bdb, uint32_t lsmax) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + bdb->lsmax = (lsmax > 0) ? tclmax(lsmax, BDBMINLSMAX) : BDBDEFLSMAX; + return true; } - /* Set the capacity number of records. */ -bool tcbdbsetcapnum(TCBDB *bdb, uint64_t capnum){ - assert(bdb); - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - bdb->capnum = capnum; - return true; +bool tcbdbsetcapnum(TCBDB *bdb, uint64_t capnum) { + assert(bdb); + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + bdb->capnum = capnum; + return true; } - /* Set the custom codec functions of a B+ tree database object. */ -bool tcbdbsetcodecfunc(TCBDB *bdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop){ - assert(bdb && enc && dec); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbsetcodecfunc(TCBDB *bdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop) { + assert(bdb && enc && dec); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tchdbsetcodecfunc(bdb->hdb, enc, encop, dec, decop); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tchdbsetcodecfunc(bdb->hdb, enc, encop, dec, decop); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Get the unit step number of auto defragmentation of a B+ tree database object. */ -uint32_t tcbdbdfunit(TCBDB *bdb){ - assert(bdb); - return tchdbdfunit(bdb->hdb); +uint32_t tcbdbdfunit(TCBDB *bdb) { + assert(bdb); + return tchdbdfunit(bdb->hdb); } - /* Perform dynamic defragmentation of a B+ tree database object. */ -bool tcbdbdefrag(TCBDB *bdb, int64_t step){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbdefrag(TCBDB *bdb, int64_t step) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tchdbdefrag(bdb->hdb, step); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tchdbdefrag(bdb->hdb, step); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Clear the cache of a B+ tree database object. */ -bool tcbdbcacheclear(TCBDB *bdb){ - assert(bdb); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - BDBUNLOCKMETHOD(bdb); - return false; - } - BDBTHREADYIELD(bdb); - bool err = false; - bool tran = bdb->tran; - if(TCMAPRNUM(bdb->leafc) > 0){ - bool clk = BDBLOCKCACHE(bdb); - TCMAP *leafc = bdb->leafc; - tcmapiterinit(leafc); - int rsiz; - const void *buf; - while((buf = tcmapiternext(leafc, &rsiz)) != NULL){ - BDBLEAF *leaf = (BDBLEAF *)tcmapiterval(buf, &rsiz); - if(!(tran && leaf->dirty) && !tcbdbleafcacheout(bdb, leaf)) err = true; - } - if(clk) BDBUNLOCKCACHE(bdb); - } - if(TCMAPRNUM(bdb->nodec) > 0){ - bool clk = BDBLOCKCACHE(bdb); - TCMAP *nodec = bdb->nodec; - tcmapiterinit(nodec); - int rsiz; - const void *buf; - while((buf = tcmapiternext(nodec, &rsiz)) != NULL){ - BDBNODE *node = (BDBNODE *)tcmapiterval(buf, &rsiz); - if(!(tran && node->dirty) && !tcbdbnodecacheout(bdb, node)) err = true; +bool tcbdbcacheclear(TCBDB *bdb) { + assert(bdb); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBTHREADYIELD(bdb); + bool err = false; + bool tran = bdb->tran; + if (TCMAPRNUM(bdb->leafc) > 0) { + bool clk = BDBLOCKCACHE(bdb); + TCMAP *leafc = bdb->leafc; + tcmapiterinit(leafc); + int rsiz; + const void *buf; + while ((buf = tcmapiternext(leafc, &rsiz)) != NULL) { + BDBLEAF *leaf = (BDBLEAF *) tcmapiterval(buf, &rsiz); + if (!(tran && leaf->dirty) && !tcbdbleafcacheout(bdb, leaf)) err = true; + } + if (clk) BDBUNLOCKCACHE(bdb); + } + if (TCMAPRNUM(bdb->nodec) > 0) { + bool clk = BDBLOCKCACHE(bdb); + TCMAP *nodec = bdb->nodec; + tcmapiterinit(nodec); + int rsiz; + const void *buf; + while ((buf = tcmapiternext(nodec, &rsiz)) != NULL) { + BDBNODE *node = (BDBNODE *) tcmapiterval(buf, &rsiz); + if (!(tran && node->dirty) && !tcbdbnodecacheout(bdb, node)) err = true; + } + if (clk) BDBUNLOCKCACHE(bdb); } - if(clk) BDBUNLOCKCACHE(bdb); - } - BDBUNLOCKMETHOD(bdb); - return !err; + BDBUNLOCKMETHOD(bdb); + return !err; } - /* Store a new record into a B+ tree database object with backward duplication. */ -bool tcbdbputdupback(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbputdupback(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(bdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUPB); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDDUPB); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a record into a B+ tree database object with a duplication handler. */ bool tcbdbputproc(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - TCPDPROC proc, void *op){ - assert(bdb && kbuf && ksiz >= 0 && proc); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open || !bdb->wmode){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + TCPDPROC proc, void *op) { + assert(bdb && kbuf && ksiz >= 0 && proc); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open || !bdb->wmode) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBPDPROCOP procop; + procop.proc = proc; + procop.op = op; + BDBPDPROCOP *procptr = &procop; + tcgeneric_t stack[(TCNUMBUFSIZ * 2) / sizeof (tcgeneric_t) + 1]; + char *rbuf; + if (ksiz <= sizeof (stack) - sizeof (procptr)) { + rbuf = (char *) stack; + } else { + TCMALLOC(rbuf, ksiz + sizeof (procptr)); + } + char *wp = rbuf; + memcpy(wp, &procptr, sizeof (procptr)); + wp += sizeof (procptr); + memcpy(wp, kbuf, ksiz); + kbuf = rbuf + sizeof (procptr); + bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDPROC); + if (rbuf != (char *) stack) TCFREE(rbuf); BDBUNLOCKMETHOD(bdb); - return false; - } - BDBPDPROCOP procop; - procop.proc = proc; - procop.op = op; - BDBPDPROCOP *procptr = &procop; - tcgeneric_t stack[(TCNUMBUFSIZ*2)/sizeof(tcgeneric_t)+1]; - char *rbuf; - if(ksiz <= sizeof(stack) - sizeof(procptr)){ - rbuf = (char *)stack; - } else { - TCMALLOC(rbuf, ksiz + sizeof(procptr)); - } - char *wp = rbuf; - memcpy(wp, &procptr, sizeof(procptr)); - wp += sizeof(procptr); - memcpy(wp, kbuf, ksiz); - kbuf = rbuf + sizeof(procptr); - bool rv = tcbdbputimpl(bdb, kbuf, ksiz, vbuf, vsiz, BDBPDPROC); - if(rbuf != (char *)stack) TCFREE(rbuf); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Store a new string record into a B+ tree database object with backward duplication. */ -bool tcbdbputdupback2(TCBDB *bdb, const char *kstr, const char *vstr){ - assert(bdb && kstr && vstr); - return tcbdbputdupback(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tcbdbputdupback2(TCBDB *bdb, const char *kstr, const char *vstr) { + assert(bdb && kstr && vstr); + return tcbdbputdupback(bdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Move a cursor object to the rear of records corresponding a key. */ -bool tcbdbcurjumpback(BDBCUR *cur, const void *kbuf, int ksiz){ - assert(cur && kbuf && ksiz >= 0); - TCBDB *bdb = cur->bdb; - if(!BDBLOCKMETHOD(bdb, false)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbcurjumpback(BDBCUR *cur, const void *kbuf, int ksiz) { + assert(cur && kbuf && ksiz >= 0); + TCBDB *bdb = cur->bdb; + if (!BDBLOCKMETHOD(bdb, false)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + bool rv = tcbdbcurjumpimpl(cur, kbuf, ksiz, false); BDBUNLOCKMETHOD(bdb); - return false; - } - bool rv = tcbdbcurjumpimpl(cur, kbuf, ksiz, false); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } - /* Move a cursor object to the rear of records corresponding a key string. */ -bool tcbdbcurjumpback2(BDBCUR *cur, const char *kstr){ - assert(cur && kstr); - return tcbdbcurjumpback(cur, kstr, strlen(kstr)); +bool tcbdbcurjumpback2(BDBCUR *cur, const char *kstr) { + assert(cur && kstr); + return tcbdbcurjumpback(cur, kstr, strlen(kstr)); } - /* Process each record atomically of a B+ tree database object. */ -bool tcbdbforeach(TCBDB *bdb, TCITER iter, void *op){ - assert(bdb && iter); - if(!BDBLOCKMETHOD(bdb, true)) return false; - if(!bdb->open){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcbdbforeach(TCBDB *bdb, TCITER iter, void *op) { + assert(bdb && iter); + if (!BDBLOCKMETHOD(bdb, true)) return false; + if (!bdb->open) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + BDBUNLOCKMETHOD(bdb); + return false; + } + BDBTHREADYIELD(bdb); + bool rv = tcbdbforeachimpl(bdb, iter, op); BDBUNLOCKMETHOD(bdb); - return false; - } - BDBTHREADYIELD(bdb); - bool rv = tcbdbforeachimpl(bdb, iter, op); - BDBUNLOCKMETHOD(bdb); - return rv; + return rv; } @@ -1702,440 +1605,430 @@ bool tcbdbforeach(TCBDB *bdb, TCITER iter, void *op){ * private features *************************************************************************************************/ - /* Clear all members. `bdb' specifies the B+ tree database object. */ -static void tcbdbclear(TCBDB *bdb){ - assert(bdb); - bdb->mmtx = NULL; - bdb->cmtx = NULL; - bdb->hdb = NULL; - bdb->open = false; - bdb->wmode = false; - bdb->lmemb = BDBDEFLMEMB; - bdb->nmemb = BDBDEFNMEMB; - bdb->opts = 0; - bdb->root = 0; - bdb->first = 0; - bdb->last = 0; - bdb->lnum = 0; - bdb->nnum = 0; - bdb->rnum = 0; - bdb->leafc = NULL; - bdb->nodec = NULL; - bdb->cmp = NULL; - bdb->cmpop = NULL; - bdb->lcnum = BDBDEFLCNUM; - bdb->ncnum = BDBDEFNCNUM; - bdb->lsmax = BDBDEFLSMAX; - bdb->lschk = 0; - bdb->capnum = 0; - bdb->hist = NULL; - bdb->hnum = 0; - bdb->hleaf = 0; - bdb->lleaf = 0; - bdb->tran = false; - bdb->rbopaque = NULL; - bdb->clock = 0; - bdb->cnt_saveleaf = -1; - bdb->cnt_loadleaf = -1; - bdb->cnt_killleaf = -1; - bdb->cnt_adjleafc = -1; - bdb->cnt_savenode = -1; - bdb->cnt_loadnode = -1; - bdb->cnt_adjnodec = -1; - TCDODEBUG(bdb->cnt_saveleaf = 0); - TCDODEBUG(bdb->cnt_loadleaf = 0); - TCDODEBUG(bdb->cnt_killleaf = 0); - TCDODEBUG(bdb->cnt_adjleafc = 0); - TCDODEBUG(bdb->cnt_savenode = 0); - TCDODEBUG(bdb->cnt_loadnode = 0); - TCDODEBUG(bdb->cnt_adjnodec = 0); +static void tcbdbclear(TCBDB *bdb) { + assert(bdb); + bdb->mmtx = NULL; + bdb->cmtx = NULL; + bdb->hdb = NULL; + bdb->open = false; + bdb->wmode = false; + bdb->lmemb = BDBDEFLMEMB; + bdb->nmemb = BDBDEFNMEMB; + bdb->opts = 0; + bdb->root = 0; + bdb->first = 0; + bdb->last = 0; + bdb->lnum = 0; + bdb->nnum = 0; + bdb->rnum = 0; + bdb->leafc = NULL; + bdb->nodec = NULL; + bdb->cmp = NULL; + bdb->cmpop = NULL; + bdb->lcnum = BDBDEFLCNUM; + bdb->ncnum = BDBDEFNCNUM; + bdb->lsmax = BDBDEFLSMAX; + bdb->lschk = 0; + bdb->capnum = 0; + bdb->hist = NULL; + bdb->hnum = 0; + bdb->hleaf = 0; + bdb->lleaf = 0; + bdb->tran = false; + bdb->rbopaque = NULL; + bdb->clock = 0; + bdb->cnt_saveleaf = -1; + bdb->cnt_loadleaf = -1; + bdb->cnt_killleaf = -1; + bdb->cnt_adjleafc = -1; + bdb->cnt_savenode = -1; + bdb->cnt_loadnode = -1; + bdb->cnt_adjnodec = -1; + TCDODEBUG(bdb->cnt_saveleaf = 0); + TCDODEBUG(bdb->cnt_loadleaf = 0); + TCDODEBUG(bdb->cnt_killleaf = 0); + TCDODEBUG(bdb->cnt_adjleafc = 0); + TCDODEBUG(bdb->cnt_savenode = 0); + TCDODEBUG(bdb->cnt_loadnode = 0); + TCDODEBUG(bdb->cnt_adjnodec = 0); } - /* Serialize meta data into the opaque field. `bdb' specifies the B+ tree database object. */ -static void tcbdbdumpmeta(TCBDB *bdb){ - assert(bdb); - char odata[BDBOPAQUESIZ]; - memset(odata, 0, BDBOPAQUESIZ); - char *wp = odata; - if(bdb->cmp == tccmplexical){ - *(uint8_t *)(wp++) = 0x0; - } else if(bdb->cmp == tccmpdecimal){ - *(uint8_t *)(wp++) = 0x1; - } else if(bdb->cmp == tccmpint32){ - *(uint8_t *)(wp++) = 0x2; - } else if(bdb->cmp == tccmpint64){ - *(uint8_t *)(wp++) = 0x3; - } else { - *(uint8_t *)(wp++) = 0xff; - } - wp += 7; - uint32_t lnum; - lnum = bdb->lmemb; - lnum = TCHTOIL(lnum); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - lnum = bdb->nmemb; - lnum = TCHTOIL(lnum); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - uint64_t llnum; - llnum = bdb->root; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = bdb->first; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = bdb->last; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = bdb->lnum; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = bdb->nnum; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = bdb->rnum; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - tchdbwriteopaque(bdb->hdb, odata, 0, BDBOPAQUESIZ); +static void tcbdbdumpmeta(TCBDB *bdb) { + assert(bdb); + char odata[BDBOPAQUESIZ]; + memset(odata, 0, BDBOPAQUESIZ); + char *wp = odata; + if (bdb->cmp == tccmplexical) { + *(uint8_t *) (wp++) = 0x0; + } else if (bdb->cmp == tccmpdecimal) { + *(uint8_t *) (wp++) = 0x1; + } else if (bdb->cmp == tccmpint32) { + *(uint8_t *) (wp++) = 0x2; + } else if (bdb->cmp == tccmpint64) { + *(uint8_t *) (wp++) = 0x3; + } else { + *(uint8_t *) (wp++) = 0xff; + } + wp += 7; + uint32_t lnum; + lnum = bdb->lmemb; + lnum = TCHTOIL(lnum); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + lnum = bdb->nmemb; + lnum = TCHTOIL(lnum); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + uint64_t llnum; + llnum = bdb->root; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = bdb->first; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = bdb->last; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = bdb->lnum; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = bdb->nnum; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = bdb->rnum; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + tchdbwriteopaque(bdb->hdb, odata, 0, BDBOPAQUESIZ); } - /* Deserialize meta data from the opaque field. `bdb' specifies the B+ tree database object. */ -static void tcbdbloadmeta(TCBDB *bdb){ - char odata[BDBOPAQUESIZ]; - tchdbreadopaque(bdb->hdb, odata, 0, BDBOPAQUESIZ); - const char *rp = odata; - uint8_t cnum = *(uint8_t *)(rp++); - if(cnum == 0x0){ - bdb->cmp = tccmplexical; - } else if(cnum == 0x1){ - bdb->cmp = tccmpdecimal; - } else if(cnum == 0x2){ - bdb->cmp = tccmpint32; - } else if(cnum == 0x3){ - bdb->cmp = tccmpint64; - } - rp += 7; - uint32_t lnum; - memcpy(&lnum, rp, sizeof(lnum)); - rp += sizeof(lnum); - bdb->lmemb = TCITOHL(lnum); - memcpy(&lnum, rp, sizeof(lnum)); - rp += sizeof(lnum); - bdb->nmemb = TCITOHL(lnum); - uint64_t llnum; - memcpy(&llnum, rp, sizeof(llnum)); - bdb->root = TCITOHLL(llnum); - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - bdb->first = TCITOHLL(llnum); - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - bdb->last = TCITOHLL(llnum); - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - bdb->lnum = TCITOHLL(llnum); - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - bdb->nnum = TCITOHLL(llnum); - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - bdb->rnum = TCITOHLL(llnum); - rp += sizeof(llnum); +static void tcbdbloadmeta(TCBDB *bdb) { + char odata[BDBOPAQUESIZ]; + tchdbreadopaque(bdb->hdb, odata, 0, BDBOPAQUESIZ); + const char *rp = odata; + uint8_t cnum = *(uint8_t *) (rp++); + if (cnum == 0x0) { + bdb->cmp = tccmplexical; + } else if (cnum == 0x1) { + bdb->cmp = tccmpdecimal; + } else if (cnum == 0x2) { + bdb->cmp = tccmpint32; + } else if (cnum == 0x3) { + bdb->cmp = tccmpint64; + } + rp += 7; + uint32_t lnum; + memcpy(&lnum, rp, sizeof (lnum)); + rp += sizeof (lnum); + bdb->lmemb = TCITOHL(lnum); + memcpy(&lnum, rp, sizeof (lnum)); + rp += sizeof (lnum); + bdb->nmemb = TCITOHL(lnum); + uint64_t llnum; + memcpy(&llnum, rp, sizeof (llnum)); + bdb->root = TCITOHLL(llnum); + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + bdb->first = TCITOHLL(llnum); + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + bdb->last = TCITOHLL(llnum); + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + bdb->lnum = TCITOHLL(llnum); + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + bdb->nnum = TCITOHLL(llnum); + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + bdb->rnum = TCITOHLL(llnum); + rp += sizeof (llnum); } - /* Create a new leaf. `bdb' specifies the B+ tree database object. `prev' specifies the ID number of the previous leaf. `next' specifies the ID number of the next leaf. The return value is the new leaf object. */ -static BDBLEAF *tcbdbleafnew(TCBDB *bdb, uint64_t prev, uint64_t next){ - assert(bdb); - BDBLEAF lent; - lent.id = ++bdb->lnum; - lent.recs = tcptrlistnew2(bdb->lmemb + 1); - lent.size = 0; - lent.prev = prev; - lent.next = next; - lent.dirty = true; - lent.dead = false; - tcmapputkeep(bdb->leafc, &(lent.id), sizeof(lent.id), &lent, sizeof(lent)); - int rsiz; - return (BDBLEAF *)tcmapget(bdb->leafc, &(lent.id), sizeof(lent.id), &rsiz); +static BDBLEAF *tcbdbleafnew(TCBDB *bdb, uint64_t prev, uint64_t next) { + assert(bdb); + BDBLEAF lent; + lent.id = ++bdb->lnum; + lent.recs = tcptrlistnew2(bdb->lmemb + 1); + lent.size = 0; + lent.prev = prev; + lent.next = next; + lent.dirty = true; + lent.dead = false; + tcmapputkeep(bdb->leafc, &(lent.id), sizeof (lent.id), &lent, sizeof (lent)); + int rsiz; + return (BDBLEAF *) tcmapget(bdb->leafc, &(lent.id), sizeof (lent.id), &rsiz); } - /* Remove a leaf from the cache. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. If successful, the return value is true, else, it is false. */ -static bool tcbdbleafcacheout(TCBDB *bdb, BDBLEAF *leaf){ - assert(bdb && leaf); - bool err = false; - if(leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; - TCPTRLIST *recs = leaf->recs; - int ln = TCPTRLISTNUM(recs); - for(int i = 0; i < ln; i++){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - if(rec->rest) tclistdel(rec->rest); - TCFREE(rec); - } - tcptrlistdel(recs); - tcmapout(bdb->leafc, &(leaf->id), sizeof(leaf->id)); - return !err; +static bool tcbdbleafcacheout(TCBDB *bdb, BDBLEAF *leaf) { + assert(bdb && leaf); + bool err = false; + if (leaf->dirty && !tcbdbleafsave(bdb, leaf)) err = true; + TCPTRLIST *recs = leaf->recs; + int ln = TCPTRLISTNUM(recs); + for (int i = 0; i < ln; i++) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + if (rec->rest) tclistdel(rec->rest); + TCFREE(rec); + } + tcptrlistdel(recs); + tcmapout(bdb->leafc, &(leaf->id), sizeof (leaf->id)); + return !err; } - /* Save a leaf into the internal database. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. If successful, the return value is true, else, it is false. */ -static bool tcbdbleafsave(TCBDB *bdb, BDBLEAF *leaf){ - assert(bdb && leaf); - TCDODEBUG(bdb->cnt_saveleaf++); - TCXSTR *rbuf = tcxstrnew3(BDBPAGEBUFSIZ); - char hbuf[(sizeof(uint64_t)+1)*3]; - char *wp = hbuf; - uint64_t llnum; - int step; - llnum = leaf->prev; - TCSETVNUMBUF64(step, wp, llnum); - wp += step; - llnum = leaf->next; - TCSETVNUMBUF64(step, wp, llnum); - wp += step; - TCXSTRCAT(rbuf, hbuf, wp - hbuf); - TCPTRLIST *recs = leaf->recs; - int ln = TCPTRLISTNUM(recs); - for(int i = 0; i < ln; i++){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - char *dbuf = (char *)rec + sizeof(*rec); - int lnum; - wp = hbuf; - lnum = rec->ksiz; - TCSETVNUMBUF(step, wp, lnum); - wp += step; - lnum = rec->vsiz; - TCSETVNUMBUF(step, wp, lnum); +static bool tcbdbleafsave(TCBDB *bdb, BDBLEAF *leaf) { + assert(bdb && leaf); + TCDODEBUG(bdb->cnt_saveleaf++); + TCXSTR *rbuf = tcxstrnew3(BDBPAGEBUFSIZ); + char hbuf[(sizeof (uint64_t) + 1)*3]; + char *wp = hbuf; + uint64_t llnum; + int step; + llnum = leaf->prev; + TCSETVNUMBUF64(step, wp, llnum); wp += step; - TCLIST *rest = rec->rest; - int rnum = rest ? TCLISTNUM(rest) : 0; - TCSETVNUMBUF(step, wp, rnum); + llnum = leaf->next; + TCSETVNUMBUF64(step, wp, llnum); wp += step; TCXSTRCAT(rbuf, hbuf, wp - hbuf); - TCXSTRCAT(rbuf, dbuf, rec->ksiz); - TCXSTRCAT(rbuf, dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); - for(int j = 0; j < rnum; j++){ - const char *vbuf; - int vsiz; - TCLISTVAL(vbuf, rest, j, vsiz); - TCSETVNUMBUF(step, hbuf, vsiz); - TCXSTRCAT(rbuf, hbuf, step); - TCXSTRCAT(rbuf, vbuf, vsiz); - } - } - bool err = false; - step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long)leaf->id); - if(ln < 1 && !tchdbout(bdb->hdb, hbuf, step) && tchdbecode(bdb->hdb) != TCENOREC) - err = true; - if(!leaf->dead && !tchdbput(bdb->hdb, hbuf, step, TCXSTRPTR(rbuf), TCXSTRSIZE(rbuf))) - err = true; - tcxstrdel(rbuf); - leaf->dirty = false; - leaf->dead = false; - return !err; + TCPTRLIST *recs = leaf->recs; + int ln = TCPTRLISTNUM(recs); + for (int i = 0; i < ln; i++) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + char *dbuf = (char *) rec + sizeof (*rec); + int lnum; + wp = hbuf; + lnum = rec->ksiz; + TCSETVNUMBUF(step, wp, lnum); + wp += step; + lnum = rec->vsiz; + TCSETVNUMBUF(step, wp, lnum); + wp += step; + TCLIST *rest = rec->rest; + int rnum = rest ? TCLISTNUM(rest) : 0; + TCSETVNUMBUF(step, wp, rnum); + wp += step; + TCXSTRCAT(rbuf, hbuf, wp - hbuf); + TCXSTRCAT(rbuf, dbuf, rec->ksiz); + TCXSTRCAT(rbuf, dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); + for (int j = 0; j < rnum; j++) { + const char *vbuf; + int vsiz; + TCLISTVAL(vbuf, rest, j, vsiz); + TCSETVNUMBUF(step, hbuf, vsiz); + TCXSTRCAT(rbuf, hbuf, step); + TCXSTRCAT(rbuf, vbuf, vsiz); + } + } + bool err = false; + step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long) leaf->id); + if (ln < 1 && !tchdbout(bdb->hdb, hbuf, step) && tchdbecode(bdb->hdb) != TCENOREC) + err = true; + if (!leaf->dead && !tchdbput(bdb->hdb, hbuf, step, TCXSTRPTR(rbuf), TCXSTRSIZE(rbuf))) + err = true; + tcxstrdel(rbuf); + leaf->dirty = false; + leaf->dead = false; + return !err; } - /* Load a leaf from the internal database. `bdb' specifies the B+ tree database object. `id' specifies the ID number of the leaf. The return value is the leaf object or `NULL' on failure. */ -static BDBLEAF *tcbdbleafload(TCBDB *bdb, uint64_t id){ - assert(bdb && id > 0); - bool clk = BDBLOCKCACHE(bdb); - int rsiz; - BDBLEAF *leaf = (BDBLEAF *)tcmapget3(bdb->leafc, &id, sizeof(id), &rsiz); - if(leaf){ - if(clk) BDBUNLOCKCACHE(bdb); - return leaf; - } - if(clk) BDBUNLOCKCACHE(bdb); - TCDODEBUG(bdb->cnt_loadleaf++); - char hbuf[(sizeof(uint64_t)+1)*3]; - int step; - step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long)id); - char *rbuf = NULL; - char wbuf[BDBPAGEBUFSIZ]; - const char *rp = NULL; - rsiz = tchdbget3(bdb->hdb, hbuf, step, wbuf, BDBPAGEBUFSIZ); - if(rsiz < 1){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return false; - } else if(rsiz < BDBPAGEBUFSIZ){ - rp = wbuf; - } else { - if(!(rbuf = tchdbget(bdb->hdb, hbuf, step, &rsiz))){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return false; - } - rp = rbuf; - } - BDBLEAF lent; - lent.id = id; - uint64_t llnum; - TCREADVNUMBUF64(rp, llnum, step); - lent.prev = llnum; - rp += step; - rsiz -= step; - TCREADVNUMBUF64(rp, llnum, step); - lent.next = llnum; - rp += step; - rsiz -= step; - lent.dirty = false; - lent.dead = false; - lent.recs = tcptrlistnew2(bdb->lmemb + 1); - lent.size = 0; - bool err = false; - while(rsiz >= 3){ - int ksiz; - TCREADVNUMBUF(rp, ksiz, step); - rp += step; - rsiz -= step; - int vsiz; - TCREADVNUMBUF(rp, vsiz, step); +static BDBLEAF *tcbdbleafload(TCBDB *bdb, uint64_t id) { + assert(bdb && id > 0); + bool clk = BDBLOCKCACHE(bdb); + int rsiz; + BDBLEAF *leaf = (BDBLEAF *) tcmapget3(bdb->leafc, &id, sizeof (id), &rsiz); + if (leaf) { + if (clk) BDBUNLOCKCACHE(bdb); + return leaf; + } + if (clk) BDBUNLOCKCACHE(bdb); + TCDODEBUG(bdb->cnt_loadleaf++); + char hbuf[(sizeof (uint64_t) + 1)*3]; + int step; + step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long) id); + char *rbuf = NULL; + char wbuf[BDBPAGEBUFSIZ]; + const char *rp = NULL; + rsiz = tchdbget3(bdb->hdb, hbuf, step, wbuf, BDBPAGEBUFSIZ); + if (rsiz < 1) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return false; + } else if (rsiz < BDBPAGEBUFSIZ) { + rp = wbuf; + } else { + if (!(rbuf = tchdbget(bdb->hdb, hbuf, step, &rsiz))) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return false; + } + rp = rbuf; + } + BDBLEAF lent; + lent.id = id; + uint64_t llnum; + TCREADVNUMBUF64(rp, llnum, step); + lent.prev = llnum; rp += step; rsiz -= step; - int rnum; - TCREADVNUMBUF(rp, rnum, step); + TCREADVNUMBUF64(rp, llnum, step); + lent.next = llnum; rp += step; rsiz -= step; - if(rsiz < ksiz + vsiz + rnum){ - err = true; - break; - } - int psiz = TCALIGNPAD(ksiz); - BDBREC *nrec; - TCMALLOC(nrec, sizeof(*nrec) + ksiz + psiz + vsiz + 1); - char *dbuf = (char *)nrec + sizeof(*nrec); - memcpy(dbuf, rp, ksiz); - dbuf[ksiz] = '\0'; - nrec->ksiz = ksiz; - rp += ksiz; - rsiz -= ksiz; - memcpy(dbuf + ksiz + psiz, rp, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - nrec->vsiz = vsiz; - rp += vsiz; - rsiz -= vsiz; - lent.size += ksiz; - lent.size += vsiz; - if(rnum > 0){ - nrec->rest = tclistnew2(rnum); - while(rnum-- > 0 && rsiz > 0){ + lent.dirty = false; + lent.dead = false; + lent.recs = tcptrlistnew2(bdb->lmemb + 1); + lent.size = 0; + bool err = false; + while (rsiz >= 3) { + int ksiz; + TCREADVNUMBUF(rp, ksiz, step); + rp += step; + rsiz -= step; + int vsiz; TCREADVNUMBUF(rp, vsiz, step); rp += step; rsiz -= step; - if(rsiz < vsiz){ - err = true; - break; + int rnum; + TCREADVNUMBUF(rp, rnum, step); + rp += step; + rsiz -= step; + if (rsiz < ksiz + vsiz + rnum) { + err = true; + break; } - TCLISTPUSH(nrec->rest, rp, vsiz); + int psiz = TCALIGNPAD(ksiz); + BDBREC *nrec; + TCMALLOC(nrec, sizeof (*nrec) + ksiz + psiz + vsiz + 1); + char *dbuf = (char *) nrec + sizeof (*nrec); + memcpy(dbuf, rp, ksiz); + dbuf[ksiz] = '\0'; + nrec->ksiz = ksiz; + rp += ksiz; + rsiz -= ksiz; + memcpy(dbuf + ksiz + psiz, rp, vsiz); + dbuf[ksiz + psiz + vsiz] = '\0'; + nrec->vsiz = vsiz; rp += vsiz; rsiz -= vsiz; + lent.size += ksiz; lent.size += vsiz; - } - } else { - nrec->rest = NULL; + if (rnum > 0) { + nrec->rest = tclistnew2(rnum); + while (rnum-- > 0 && rsiz > 0) { + TCREADVNUMBUF(rp, vsiz, step); + rp += step; + rsiz -= step; + if (rsiz < vsiz) { + err = true; + break; + } + TCLISTPUSH(nrec->rest, rp, vsiz); + rp += vsiz; + rsiz -= vsiz; + lent.size += vsiz; + } + } else { + nrec->rest = NULL; + } + TCPTRLISTPUSH(lent.recs, nrec); } - TCPTRLISTPUSH(lent.recs, nrec); - } - TCFREE(rbuf); - if(err || rsiz != 0){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return NULL; - } - clk = BDBLOCKCACHE(bdb); - if(!tcmapputkeep(bdb->leafc, &(lent.id), sizeof(lent.id), &lent, sizeof(lent))){ - int ln = TCPTRLISTNUM(lent.recs); - for(int i = 0; i < ln; i++){ - BDBREC *rec = TCPTRLISTVAL(lent.recs, i); - if(rec->rest) tclistdel(rec->rest); - TCFREE(rec); + TCFREE(rbuf); + if (err || rsiz != 0) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return NULL; + } + clk = BDBLOCKCACHE(bdb); + if (!tcmapputkeep(bdb->leafc, &(lent.id), sizeof (lent.id), &lent, sizeof (lent))) { + int ln = TCPTRLISTNUM(lent.recs); + for (int i = 0; i < ln; i++) { + BDBREC *rec = TCPTRLISTVAL(lent.recs, i); + if (rec->rest) tclistdel(rec->rest); + TCFREE(rec); + } + tcptrlistdel(lent.recs); } - tcptrlistdel(lent.recs); - } - leaf = (BDBLEAF *)tcmapget(bdb->leafc, &(lent.id), sizeof(lent.id), &rsiz); - if(clk) BDBUNLOCKCACHE(bdb); - return leaf; + leaf = (BDBLEAF *) tcmapget(bdb->leafc, &(lent.id), sizeof (lent.id), &rsiz); + if (clk) BDBUNLOCKCACHE(bdb); + return leaf; } - /* Check existence of a leaf in the internal database. `bdb' specifies the B+ tree database object. `id' specifies the ID number of the leaf. The return value is true if the leaf exists, else, it is false. */ -static bool tcbdbleafcheck(TCBDB *bdb, uint64_t id){ - assert(bdb && id > 0); - bool clk = BDBLOCKCACHE(bdb); - int rsiz; - BDBLEAF *leaf = (BDBLEAF *)tcmapget(bdb->leafc, &id, sizeof(id), &rsiz); - if(clk) BDBUNLOCKCACHE(bdb); - if(leaf) return true; - char hbuf[(sizeof(uint64_t)+1)*3]; - int step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long)id); - return tchdbvsiz(bdb->hdb, hbuf, step) > 0; +static bool tcbdbleafcheck(TCBDB *bdb, uint64_t id) { + assert(bdb && id > 0); + bool clk = BDBLOCKCACHE(bdb); + int rsiz; + BDBLEAF *leaf = (BDBLEAF *) tcmapget(bdb->leafc, &id, sizeof (id), &rsiz); + if (clk) BDBUNLOCKCACHE(bdb); + if (leaf) return true; + char hbuf[(sizeof (uint64_t) + 1)*3]; + int step = sprintf(hbuf, "%" PRIxMAX "", (unsigned long long) id); + return tchdbvsiz(bdb->hdb, hbuf, step) > 0; } - /* Load the historical leaf from the internal database. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. `id' specifies the ID number of the historical leaf. If successful, the return value is the pointer to the leaf, else, it is `NULL'. */ -static BDBLEAF *tcbdbgethistleaf(TCBDB *bdb, const char *kbuf, int ksiz, uint64_t id){ - assert(bdb && kbuf && ksiz >= 0 && id > 0); - BDBLEAF *leaf = tcbdbleafload(bdb, id); - if(!leaf) return NULL; - int ln = TCPTRLISTNUM(leaf->recs); - if(ln < 2) return NULL; - BDBREC *rec = TCPTRLISTVAL(leaf->recs, 0); - char *dbuf = (char *)rec + sizeof(*rec); - int rv; - if(bdb->cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); - } - if(rv == 0) return leaf; - if(rv < 0) return NULL; - rec = TCPTRLISTVAL(leaf->recs, ln - 1); - dbuf = (char *)rec + sizeof(*rec); - if(bdb->cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); - } - if(rv <= 0 || leaf->next < 1) return leaf; - return NULL; -} - - -/* Add a record to a leaf. +static BDBLEAF *tcbdbgethistleaf(TCBDB *bdb, const char *kbuf, int ksiz, uint64_t id) { + assert(bdb && kbuf && ksiz >= 0 && id > 0); + BDBLEAF *leaf = tcbdbleafload(bdb, id); + if (!leaf) return NULL; + int ln = TCPTRLISTNUM(leaf->recs); + if (ln < 2) return NULL; + BDBREC *rec = TCPTRLISTVAL(leaf->recs, 0); + char *dbuf = (char *) rec + sizeof (*rec); + int rv; + if (bdb->cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); + } + if (rv == 0) return leaf; + if (rv < 0) return NULL; + rec = TCPTRLISTVAL(leaf->recs, ln - 1); + dbuf = (char *) rec + sizeof (*rec); + if (bdb->cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); + } + if (rv <= 0 || leaf->next < 1) return leaf; + return NULL; +} + +/* Add a record to a leaf. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. `dmode' specifies behavior when the key overlaps. @@ -2145,457 +2038,450 @@ static BDBLEAF *tcbdbgethistleaf(TCBDB *bdb, const char *kbuf, int ksiz, uint64_ `vsiz' specifies the size of the region of the value. If successful, the return value is true, else, it is false. */ static bool tcbdbleafaddrec(TCBDB *bdb, BDBLEAF *leaf, int dmode, - const char *kbuf, int ksiz, const char *vbuf, int vsiz){ - assert(bdb && leaf && kbuf && ksiz >= 0); - TCCMP cmp = bdb->cmp; - void *cmpop = bdb->cmpop; - TCPTRLIST *recs = leaf->recs; - int ln = TCPTRLISTNUM(recs); - int left = 0; - int right = ln; - int i = (left + right) / 2; - while(right >= left && i < ln){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - char *dbuf = (char *)rec + sizeof(*rec); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); - } - if(rv == 0){ - break; - } else if(rv <= 0){ - right = i - 1; - } else { - left = i + 1; + const char *kbuf, int ksiz, const char *vbuf, int vsiz) { + assert(bdb && leaf && kbuf && ksiz >= 0); + TCCMP cmp = bdb->cmp; + void *cmpop = bdb->cmpop; + TCPTRLIST *recs = leaf->recs; + int ln = TCPTRLISTNUM(recs); + int left = 0; + int right = ln; + int i = (left + right) / 2; + while (right >= left && i < ln) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + char *dbuf = (char *) rec + sizeof (*rec); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); + } + if (rv == 0) { + break; + } else if (rv <= 0) { + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; } - i = (left + right) / 2; - } - while(i < ln){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - char *dbuf = (char *)rec + sizeof(*rec); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); - } - if(rv == 0){ - int psiz = TCALIGNPAD(rec->ksiz); - BDBREC *orec = rec; - BDBPDPROCOP *procptr; - int nvsiz; - char *nvbuf; - switch(dmode){ - case BDBPDKEEP: - tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - case BDBPDCAT: - leaf->size += vsiz; - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + rec->vsiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(recs, i, rec); - dbuf = (char *)rec + sizeof(*rec); - } - memcpy(dbuf + rec->ksiz + psiz + rec->vsiz, vbuf, vsiz); - rec->vsiz += vsiz; - dbuf[rec->ksiz+psiz+rec->vsiz] = '\0'; - break; - case BDBPDDUP: - leaf->size += vsiz; - if(!rec->rest) rec->rest = tclistnew2(1); - TCLISTPUSH(rec->rest, vbuf, vsiz); - bdb->rnum++; - break; - case BDBPDDUPB: - leaf->size += vsiz; - if(!rec->rest) rec->rest = tclistnew2(1); - tclistunshift(rec->rest, dbuf + rec->ksiz + psiz, rec->vsiz); - if(vsiz > rec->vsiz){ - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(recs, i, rec); - dbuf = (char *)rec + sizeof(*rec); - } - } - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - bdb->rnum++; - break; - case BDBPDADDINT: - if(rec->vsiz != sizeof(int)){ - tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - if(*(int *)vbuf == 0){ - *(int *)vbuf = *(int *)(dbuf + rec->ksiz + psiz); - return true; - } - *(int *)(dbuf + rec->ksiz + psiz) += *(int *)vbuf; - *(int *)vbuf = *(int *)(dbuf + rec->ksiz + psiz); - break; - case BDBPDADDDBL: -#ifdef __mips__ - { - double _vbuf; - double _tmp; - - if(rec->vsiz != sizeof(double)){ - tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - memcpy(&_vbuf, vbuf, sizeof(double)); - if(_vbuf == 0.0){ - memcpy(vbuf, dbuf + rec->ksiz + psiz, sizeof(double)); - return true; + while (i < ln) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + char *dbuf = (char *) rec + sizeof (*rec); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); } - memcpy(&_tmp, dbuf + rec->ksiz + psiz, sizeof(double)); - _tmp += _vbuf; - memcpy(dbuf + rec->ksiz + psiz, &_tmp, sizeof(double)); - memcpy(vbuf, dbuf + rec->ksiz + psiz, sizeof(double)); - } + if (rv == 0) { + int psiz = TCALIGNPAD(rec->ksiz); + BDBREC *orec = rec; + BDBPDPROCOP *procptr; + int nvsiz; + char *nvbuf; + switch (dmode) { + case BDBPDKEEP: + tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + case BDBPDCAT: + leaf->size += vsiz; + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + rec->vsiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(recs, i, rec); + dbuf = (char *) rec + sizeof (*rec); + } + memcpy(dbuf + rec->ksiz + psiz + rec->vsiz, vbuf, vsiz); + rec->vsiz += vsiz; + dbuf[rec->ksiz + psiz + rec->vsiz] = '\0'; + break; + case BDBPDDUP: + leaf->size += vsiz; + if (!rec->rest) rec->rest = tclistnew2(1); + TCLISTPUSH(rec->rest, vbuf, vsiz); + bdb->rnum++; + break; + case BDBPDDUPB: + leaf->size += vsiz; + if (!rec->rest) rec->rest = tclistnew2(1); + tclistunshift(rec->rest, dbuf + rec->ksiz + psiz, rec->vsiz); + if (vsiz > rec->vsiz) { + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(recs, i, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + bdb->rnum++; + break; + case BDBPDADDINT: + if (rec->vsiz != sizeof (int)) { + tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + } + if (*(int *) vbuf == 0) { + *(int *) vbuf = *(int *) (dbuf + rec->ksiz + psiz); + return true; + } + *(int *) (dbuf + rec->ksiz + psiz) += *(int *) vbuf; + *(int *) vbuf = *(int *) (dbuf + rec->ksiz + psiz); + break; + case BDBPDADDDBL: +#ifdef __mips__ + { + double _vbuf; + double _tmp; + + if (rec->vsiz != sizeof (double)) { + tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + } + memcpy(&_vbuf, vbuf, sizeof (double)); + if (_vbuf == 0.0) { + memcpy(vbuf, dbuf + rec->ksiz + psiz, sizeof (double)); + return true; + } + memcpy(&_tmp, dbuf + rec->ksiz + psiz, sizeof (double)); + _tmp += _vbuf; + memcpy(dbuf + rec->ksiz + psiz, &_tmp, sizeof (double)); + memcpy(vbuf, dbuf + rec->ksiz + psiz, sizeof (double)); + } #else - if(rec->vsiz != sizeof(double)){ - tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - if(*(double *)vbuf == 0.0){ - *(double *)vbuf = *(double *)(dbuf + rec->ksiz + psiz); - return true; - } - *(double *)(dbuf + rec->ksiz + psiz) += *(double *)vbuf; - *(double *)vbuf = *(double *)(dbuf + rec->ksiz + psiz); + if (rec->vsiz != sizeof (double)) { + tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + } + if (*(double *) vbuf == 0.0) { + *(double *) vbuf = *(double *) (dbuf + rec->ksiz + psiz); + return true; + } + *(double *) (dbuf + rec->ksiz + psiz) += *(double *) vbuf; + *(double *) vbuf = *(double *) (dbuf + rec->ksiz + psiz); #endif - break; - case BDBPDPROC: - procptr = *(BDBPDPROCOP **)((char *)kbuf - sizeof(procptr)); - nvbuf = procptr->proc(dbuf + rec->ksiz + psiz, rec->vsiz, &nvsiz, procptr->op); - if(nvbuf == (void *)-1){ - tcbdbremoverec(bdb, leaf, rec, i); - } else if(nvbuf){ - leaf->size += nvsiz - rec->vsiz; - if(nvsiz > rec->vsiz){ - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + nvsiz + 1); - if(rec != orec){ - tcptrlistover(recs, i, rec); - dbuf = (char *)rec + sizeof(*rec); - } + break; + case BDBPDPROC: + procptr = *(BDBPDPROCOP **) ((char *) kbuf - sizeof (procptr)); + nvbuf = procptr->proc(dbuf + rec->ksiz + psiz, rec->vsiz, &nvsiz, procptr->op); + if (nvbuf == (void *) - 1) { + tcbdbremoverec(bdb, leaf, rec, i); + } else if (nvbuf) { + leaf->size += nvsiz - rec->vsiz; + if (nvsiz > rec->vsiz) { + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + nvsiz + 1); + if (rec != orec) { + tcptrlistover(recs, i, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, nvbuf, nvsiz); + dbuf[rec->ksiz + psiz + nvsiz] = '\0'; + rec->vsiz = nvsiz; + TCFREE(nvbuf); + } else { + tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + } + break; + default: + leaf->size += vsiz - rec->vsiz; + if (vsiz > rec->vsiz) { + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(recs, i, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + break; } - memcpy(dbuf + rec->ksiz + psiz, nvbuf, nvsiz); - dbuf[rec->ksiz+psiz+nvsiz] = '\0'; - rec->vsiz = nvsiz; - TCFREE(nvbuf); - } else { - tcbdbsetecode(bdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - break; - default: - leaf->size += vsiz - rec->vsiz; - if(vsiz > rec->vsiz){ - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(recs, i, rec); - dbuf = (char *)rec + sizeof(*rec); + break; + } else if (rv < 0) { + if (!vbuf) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; } - } - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - break; - } - break; - } else if(rv < 0){ - if(!vbuf){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - leaf->size += ksiz + vsiz; - int psiz = TCALIGNPAD(ksiz); - BDBREC *nrec; - TCMALLOC(nrec, sizeof(*nrec) + ksiz + psiz + vsiz + 1); - char *dbuf = (char *)nrec + sizeof(*nrec); - memcpy(dbuf, kbuf, ksiz); - dbuf[ksiz] = '\0'; - nrec->ksiz = ksiz; - memcpy(dbuf + ksiz + psiz, vbuf, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - nrec->vsiz = vsiz; - nrec->rest = NULL; - TCPTRLISTINSERT(recs, i, nrec); - bdb->rnum++; - break; - } - i++; - } - if(i >= ln){ - if(!vbuf){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - leaf->size += ksiz + vsiz; - int psiz = TCALIGNPAD(ksiz); - BDBREC *nrec; - TCMALLOC(nrec, sizeof(*nrec) + ksiz + psiz + vsiz + 1); - char *dbuf = (char *)nrec + sizeof(*nrec); - memcpy(dbuf, kbuf, ksiz); - dbuf[ksiz] = '\0'; - nrec->ksiz = ksiz; - memcpy(dbuf + ksiz + psiz, vbuf, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - nrec->vsiz = vsiz; - nrec->rest = NULL; - TCPTRLISTPUSH(recs, nrec); - bdb->rnum++; - } - leaf->dirty = true; - return true; + leaf->size += ksiz + vsiz; + int psiz = TCALIGNPAD(ksiz); + BDBREC *nrec; + TCMALLOC(nrec, sizeof (*nrec) + ksiz + psiz + vsiz + 1); + char *dbuf = (char *) nrec + sizeof (*nrec); + memcpy(dbuf, kbuf, ksiz); + dbuf[ksiz] = '\0'; + nrec->ksiz = ksiz; + memcpy(dbuf + ksiz + psiz, vbuf, vsiz); + dbuf[ksiz + psiz + vsiz] = '\0'; + nrec->vsiz = vsiz; + nrec->rest = NULL; + TCPTRLISTINSERT(recs, i, nrec); + bdb->rnum++; + break; + } + i++; + } + if (i >= ln) { + if (!vbuf) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + leaf->size += ksiz + vsiz; + int psiz = TCALIGNPAD(ksiz); + BDBREC *nrec; + TCMALLOC(nrec, sizeof (*nrec) + ksiz + psiz + vsiz + 1); + char *dbuf = (char *) nrec + sizeof (*nrec); + memcpy(dbuf, kbuf, ksiz); + dbuf[ksiz] = '\0'; + nrec->ksiz = ksiz; + memcpy(dbuf + ksiz + psiz, vbuf, vsiz); + dbuf[ksiz + psiz + vsiz] = '\0'; + nrec->vsiz = vsiz; + nrec->rest = NULL; + TCPTRLISTPUSH(recs, nrec); + bdb->rnum++; + } + leaf->dirty = true; + return true; } - /* Divide a leaf into two. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. The return value is the new leaf object or `NULL' on failure. */ -static BDBLEAF *tcbdbleafdivide(TCBDB *bdb, BDBLEAF *leaf){ - assert(bdb && leaf); - bdb->hleaf = 0; - TCPTRLIST *recs = leaf->recs; - int mid = TCPTRLISTNUM(recs) / 2; - BDBLEAF *newleaf = tcbdbleafnew(bdb, leaf->id, leaf->next); - if(newleaf->next > 0){ - BDBLEAF *nextleaf = tcbdbleafload(bdb, newleaf->next); - if(!nextleaf) return NULL; - nextleaf->prev = newleaf->id; - nextleaf->dirty = true; - } - leaf->next = newleaf->id; - leaf->dirty = true; - int ln = TCPTRLISTNUM(recs); - TCPTRLIST *newrecs = newleaf->recs; - int nsiz = 0; - for(int i = mid; i < ln; i++){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - nsiz += rec->ksiz + rec->vsiz; - if(rec->rest){ - TCLIST *rest = rec->rest; - int rnum = TCLISTNUM(rest); - for(int j = 0; j < rnum; j++){ - nsiz += TCLISTVALSIZ(rest, j); - } - } - TCPTRLISTPUSH(newrecs, rec); - } - TCPTRLISTTRUNC(recs, TCPTRLISTNUM(recs) - TCPTRLISTNUM(newrecs)); - leaf->size -= nsiz; - newleaf->size = nsiz; - return newleaf; +static BDBLEAF *tcbdbleafdivide(TCBDB *bdb, BDBLEAF *leaf) { + assert(bdb && leaf); + bdb->hleaf = 0; + TCPTRLIST *recs = leaf->recs; + int mid = TCPTRLISTNUM(recs) / 2; + BDBLEAF *newleaf = tcbdbleafnew(bdb, leaf->id, leaf->next); + if (newleaf->next > 0) { + BDBLEAF *nextleaf = tcbdbleafload(bdb, newleaf->next); + if (!nextleaf) return NULL; + nextleaf->prev = newleaf->id; + nextleaf->dirty = true; + } + leaf->next = newleaf->id; + leaf->dirty = true; + int ln = TCPTRLISTNUM(recs); + TCPTRLIST *newrecs = newleaf->recs; + int nsiz = 0; + for (int i = mid; i < ln; i++) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + nsiz += rec->ksiz + rec->vsiz; + if (rec->rest) { + TCLIST *rest = rec->rest; + int rnum = TCLISTNUM(rest); + for (int j = 0; j < rnum; j++) { + nsiz += TCLISTVALSIZ(rest, j); + } + } + TCPTRLISTPUSH(newrecs, rec); + } + TCPTRLISTTRUNC(recs, TCPTRLISTNUM(recs) - TCPTRLISTNUM(newrecs)); + leaf->size -= nsiz; + newleaf->size = nsiz; + return newleaf; } - /* Cut off the path to a leaf and mark it dead. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. If successful, the return value is true, else, it is false. */ -static bool tcbdbleafkill(TCBDB *bdb, BDBLEAF *leaf){ - assert(bdb && leaf); - BDBNODE *node = tcbdbnodeload(bdb, bdb->hist[--bdb->hnum]); - if(!node) return false; - if(tcbdbnodesubidx(bdb, node, leaf->id)){ - TCDODEBUG(bdb->cnt_killleaf++); - if(bdb->hleaf == leaf->id) bdb->hleaf = 0; - if(leaf->prev > 0){ - BDBLEAF *tleaf = tcbdbleafload(bdb, leaf->prev); - if(!tleaf) return false; - tleaf->next = leaf->next; - tleaf->dirty = true; - if(bdb->last == leaf->id) bdb->last = leaf->prev; - } - if(leaf->next > 0){ - BDBLEAF *tleaf = tcbdbleafload(bdb, leaf->next); - if(!tleaf) return false; - tleaf->prev = leaf->prev; - tleaf->dirty = true; - if(bdb->first == leaf->id) bdb->first = leaf->next; - } - leaf->dead = true; - } - bdb->clock++; - return true; +static bool tcbdbleafkill(TCBDB *bdb, BDBLEAF *leaf) { + assert(bdb && leaf); + BDBNODE *node = tcbdbnodeload(bdb, bdb->hist[--bdb->hnum]); + if (!node) return false; + if (tcbdbnodesubidx(bdb, node, leaf->id)) { + TCDODEBUG(bdb->cnt_killleaf++); + if (bdb->hleaf == leaf->id) bdb->hleaf = 0; + if (leaf->prev > 0) { + BDBLEAF *tleaf = tcbdbleafload(bdb, leaf->prev); + if (!tleaf) return false; + tleaf->next = leaf->next; + tleaf->dirty = true; + if (bdb->last == leaf->id) bdb->last = leaf->prev; + } + if (leaf->next > 0) { + BDBLEAF *tleaf = tcbdbleafload(bdb, leaf->next); + if (!tleaf) return false; + tleaf->prev = leaf->prev; + tleaf->dirty = true; + if (bdb->first == leaf->id) bdb->first = leaf->next; + } + leaf->dead = true; + } + bdb->clock++; + return true; } - /* Create a new node. `bdb' specifies the B+ tree database object. `heir' specifies the ID of the child before the first index. The return value is the new node object. */ -static BDBNODE *tcbdbnodenew(TCBDB *bdb, uint64_t heir){ - assert(bdb && heir > 0); - BDBNODE nent; - nent.id = ++bdb->nnum + BDBNODEIDBASE; - nent.idxs = tcptrlistnew2(bdb->nmemb + 1); - nent.heir = heir; - nent.dirty = true; - nent.dead = false; - tcmapputkeep(bdb->nodec, &(nent.id), sizeof(nent.id), &nent, sizeof(nent)); - int rsiz; - return (BDBNODE *)tcmapget(bdb->nodec, &(nent.id), sizeof(nent.id), &rsiz); +static BDBNODE *tcbdbnodenew(TCBDB *bdb, uint64_t heir) { + assert(bdb && heir > 0); + BDBNODE nent; + nent.id = ++bdb->nnum + BDBNODEIDBASE; + nent.idxs = tcptrlistnew2(bdb->nmemb + 1); + nent.heir = heir; + nent.dirty = true; + nent.dead = false; + tcmapputkeep(bdb->nodec, &(nent.id), sizeof (nent.id), &nent, sizeof (nent)); + int rsiz; + return (BDBNODE *) tcmapget(bdb->nodec, &(nent.id), sizeof (nent.id), &rsiz); } - /* Remove a node from the cache. `bdb' specifies the B+ tree database object. `node' specifies the node object. If successful, the return value is true, else, it is false. */ -static bool tcbdbnodecacheout(TCBDB *bdb, BDBNODE *node){ - assert(bdb && node); - bool err = false; - if(node->dirty && !tcbdbnodesave(bdb, node)) err = true; - TCPTRLIST *idxs = node->idxs; - int ln = TCPTRLISTNUM(idxs); - for(int i = 0; i < ln; i++){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - TCFREE(idx); - } - tcptrlistdel(idxs); - tcmapout(bdb->nodec, &(node->id), sizeof(node->id)); - return !err; +static bool tcbdbnodecacheout(TCBDB *bdb, BDBNODE *node) { + assert(bdb && node); + bool err = false; + if (node->dirty && !tcbdbnodesave(bdb, node)) err = true; + TCPTRLIST *idxs = node->idxs; + int ln = TCPTRLISTNUM(idxs); + for (int i = 0; i < ln; i++) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + TCFREE(idx); + } + tcptrlistdel(idxs); + tcmapout(bdb->nodec, &(node->id), sizeof (node->id)); + return !err; } - /* Save a node into the internal database. `bdb' specifies the B+ tree database object. `node' specifies the node object. If successful, the return value is true, else, it is false. */ -static bool tcbdbnodesave(TCBDB *bdb, BDBNODE *node){ - assert(bdb && node); - TCDODEBUG(bdb->cnt_savenode++); - TCXSTR *rbuf = tcxstrnew3(BDBPAGEBUFSIZ); - char hbuf[(sizeof(uint64_t)+1)*2]; - uint64_t llnum; - int step; - llnum = node->heir; - TCSETVNUMBUF64(step, hbuf, llnum); - TCXSTRCAT(rbuf, hbuf, step); - TCPTRLIST *idxs = node->idxs; - int ln = TCPTRLISTNUM(idxs); - for(int i = 0; i < ln; i++){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - char *wp = hbuf; - llnum = idx->pid; - TCSETVNUMBUF64(step, wp, llnum); - wp += step; - uint32_t lnum = idx->ksiz; - TCSETVNUMBUF(step, wp, lnum); - wp += step; - TCXSTRCAT(rbuf, hbuf, wp - hbuf); - TCXSTRCAT(rbuf, ebuf, idx->ksiz); - } - bool err = false; - step = sprintf(hbuf, "#%" PRIxMAX "", (unsigned long long)(node->id - BDBNODEIDBASE)); - if(ln < 1 && !tchdbout(bdb->hdb, hbuf, step) && tchdbecode(bdb->hdb) != TCENOREC) - err = true; - if(!node->dead && !tchdbput(bdb->hdb, hbuf, step, TCXSTRPTR(rbuf), TCXSTRSIZE(rbuf))) - err = true; - tcxstrdel(rbuf); - node->dirty = false; - node->dead = false; - return !err; +static bool tcbdbnodesave(TCBDB *bdb, BDBNODE *node) { + assert(bdb && node); + TCDODEBUG(bdb->cnt_savenode++); + TCXSTR *rbuf = tcxstrnew3(BDBPAGEBUFSIZ); + char hbuf[(sizeof (uint64_t) + 1)*2]; + uint64_t llnum; + int step; + llnum = node->heir; + TCSETVNUMBUF64(step, hbuf, llnum); + TCXSTRCAT(rbuf, hbuf, step); + TCPTRLIST *idxs = node->idxs; + int ln = TCPTRLISTNUM(idxs); + for (int i = 0; i < ln; i++) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + char *wp = hbuf; + llnum = idx->pid; + TCSETVNUMBUF64(step, wp, llnum); + wp += step; + uint32_t lnum = idx->ksiz; + TCSETVNUMBUF(step, wp, lnum); + wp += step; + TCXSTRCAT(rbuf, hbuf, wp - hbuf); + TCXSTRCAT(rbuf, ebuf, idx->ksiz); + } + bool err = false; + step = sprintf(hbuf, "#%" PRIxMAX "", (unsigned long long) (node->id - BDBNODEIDBASE)); + if (ln < 1 && !tchdbout(bdb->hdb, hbuf, step) && tchdbecode(bdb->hdb) != TCENOREC) + err = true; + if (!node->dead && !tchdbput(bdb->hdb, hbuf, step, TCXSTRPTR(rbuf), TCXSTRSIZE(rbuf))) + err = true; + tcxstrdel(rbuf); + node->dirty = false; + node->dead = false; + return !err; } - /* Load a node from the internal database. `bdb' specifies the B+ tree database object. `id' specifies the ID number of the node. The return value is the node object or `NULL' on failure. */ -static BDBNODE *tcbdbnodeload(TCBDB *bdb, uint64_t id){ - assert(bdb && id > BDBNODEIDBASE); - bool clk = BDBLOCKCACHE(bdb); - int rsiz; - BDBNODE *node = (BDBNODE *)tcmapget3(bdb->nodec, &id, sizeof(id), &rsiz); - if(node){ - if(clk) BDBUNLOCKCACHE(bdb); - return node; - } - if(clk) BDBUNLOCKCACHE(bdb); - TCDODEBUG(bdb->cnt_loadnode++); - char hbuf[(sizeof(uint64_t)+1)*2]; - int step; - step = sprintf(hbuf, "#%" PRIxMAX "", (unsigned long long)(id - BDBNODEIDBASE)); - char *rbuf = NULL; - char wbuf[BDBPAGEBUFSIZ]; - const char *rp = NULL; - rsiz = tchdbget3(bdb->hdb, hbuf, step, wbuf, BDBPAGEBUFSIZ); - if(rsiz < 1){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return NULL; - } else if(rsiz < BDBPAGEBUFSIZ){ - rp = wbuf; - } else { - if(!(rbuf = tchdbget(bdb->hdb, hbuf, step, &rsiz))){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return NULL; - } - rp = rbuf; - } - BDBNODE nent; - nent.id = id; - uint64_t llnum; - TCREADVNUMBUF64(rp, llnum, step); - nent.heir = llnum; - rp += step; - rsiz -= step; - nent.dirty = false; - nent.dead = false; - nent.idxs = tcptrlistnew2(bdb->nmemb + 1); - bool err = false; - while(rsiz >= 2){ - uint64_t pid; - TCREADVNUMBUF64(rp, pid, step); - rp += step; - rsiz -= step; - int ksiz; - TCREADVNUMBUF(rp, ksiz, step); +static BDBNODE *tcbdbnodeload(TCBDB *bdb, uint64_t id) { + assert(bdb && id > BDBNODEIDBASE); + bool clk = BDBLOCKCACHE(bdb); + int rsiz; + BDBNODE *node = (BDBNODE *) tcmapget3(bdb->nodec, &id, sizeof (id), &rsiz); + if (node) { + if (clk) BDBUNLOCKCACHE(bdb); + return node; + } + if (clk) BDBUNLOCKCACHE(bdb); + TCDODEBUG(bdb->cnt_loadnode++); + char hbuf[(sizeof (uint64_t) + 1)*2]; + int step; + step = sprintf(hbuf, "#%" PRIxMAX "", (unsigned long long) (id - BDBNODEIDBASE)); + char *rbuf = NULL; + char wbuf[BDBPAGEBUFSIZ]; + const char *rp = NULL; + rsiz = tchdbget3(bdb->hdb, hbuf, step, wbuf, BDBPAGEBUFSIZ); + if (rsiz < 1) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return NULL; + } else if (rsiz < BDBPAGEBUFSIZ) { + rp = wbuf; + } else { + if (!(rbuf = tchdbget(bdb->hdb, hbuf, step, &rsiz))) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return NULL; + } + rp = rbuf; + } + BDBNODE nent; + nent.id = id; + uint64_t llnum; + TCREADVNUMBUF64(rp, llnum, step); + nent.heir = llnum; rp += step; rsiz -= step; - if(rsiz < ksiz){ - err = true; - break; - } - BDBIDX *nidx; - TCMALLOC(nidx, sizeof(*nidx) + ksiz + 1); - nidx->pid = pid; - char *ebuf = (char *)nidx + sizeof(*nidx); - memcpy(ebuf, rp, ksiz); - ebuf[ksiz] = '\0'; - nidx->ksiz = ksiz; - rp += ksiz; - rsiz -= ksiz; - TCPTRLISTPUSH(nent.idxs, nidx); - } - TCFREE(rbuf); - if(err || rsiz != 0){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return NULL; - } - clk = BDBLOCKCACHE(bdb); - if(!tcmapputkeep(bdb->nodec, &(nent.id), sizeof(nent.id), &nent, sizeof(nent))){ - int ln = TCPTRLISTNUM(nent.idxs); - for(int i = 0; i < ln; i++){ - BDBIDX *idx = TCPTRLISTVAL(nent.idxs, i); - TCFREE(idx); + nent.dirty = false; + nent.dead = false; + nent.idxs = tcptrlistnew2(bdb->nmemb + 1); + bool err = false; + while (rsiz >= 2) { + uint64_t pid; + TCREADVNUMBUF64(rp, pid, step); + rp += step; + rsiz -= step; + int ksiz; + TCREADVNUMBUF(rp, ksiz, step); + rp += step; + rsiz -= step; + if (rsiz < ksiz) { + err = true; + break; + } + BDBIDX *nidx; + TCMALLOC(nidx, sizeof (*nidx) + ksiz + 1); + nidx->pid = pid; + char *ebuf = (char *) nidx + sizeof (*nidx); + memcpy(ebuf, rp, ksiz); + ebuf[ksiz] = '\0'; + nidx->ksiz = ksiz; + rp += ksiz; + rsiz -= ksiz; + TCPTRLISTPUSH(nent.idxs, nidx); + } + TCFREE(rbuf); + if (err || rsiz != 0) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return NULL; + } + clk = BDBLOCKCACHE(bdb); + if (!tcmapputkeep(bdb->nodec, &(nent.id), sizeof (nent.id), &nent, sizeof (nent))) { + int ln = TCPTRLISTNUM(nent.idxs); + for (int i = 0; i < ln; i++) { + BDBIDX *idx = TCPTRLISTVAL(nent.idxs, i); + TCFREE(idx); + } + tcptrlistdel(nent.idxs); } - tcptrlistdel(nent.idxs); - } - node = (BDBNODE *)tcmapget(bdb->nodec, &(nent.id), sizeof(nent.id), &rsiz); - if(clk) BDBUNLOCKCACHE(bdb); - return node; + node = (BDBNODE *) tcmapget(bdb->nodec, &(nent.id), sizeof (nent.id), &rsiz); + if (clk) BDBUNLOCKCACHE(bdb); + return node; } - /* Add an index to a node. `bdb' specifies the B+ tree database object. `node' specifies the node object. @@ -2604,197 +2490,194 @@ static BDBNODE *tcbdbnodeload(TCBDB *bdb, uint64_t id){ `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. */ static void tcbdbnodeaddidx(TCBDB *bdb, BDBNODE *node, bool order, uint64_t pid, - const char *kbuf, int ksiz){ - assert(bdb && node && pid > 0 && kbuf && ksiz >= 0); - BDBIDX *nidx; - TCMALLOC(nidx, sizeof(*nidx) + ksiz + 1); - nidx->pid = pid; - char *ebuf = (char *)nidx + sizeof(*nidx); - memcpy(ebuf, kbuf, ksiz); - ebuf[ksiz] = '\0'; - nidx->ksiz = ksiz; - TCCMP cmp = bdb->cmp; - void *cmpop = bdb->cmpop; - TCPTRLIST *idxs = node->idxs; - if(order){ - TCPTRLISTPUSH(idxs, nidx); - } else { - int ln = TCPTRLISTNUM(idxs); - int left = 0; - int right = ln; - int i = (left + right) / 2; - while(right >= left && i < ln){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); - } else { - rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); - } - if(rv == 0){ - break; - } else if(rv <= 0){ - right = i - 1; - } else { - left = i + 1; - } - i = (left + right) / 2; - } - while(i < ln){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); - } else { - rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); - } - if(rv < 0){ - TCPTRLISTINSERT(idxs, i, nidx); - break; - } - i++; - } - if(i >= ln) TCPTRLISTPUSH(idxs, nidx); - } - node->dirty = true; + const char *kbuf, int ksiz) { + assert(bdb && node && pid > 0 && kbuf && ksiz >= 0); + BDBIDX *nidx; + TCMALLOC(nidx, sizeof (*nidx) + ksiz + 1); + nidx->pid = pid; + char *ebuf = (char *) nidx + sizeof (*nidx); + memcpy(ebuf, kbuf, ksiz); + ebuf[ksiz] = '\0'; + nidx->ksiz = ksiz; + TCCMP cmp = bdb->cmp; + void *cmpop = bdb->cmpop; + TCPTRLIST *idxs = node->idxs; + if (order) { + TCPTRLISTPUSH(idxs, nidx); + } else { + int ln = TCPTRLISTNUM(idxs); + int left = 0; + int right = ln; + int i = (left + right) / 2; + while (right >= left && i < ln) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); + } else { + rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); + } + if (rv == 0) { + break; + } else if (rv <= 0) { + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; + } + while (i < ln) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); + } else { + rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); + } + if (rv < 0) { + TCPTRLISTINSERT(idxs, i, nidx); + break; + } + i++; + } + if (i >= ln) TCPTRLISTPUSH(idxs, nidx); + } + node->dirty = true; } - /* Subtract an index from a node. `bdb' specifies the B+ tree database object. `node' specifies the node object. `pid' specifies the ID number of referred page. The return value is whether the subtraction is completed. */ -static bool tcbdbnodesubidx(TCBDB *bdb, BDBNODE *node, uint64_t pid){ - assert(bdb && node && pid > 0); - node->dirty = true; - TCPTRLIST *idxs = node->idxs; - if(node->heir == pid){ - if(TCPTRLISTNUM(idxs) > 0){ - BDBIDX *idx = tcptrlistshift(idxs); - assert(idx); - node->heir = idx->pid; - TCFREE(idx); - return true; - } else if(bdb->hnum > 0){ - BDBNODE *pnode = tcbdbnodeload(bdb, bdb->hist[--bdb->hnum]); - if(!pnode){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return false; - } - node->dead = true; - return tcbdbnodesubidx(bdb, pnode, node->id); - } - node->dead = true; - bdb->root = pid; - while(pid > BDBNODEIDBASE){ - node = tcbdbnodeload(bdb, pid); - if(!node){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return false; - } - if(node->dead){ - pid = node->heir; +static bool tcbdbnodesubidx(TCBDB *bdb, BDBNODE *node, uint64_t pid) { + assert(bdb && node && pid > 0); + node->dirty = true; + TCPTRLIST *idxs = node->idxs; + if (node->heir == pid) { + if (TCPTRLISTNUM(idxs) > 0) { + BDBIDX *idx = tcptrlistshift(idxs); + assert(idx); + node->heir = idx->pid; + TCFREE(idx); + return true; + } else if (bdb->hnum > 0) { + BDBNODE *pnode = tcbdbnodeload(bdb, bdb->hist[--bdb->hnum]); + if (!pnode) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return false; + } + node->dead = true; + return tcbdbnodesubidx(bdb, pnode, node->id); + } + node->dead = true; bdb->root = pid; - } else { - pid = 0; - } + while (pid > BDBNODEIDBASE) { + node = tcbdbnodeload(bdb, pid); + if (!node) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return false; + } + if (node->dead) { + pid = node->heir; + bdb->root = pid; + } else { + pid = 0; + } + } + return false; } - return false; - } - int ln = TCPTRLISTNUM(idxs); - for(int i = 0; i < ln; i++){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - if(idx->pid == pid){ - TCFREE(tcptrlistremove(idxs, i)); - return true; + int ln = TCPTRLISTNUM(idxs); + for (int i = 0; i < ln; i++) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + if (idx->pid == pid) { + TCFREE(tcptrlistremove(idxs, i)); + return true; + } } - } - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return false; + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return false; } - /* Search the leaf object corresponding to a key. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. The return value is the ID number of the leaf object or 0 on failure. */ -static uint64_t tcbdbsearchleaf(TCBDB *bdb, const char *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - TCCMP cmp = bdb->cmp; - void *cmpop = bdb->cmpop; - uint64_t *hist = bdb->hist; - uint64_t pid = bdb->root; - int hnum = 0; - bdb->hleaf = 0; - while(pid > BDBNODEIDBASE){ - BDBNODE *node = tcbdbnodeload(bdb, pid); - if(!node){ - tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); - return 0; - } - hist[hnum++] = node->id; - TCPTRLIST *idxs = node->idxs; - int ln = TCPTRLISTNUM(idxs); - if(ln > 0){ - int left = 0; - int right = ln; - int i = (left + right) / 2; - BDBIDX *idx = NULL; - while(right >= left && i < ln){ - idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); - } else { - rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); +static uint64_t tcbdbsearchleaf(TCBDB *bdb, const char *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + TCCMP cmp = bdb->cmp; + void *cmpop = bdb->cmpop; + uint64_t *hist = bdb->hist; + uint64_t pid = bdb->root; + int hnum = 0; + bdb->hleaf = 0; + while (pid > BDBNODEIDBASE) { + BDBNODE *node = tcbdbnodeload(bdb, pid); + if (!node) { + tcbdbsetecode(bdb, TCEMISC, __FILE__, __LINE__, __func__); + return 0; } - if(rv == 0){ - break; - } else if(rv <= 0){ - right = i - 1; - } else { - left = i + 1; - } - i = (left + right) / 2; - } - if(i > 0) i--; - while(i < ln){ - idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); + hist[hnum++] = node->id; + TCPTRLIST *idxs = node->idxs; + int ln = TCPTRLISTNUM(idxs); + if (ln > 0) { + int left = 0; + int right = ln; + int i = (left + right) / 2; + BDBIDX *idx = NULL; + while (right >= left && i < ln) { + idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); + } else { + rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); + } + if (rv == 0) { + break; + } else if (rv <= 0) { + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; + } + if (i > 0) i--; + while (i < ln) { + idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, ebuf, idx->ksiz); + } else { + rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); + } + if (rv < 0) { + if (i == 0) { + pid = node->heir; + break; + } + idx = TCPTRLISTVAL(idxs, i - 1); + pid = idx->pid; + break; + } + i++; + } + if (i >= ln) pid = idx->pid; } else { - rv = cmp(kbuf, ksiz, ebuf, idx->ksiz, cmpop); - } - if(rv < 0){ - if(i == 0){ pid = node->heir; - break; - } - idx = TCPTRLISTVAL(idxs, i - 1); - pid = idx->pid; - break; } - i++; - } - if(i >= ln) pid = idx->pid; - } else { - pid = node->heir; } - } - if(bdb->lleaf == pid) bdb->hleaf = pid; - bdb->lleaf = pid; - bdb->hnum = hnum; - return pid; + if (bdb->lleaf == pid) bdb->hleaf = pid; + bdb->lleaf = pid; + bdb->hnum = hnum; + return pid; } - /* Search a record of a leaf. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. @@ -2802,272 +2685,266 @@ static uint64_t tcbdbsearchleaf(TCBDB *bdb, const char *kbuf, int ksiz){ `ksiz' specifies the size of the region of the key. `ip' specifies the pointer to a variable to fetch the index of the correspnding record. The return value is the pointer to a corresponding record or `NULL' on failure. */ -static BDBREC *tcbdbsearchrec(TCBDB *bdb, BDBLEAF *leaf, const char *kbuf, int ksiz, int *ip){ - assert(bdb && leaf && kbuf && ksiz >= 0); - TCCMP cmp = bdb->cmp; - void *cmpop = bdb->cmpop; - TCPTRLIST *recs = leaf->recs; - int ln = TCPTRLISTNUM(recs); - int left = 0; - int right = ln; - int i = (left + right) / 2; - while(right >= left && i < ln){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - char *dbuf = (char *)rec + sizeof(*rec); - int rv; - if(cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); - } - if(rv == 0){ - if(ip) *ip = i; - return rec; - } else if(rv <= 0){ - right = i - 1; - } else { - left = i + 1; +static BDBREC *tcbdbsearchrec(TCBDB *bdb, BDBLEAF *leaf, const char *kbuf, int ksiz, int *ip) { + assert(bdb && leaf && kbuf && ksiz >= 0); + TCCMP cmp = bdb->cmp; + void *cmpop = bdb->cmpop; + TCPTRLIST *recs = leaf->recs; + int ln = TCPTRLISTNUM(recs); + int left = 0; + int right = ln; + int i = (left + right) / 2; + while (right >= left && i < ln) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + char *dbuf = (char *) rec + sizeof (*rec); + int rv; + if (cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = cmp(kbuf, ksiz, dbuf, rec->ksiz, cmpop); + } + if (rv == 0) { + if (ip) *ip = i; + return rec; + } else if (rv <= 0) { + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; } - i = (left + right) / 2; - } - if(ip) *ip = i; - return NULL; + if (ip) *ip = i; + return NULL; } - /* Remove a record from a leaf. `bdb' specifies the B+ tree database object. `rec' specifies the record object. `ri' specifies the index of the record. */ -static void tcbdbremoverec(TCBDB *bdb, BDBLEAF *leaf, BDBREC *rec, int ri){ - assert(bdb && leaf && rec && ri >= 0); - if(rec->rest){ - leaf->size -= rec->vsiz; - int vsiz; - char *vbuf = tclistshift(rec->rest, &vsiz); - int psiz = TCALIGNPAD(rec->ksiz); - if(vsiz > rec->vsiz){ - BDBREC *orec = rec; - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec) tcptrlistover(leaf->recs, ri, rec); - } - char *dbuf = (char *)rec + sizeof(*rec); - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - TCFREE(vbuf); - if(TCLISTNUM(rec->rest) < 1){ - tclistdel(rec->rest); - rec->rest = NULL; - } - } else { - leaf->size -= rec->ksiz + rec->vsiz; - TCFREE(tcptrlistremove(leaf->recs, ri)); - } - bdb->rnum--; +static void tcbdbremoverec(TCBDB *bdb, BDBLEAF *leaf, BDBREC *rec, int ri) { + assert(bdb && leaf && rec && ri >= 0); + if (rec->rest) { + leaf->size -= rec->vsiz; + int vsiz; + char *vbuf = tclistshift(rec->rest, &vsiz); + int psiz = TCALIGNPAD(rec->ksiz); + if (vsiz > rec->vsiz) { + BDBREC *orec = rec; + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) tcptrlistover(leaf->recs, ri, rec); + } + char *dbuf = (char *) rec + sizeof (*rec); + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + TCFREE(vbuf); + if (TCLISTNUM(rec->rest) < 1) { + tclistdel(rec->rest); + rec->rest = NULL; + } + } else { + leaf->size -= rec->ksiz + rec->vsiz; + TCFREE(tcptrlistremove(leaf->recs, ri)); + } + bdb->rnum--; } - /* Adjust the caches for leaves and nodes. `bdb' specifies the B+ tree database object. The return value is true if successful, else, it is false. */ -static bool tcbdbcacheadjust(TCBDB *bdb){ - bool err = false; - if(TCMAPRNUM(bdb->leafc) > bdb->lcnum){ - TCDODEBUG(bdb->cnt_adjleafc++); - int ecode = tchdbecode(bdb->hdb); - bool clk = BDBLOCKCACHE(bdb); - TCMAP *leafc = bdb->leafc; - tcmapiterinit(leafc); - int dnum = tclmax(TCMAPRNUM(bdb->leafc) - bdb->lcnum, BDBCACHEOUT); - for(int i = 0; i < dnum; i++){ - int rsiz; - if(!tcbdbleafcacheout(bdb, (BDBLEAF *)tcmapiterval(tcmapiternext(leafc, &rsiz), &rsiz))) - err = true; - } - if(clk) BDBUNLOCKCACHE(bdb); - if(!err && tchdbecode(bdb->hdb) != ecode) - tcbdbsetecode(bdb, ecode, __FILE__, __LINE__, __func__); - } - if(TCMAPRNUM(bdb->nodec) > bdb->ncnum){ - TCDODEBUG(bdb->cnt_adjnodec++); - int ecode = tchdbecode(bdb->hdb); - bool clk = BDBLOCKCACHE(bdb); - TCMAP *nodec = bdb->nodec; - tcmapiterinit(nodec); - int dnum = tclmax(TCMAPRNUM(bdb->nodec) - bdb->ncnum, BDBCACHEOUT); - for(int i = 0; i < dnum; i++){ - int rsiz; - if(!tcbdbnodecacheout(bdb, (BDBNODE *)tcmapiterval(tcmapiternext(nodec, &rsiz), &rsiz))) - err = true; +static bool tcbdbcacheadjust(TCBDB *bdb) { + bool err = false; + if (TCMAPRNUM(bdb->leafc) > bdb->lcnum) { + TCDODEBUG(bdb->cnt_adjleafc++); + int ecode = tchdbecode(bdb->hdb); + bool clk = BDBLOCKCACHE(bdb); + TCMAP *leafc = bdb->leafc; + tcmapiterinit(leafc); + int dnum = tclmax(TCMAPRNUM(bdb->leafc) - bdb->lcnum, BDBCACHEOUT); + for (int i = 0; i < dnum; i++) { + int rsiz; + if (!tcbdbleafcacheout(bdb, (BDBLEAF *) tcmapiterval(tcmapiternext(leafc, &rsiz), &rsiz))) + err = true; + } + if (clk) BDBUNLOCKCACHE(bdb); + if (!err && tchdbecode(bdb->hdb) != ecode) + tcbdbsetecode(bdb, ecode, __FILE__, __LINE__, __func__); + } + if (TCMAPRNUM(bdb->nodec) > bdb->ncnum) { + TCDODEBUG(bdb->cnt_adjnodec++); + int ecode = tchdbecode(bdb->hdb); + bool clk = BDBLOCKCACHE(bdb); + TCMAP *nodec = bdb->nodec; + tcmapiterinit(nodec); + int dnum = tclmax(TCMAPRNUM(bdb->nodec) - bdb->ncnum, BDBCACHEOUT); + for (int i = 0; i < dnum; i++) { + int rsiz; + if (!tcbdbnodecacheout(bdb, (BDBNODE *) tcmapiterval(tcmapiternext(nodec, &rsiz), &rsiz))) + err = true; + } + if (clk) BDBUNLOCKCACHE(bdb); + if (!err && tchdbecode(bdb->hdb) != ecode) + tcbdbsetecode(bdb, ecode, __FILE__, __LINE__, __func__); } - if(clk) BDBUNLOCKCACHE(bdb); - if(!err && tchdbecode(bdb->hdb) != ecode) - tcbdbsetecode(bdb, ecode, __FILE__, __LINE__, __func__); - } - return !err; + return !err; } - /* Purge dirty pages of caches for leaves and nodes. `bdb' specifies the B+ tree database object. */ -static void tcbdbcachepurge(TCBDB *bdb){ - bool clk = BDBLOCKCACHE(bdb); - int tsiz; - const char *tmp; - tcmapiterinit(bdb->leafc); - while((tmp = tcmapiternext(bdb->leafc, &tsiz)) != NULL){ - int lsiz; - BDBLEAF *leaf = (BDBLEAF *)tcmapiterval(tmp, &lsiz); - if(!leaf->dirty) continue; - TCPTRLIST *recs = leaf->recs; - int ln = TCPTRLISTNUM(recs); - for(int i = 0; i < ln; i++){ - BDBREC *rec = TCPTRLISTVAL(recs, i); - if(rec->rest) tclistdel(rec->rest); - TCFREE(rec); - } - tcptrlistdel(recs); - tcmapout(bdb->leafc, tmp, tsiz); - } - tcmapiterinit(bdb->nodec); - while((tmp = tcmapiternext(bdb->nodec, &tsiz)) != NULL){ - int nsiz; - BDBNODE *node = (BDBNODE *)tcmapiterval(tmp, &nsiz); - if(!node->dirty) continue; - TCPTRLIST *idxs = node->idxs; - int ln = TCPTRLISTNUM(idxs); - for(int i = 0; i < ln; i++){ - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - TCFREE(idx); +static void tcbdbcachepurge(TCBDB *bdb) { + bool clk = BDBLOCKCACHE(bdb); + int tsiz; + const char *tmp; + tcmapiterinit(bdb->leafc); + while ((tmp = tcmapiternext(bdb->leafc, &tsiz)) != NULL) { + int lsiz; + BDBLEAF *leaf = (BDBLEAF *) tcmapiterval(tmp, &lsiz); + if (!leaf->dirty) continue; + TCPTRLIST *recs = leaf->recs; + int ln = TCPTRLISTNUM(recs); + for (int i = 0; i < ln; i++) { + BDBREC *rec = TCPTRLISTVAL(recs, i); + if (rec->rest) tclistdel(rec->rest); + TCFREE(rec); + } + tcptrlistdel(recs); + tcmapout(bdb->leafc, tmp, tsiz); + } + tcmapiterinit(bdb->nodec); + while ((tmp = tcmapiternext(bdb->nodec, &tsiz)) != NULL) { + int nsiz; + BDBNODE *node = (BDBNODE *) tcmapiterval(tmp, &nsiz); + if (!node->dirty) continue; + TCPTRLIST *idxs = node->idxs; + int ln = TCPTRLISTNUM(idxs); + for (int i = 0; i < ln; i++) { + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + TCFREE(idx); + } + tcptrlistdel(idxs); + tcmapout(bdb->nodec, tmp, tsiz); } - tcptrlistdel(idxs); - tcmapout(bdb->nodec, tmp, tsiz); - } - if(clk) BDBUNLOCKCACHE(bdb); + if (clk) BDBUNLOCKCACHE(bdb); } - /* Open a database file and connect a B+ tree database object. `bdb' specifies the B+ tree database object. `path' specifies the path of the internal database file. `omode' specifies the connection mode. If successful, the return value is true, else, it is false. */ -static bool tcbdbopenimpl(TCBDB *bdb, const char *path, int omode){ - assert(bdb && path); - int homode = HDBOREADER; - if(omode & BDBOWRITER){ - homode = HDBOWRITER; - if(omode & BDBOCREAT) homode |= HDBOCREAT; - if(omode & BDBOTRUNC) homode |= HDBOTRUNC; - bdb->wmode = true; - } else { - bdb->wmode = false; - } - if(omode & BDBONOLCK) homode |= HDBONOLCK; - if(omode & BDBOLCKNB) homode |= HDBOLCKNB; - if(omode & BDBOTSYNC) homode |= HDBOTSYNC; - tchdbsettype(bdb->hdb, TCDBTBTREE); - if(!tchdbopen(bdb->hdb, path, homode)) return false; - bdb->root = 0; - bdb->first = 0; - bdb->last = 0; - bdb->lnum = 0; - bdb->nnum = 0; - bdb->rnum = 0; - bdb->leafc = tcmapnew2(bdb->lcnum * 2 + 1); - bdb->nodec = tcmapnew2(bdb->ncnum * 2 + 1); - if(bdb->wmode && tchdbrnum(bdb->hdb) < 1){ - BDBLEAF *leaf = tcbdbleafnew(bdb, 0, 0); - bdb->root = leaf->id; - bdb->first = leaf->id; - bdb->last = leaf->id; - bdb->lnum = 1; +static bool tcbdbopenimpl(TCBDB *bdb, const char *path, int omode) { + assert(bdb && path); + int homode = HDBOREADER; + if (omode & BDBOWRITER) { + homode = HDBOWRITER; + if (omode & BDBOCREAT) homode |= HDBOCREAT; + if (omode & BDBOTRUNC) homode |= HDBOTRUNC; + bdb->wmode = true; + } else { + bdb->wmode = false; + } + if (omode & BDBONOLCK) homode |= HDBONOLCK; + if (omode & BDBOLCKNB) homode |= HDBOLCKNB; + if (omode & BDBOTSYNC) homode |= HDBOTSYNC; + tchdbsettype(bdb->hdb, TCDBTBTREE); + if (!tchdbopen(bdb->hdb, path, homode)) return false; + bdb->root = 0; + bdb->first = 0; + bdb->last = 0; + bdb->lnum = 0; bdb->nnum = 0; bdb->rnum = 0; - if(!bdb->cmp){ - bdb->cmp = tccmplexical; - bdb->cmpop = NULL; + bdb->leafc = tcmapnew2(bdb->lcnum * 2 + 1); + bdb->nodec = tcmapnew2(bdb->ncnum * 2 + 1); + if (bdb->wmode && tchdbrnum(bdb->hdb) < 1) { + BDBLEAF *leaf = tcbdbleafnew(bdb, 0, 0); + bdb->root = leaf->id; + bdb->first = leaf->id; + bdb->last = leaf->id; + bdb->lnum = 1; + bdb->nnum = 0; + bdb->rnum = 0; + if (!bdb->cmp) { + bdb->cmp = tccmplexical; + bdb->cmpop = NULL; + } + tcbdbdumpmeta(bdb); + if (!tcbdbleafsave(bdb, leaf)) { + tcmapdel(bdb->nodec); + tcmapdel(bdb->leafc); + tchdbclose(bdb->hdb); + return false; + } } - tcbdbdumpmeta(bdb); - if(!tcbdbleafsave(bdb, leaf)){ - tcmapdel(bdb->nodec); - tcmapdel(bdb->leafc); - tchdbclose(bdb->hdb); - return false; - } - } - tcbdbloadmeta(bdb); - if(!bdb->cmp){ - tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); - tcmapdel(bdb->nodec); - tcmapdel(bdb->leafc); - tchdbclose(bdb->hdb); - return false; - } - if(bdb->lmemb < BDBMINLMEMB || bdb->nmemb < BDBMINNMEMB || - bdb->root < 1 || bdb->first < 1 || bdb->last < 1 || - bdb->lnum < 0 || bdb->nnum < 0 || bdb->rnum < 0){ - tcbdbsetecode(bdb, TCEMETA, __FILE__, __LINE__, __func__); - tcmapdel(bdb->nodec); - tcmapdel(bdb->leafc); - tchdbclose(bdb->hdb); - return false; - } - bdb->open = true; - uint8_t hopts = tchdbopts(bdb->hdb); - uint8_t opts = 0; - if(hopts & HDBTLARGE) opts |= BDBTLARGE; - if(hopts & HDBTDEFLATE) opts |= BDBTDEFLATE; - if(hopts & HDBTBZIP) opts |= BDBTBZIP; - if(hopts & HDBTTCBS) opts |= BDBTTCBS; - if(hopts & HDBTEXCODEC) opts |= BDBTEXCODEC; - bdb->opts = opts; - bdb->hleaf = 0; - bdb->lleaf = 0; - bdb->tran = false; - bdb->rbopaque = NULL; - bdb->clock = 1; - return true; + tcbdbloadmeta(bdb); + if (!bdb->cmp) { + tcbdbsetecode(bdb, TCEINVALID, __FILE__, __LINE__, __func__); + tcmapdel(bdb->nodec); + tcmapdel(bdb->leafc); + tchdbclose(bdb->hdb); + return false; + } + if (bdb->lmemb < BDBMINLMEMB || bdb->nmemb < BDBMINNMEMB || + bdb->root < 1 || bdb->first < 1 || bdb->last < 1 || + bdb->lnum < 0 || bdb->nnum < 0 || bdb->rnum < 0) { + tcbdbsetecode(bdb, TCEMETA, __FILE__, __LINE__, __func__); + tcmapdel(bdb->nodec); + tcmapdel(bdb->leafc); + tchdbclose(bdb->hdb); + return false; + } + bdb->open = true; + uint8_t hopts = tchdbopts(bdb->hdb); + uint8_t opts = 0; + if (hopts & HDBTLARGE) opts |= BDBTLARGE; + if (hopts & HDBTDEFLATE) opts |= BDBTDEFLATE; + if (hopts & HDBTBZIP) opts |= BDBTBZIP; + if (hopts & HDBTTCBS) opts |= BDBTTCBS; + if (hopts & HDBTEXCODEC) opts |= BDBTEXCODEC; + bdb->opts = opts; + bdb->hleaf = 0; + bdb->lleaf = 0; + bdb->tran = false; + bdb->rbopaque = NULL; + bdb->clock = 1; + return true; } - /* Close a B+ tree database object. `bdb' specifies the B+ tree database object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcloseimpl(TCBDB *bdb){ - assert(bdb); - bool err = false; - if(bdb->tran){ - tcbdbcachepurge(bdb); - tchdbwriteopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); - tcbdbloadmeta(bdb); - TCFREE(bdb->rbopaque); - bdb->tran = false; - bdb->rbopaque = NULL; - if(!tchdbtranvoid(bdb->hdb)) err = true; - } - bdb->open = false; - const char *vbuf; - int vsiz; - TCMAP *leafc = bdb->leafc; - tcmapiterinit(leafc); - while((vbuf = tcmapiternext(leafc, &vsiz)) != NULL){ - if(!tcbdbleafcacheout(bdb, (BDBLEAF *)tcmapiterval(vbuf, &vsiz))) err = true; - } - TCMAP *nodec = bdb->nodec; - tcmapiterinit(nodec); - while((vbuf = tcmapiternext(nodec, &vsiz)) != NULL){ - if(!tcbdbnodecacheout(bdb, (BDBNODE *)tcmapiterval(vbuf, &vsiz))) err = true; - } - if(bdb->wmode) tcbdbdumpmeta(bdb); - tcmapdel(bdb->nodec); - tcmapdel(bdb->leafc); - if(!tchdbclose(bdb->hdb)) err = true; - return !err; +static bool tcbdbcloseimpl(TCBDB *bdb) { + assert(bdb); + bool err = false; + if (bdb->tran) { + tcbdbcachepurge(bdb); + tchdbwriteopaque(bdb->hdb, bdb->rbopaque, 0, BDBOPAQUESIZ); + tcbdbloadmeta(bdb); + TCFREE(bdb->rbopaque); + bdb->tran = false; + bdb->rbopaque = NULL; + if (!tchdbtranvoid(bdb->hdb)) err = true; + } + bdb->open = false; + const char *vbuf; + int vsiz; + TCMAP *leafc = bdb->leafc; + tcmapiterinit(leafc); + while ((vbuf = tcmapiternext(leafc, &vsiz)) != NULL) { + if (!tcbdbleafcacheout(bdb, (BDBLEAF *) tcmapiterval(vbuf, &vsiz))) err = true; + } + TCMAP *nodec = bdb->nodec; + tcmapiterinit(nodec); + while ((vbuf = tcmapiternext(nodec, &vsiz)) != NULL) { + if (!tcbdbnodecacheout(bdb, (BDBNODE *) tcmapiterval(vbuf, &vsiz))) err = true; + } + if (bdb->wmode) tcbdbdumpmeta(bdb); + tcmapdel(bdb->nodec); + tcmapdel(bdb->leafc); + if (!tchdbclose(bdb->hdb)) err = true; + return !err; } - /* Store a record into a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. @@ -3077,174 +2954,171 @@ static bool tcbdbcloseimpl(TCBDB *bdb){ `dmode' specifies behavior when the key overlaps. If successful, the return value is true, else, it is false. */ static bool tcbdbputimpl(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - int dmode){ - assert(bdb && kbuf && ksiz >= 0); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return false; - if(!(leaf = tcbdbleafload(bdb, pid))) return false; - hlid = 0; - } - if(!tcbdbleafaddrec(bdb, leaf, dmode, kbuf, ksiz, vbuf, vsiz)){ - if(!bdb->tran) tcbdbcacheadjust(bdb); - return false; - } - int rnum = TCPTRLISTNUM(leaf->recs); - if(rnum > bdb->lmemb || (rnum > 1 && leaf->size > bdb->lsmax)){ - if(hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; - bdb->lschk = 0; - BDBLEAF *newleaf = tcbdbleafdivide(bdb, leaf); - if(!newleaf) return false; - if(leaf->id == bdb->last) bdb->last = newleaf->id; - uint64_t heir = leaf->id; - uint64_t pid = newleaf->id; - BDBREC *rec = TCPTRLISTVAL(newleaf->recs, 0); - char *dbuf = (char *)rec + sizeof(*rec); - int ksiz = rec->ksiz; - char *kbuf; - TCMEMDUP(kbuf, dbuf, ksiz); - while(true){ - BDBNODE *node; - if(bdb->hnum < 1){ - node = tcbdbnodenew(bdb, heir); - tcbdbnodeaddidx(bdb, node, true, pid, kbuf, ksiz); - bdb->root = node->id; - TCFREE(kbuf); - break; - } - uint64_t parent = bdb->hist[--bdb->hnum]; - if(!(node = tcbdbnodeload(bdb, parent))){ - TCFREE(kbuf); + int dmode) { + assert(bdb && kbuf && ksiz >= 0); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return false; + if (!(leaf = tcbdbleafload(bdb, pid))) return false; + hlid = 0; + } + if (!tcbdbleafaddrec(bdb, leaf, dmode, kbuf, ksiz, vbuf, vsiz)) { + if (!bdb->tran) tcbdbcacheadjust(bdb); return false; - } - tcbdbnodeaddidx(bdb, node, false, pid, kbuf, ksiz); - TCFREE(kbuf); - TCPTRLIST *idxs = node->idxs; - int ln = TCPTRLISTNUM(idxs); - if(ln <= bdb->nmemb) break; - int mid = ln / 2; - BDBIDX *idx = TCPTRLISTVAL(idxs, mid); - BDBNODE *newnode = tcbdbnodenew(bdb, idx->pid); - heir = node->id; - pid = newnode->id; - char *ebuf = (char *)idx + sizeof(*idx); - TCMEMDUP(kbuf, ebuf, idx->ksiz); - ksiz = idx->ksiz; - for(int i = mid + 1; i < ln; i++){ - idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - tcbdbnodeaddidx(bdb, newnode, true, idx->pid, ebuf, idx->ksiz); - } - ln = TCPTRLISTNUM(newnode->idxs); - for(int i = 0; i <= ln; i++){ - idx = tcptrlistpop(idxs); - TCFREE(idx); - } - node->dirty = true; - } - if(bdb->capnum > 0 && bdb->rnum > bdb->capnum){ - uint64_t xnum = bdb->rnum - bdb->capnum; - BDBCUR *cur = tcbdbcurnew(bdb); - while((xnum--) > 0){ - if((cur->id < 1 || cur->clock != bdb->clock) && !tcbdbcurfirstimpl(cur)){ - tcbdbcurdel(cur); - return false; + } + int rnum = TCPTRLISTNUM(leaf->recs); + if (rnum > bdb->lmemb || (rnum > 1 && leaf->size > bdb->lsmax)) { + if (hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; + bdb->lschk = 0; + BDBLEAF *newleaf = tcbdbleafdivide(bdb, leaf); + if (!newleaf) return false; + if (leaf->id == bdb->last) bdb->last = newleaf->id; + uint64_t heir = leaf->id; + uint64_t pid = newleaf->id; + BDBREC *rec = TCPTRLISTVAL(newleaf->recs, 0); + char *dbuf = (char *) rec + sizeof (*rec); + int ksiz = rec->ksiz; + char *kbuf; + TCMEMDUP(kbuf, dbuf, ksiz); + while (true) { + BDBNODE *node; + if (bdb->hnum < 1) { + node = tcbdbnodenew(bdb, heir); + tcbdbnodeaddidx(bdb, node, true, pid, kbuf, ksiz); + bdb->root = node->id; + TCFREE(kbuf); + break; + } + uint64_t parent = bdb->hist[--bdb->hnum]; + if (!(node = tcbdbnodeload(bdb, parent))) { + TCFREE(kbuf); + return false; + } + tcbdbnodeaddidx(bdb, node, false, pid, kbuf, ksiz); + TCFREE(kbuf); + TCPTRLIST *idxs = node->idxs; + int ln = TCPTRLISTNUM(idxs); + if (ln <= bdb->nmemb) break; + int mid = ln / 2; + BDBIDX *idx = TCPTRLISTVAL(idxs, mid); + BDBNODE *newnode = tcbdbnodenew(bdb, idx->pid); + heir = node->id; + pid = newnode->id; + char *ebuf = (char *) idx + sizeof (*idx); + TCMEMDUP(kbuf, ebuf, idx->ksiz); + ksiz = idx->ksiz; + for (int i = mid + 1; i < ln; i++) { + idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + tcbdbnodeaddidx(bdb, newnode, true, idx->pid, ebuf, idx->ksiz); + } + ln = TCPTRLISTNUM(newnode->idxs); + for (int i = 0; i <= ln; i++) { + idx = tcptrlistpop(idxs); + TCFREE(idx); + } + node->dirty = true; } - if(!tcbdbcuroutimpl(cur)){ - tcbdbcurdel(cur); - return false; + if (bdb->capnum > 0 && bdb->rnum > bdb->capnum) { + uint64_t xnum = bdb->rnum - bdb->capnum; + BDBCUR *cur = tcbdbcurnew(bdb); + while ((xnum--) > 0) { + if ((cur->id < 1 || cur->clock != bdb->clock) && !tcbdbcurfirstimpl(cur)) { + tcbdbcurdel(cur); + return false; + } + if (!tcbdbcuroutimpl(cur)) { + tcbdbcurdel(cur); + return false; + } + } + tcbdbcurdel(cur); } - } - tcbdbcurdel(cur); + } else if (rnum < 1) { + if (hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; + if (bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; } - } else if(rnum < 1){ - if(hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; - if(bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; - } - if(!bdb->tran && !tcbdbcacheadjust(bdb)) return false; - return true; + if (!bdb->tran && !tcbdbcacheadjust(bdb)) return false; + return true; } - /* Remove a record of a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. If successful, the return value is true, else, it is false. */ -static bool tcbdboutimpl(TCBDB *bdb, const char *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return false; - if(!(leaf = tcbdbleafload(bdb, pid))) return false; - hlid = 0; - } - int ri; - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); - if(!rec){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - tcbdbremoverec(bdb, leaf, rec, ri); - leaf->dirty = true; - if(TCPTRLISTNUM(leaf->recs) < 1){ - if(hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; - if(bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; - } - if(!bdb->tran && !tcbdbcacheadjust(bdb)) return false; - return true; +static bool tcbdboutimpl(TCBDB *bdb, const char *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return false; + if (!(leaf = tcbdbleafload(bdb, pid))) return false; + hlid = 0; + } + int ri; + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); + if (!rec) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + tcbdbremoverec(bdb, leaf, rec, ri); + leaf->dirty = true; + if (TCPTRLISTNUM(leaf->recs) < 1) { + if (hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; + if (bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; + } + if (!bdb->tran && !tcbdbcacheadjust(bdb)) return false; + return true; } - /* Remove records of a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. If successful, the return value is true, else, it is false. */ -static bool tcbdboutlist(TCBDB *bdb, const char *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return false; - if(!(leaf = tcbdbleafload(bdb, pid))) return false; - hlid = 0; - } - int ri; - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); - if(!rec){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - int rnum = 1; - int rsiz = rec->ksiz + rec->vsiz; - if(rec->rest){ - TCLIST *rest = rec->rest; - int ln = TCLISTNUM(rec->rest); - rnum += ln; - for(int i = 0; i < ln; i++){ - rsiz += TCLISTVALSIZ(rest, i); - } - tclistdel(rest); - } - TCFREE(tcptrlistremove(leaf->recs, ri)); - leaf->size -= rsiz; - leaf->dirty = true; - bdb->rnum -= rnum; - if(TCPTRLISTNUM(leaf->recs) < 1){ - if(hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; - if(bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; - } - if(!bdb->tran && !tcbdbcacheadjust(bdb)) return false; - return true; +static bool tcbdboutlist(TCBDB *bdb, const char *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return false; + if (!(leaf = tcbdbleafload(bdb, pid))) return false; + hlid = 0; + } + int ri; + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); + if (!rec) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + int rnum = 1; + int rsiz = rec->ksiz + rec->vsiz; + if (rec->rest) { + TCLIST *rest = rec->rest; + int ln = TCLISTNUM(rec->rest); + rnum += ln; + for (int i = 0; i < ln; i++) { + rsiz += TCLISTVALSIZ(rest, i); + } + tclistdel(rest); + } + TCFREE(tcptrlistremove(leaf->recs, ri)); + leaf->size -= rsiz; + leaf->dirty = true; + bdb->rnum -= rnum; + if (TCPTRLISTNUM(leaf->recs) < 1) { + if (hlid > 0 && hlid != tcbdbsearchleaf(bdb, kbuf, ksiz)) return false; + if (bdb->hnum > 0 && !tcbdbleafkill(bdb, leaf)) return false; + } + if (!bdb->tran && !tcbdbcacheadjust(bdb)) return false; + return true; } - /* Retrieve a record in a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. @@ -3253,87 +3127,84 @@ static bool tcbdboutlist(TCBDB *bdb, const char *kbuf, int ksiz){ value is assigned. If successful, the return value is the pointer to the region of the value of the corresponding record. */ -static const char *tcbdbgetimpl(TCBDB *bdb, const char *kbuf, int ksiz, int *sp){ - assert(bdb && kbuf && ksiz >= 0 && sp); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return NULL; - if(!(leaf = tcbdbleafload(bdb, pid))) return NULL; - } - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); - if(!rec){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; - } - *sp = rec->vsiz; - return (char *)rec + sizeof(*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz); +static const char *tcbdbgetimpl(TCBDB *bdb, const char *kbuf, int ksiz, int *sp) { + assert(bdb && kbuf && ksiz >= 0 && sp); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return NULL; + if (!(leaf = tcbdbleafload(bdb, pid))) return NULL; + } + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); + if (!rec) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; + } + *sp = rec->vsiz; + return (char *) rec + sizeof (*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz); } - /* Get the number of records corresponding a key in a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. If successful, the return value is the number of the corresponding records, else, it is 0. */ -static int tcbdbgetnum(TCBDB *bdb, const char *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return 0; - if(!(leaf = tcbdbleafload(bdb, pid))) return 0; - } - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); - if(!rec){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return 0; - } - return rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; +static int tcbdbgetnum(TCBDB *bdb, const char *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return 0; + if (!(leaf = tcbdbleafload(bdb, pid))) return 0; + } + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); + if (!rec) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return 0; + } + return rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; } - /* Retrieve records in a B+ tree database object. `bdb' specifies the B+ tree database object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. If successful, the return value is a list object of the values of the corresponding records. */ -static TCLIST *tcbdbgetlist(TCBDB *bdb, const char *kbuf, int ksiz){ - assert(bdb && kbuf && ksiz >= 0); - BDBLEAF *leaf = NULL; - uint64_t hlid = bdb->hleaf; - if(hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))){ - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1) return NULL; - if(!(leaf = tcbdbleafload(bdb, pid))) return NULL; - } - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); - if(!rec){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; - } - TCLIST *vals; - TCLIST *rest = rec->rest; - if(rest){ - int ln = TCLISTNUM(rest); - vals = tclistnew2(ln + 1); - TCLISTPUSH(vals, (char *)rec + sizeof(*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); - for(int i = 0; i < ln; i++){ - const char *vbuf; - int vsiz; - TCLISTVAL(vbuf, rest, i, vsiz); - TCLISTPUSH(vals, vbuf, vsiz); - } - } else { - vals = tclistnew2(1); - TCLISTPUSH(vals, (char *)rec + sizeof(*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); - } - return vals; +static TCLIST *tcbdbgetlist(TCBDB *bdb, const char *kbuf, int ksiz) { + assert(bdb && kbuf && ksiz >= 0); + BDBLEAF *leaf = NULL; + uint64_t hlid = bdb->hleaf; + if (hlid < 1 || !(leaf = tcbdbgethistleaf(bdb, kbuf, ksiz, hlid))) { + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) return NULL; + if (!(leaf = tcbdbleafload(bdb, pid))) return NULL; + } + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, NULL); + if (!rec) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; + } + TCLIST *vals; + TCLIST *rest = rec->rest; + if (rest) { + int ln = TCLISTNUM(rest); + vals = tclistnew2(ln + 1); + TCLISTPUSH(vals, (char *) rec + sizeof (*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); + for (int i = 0; i < ln; i++) { + const char *vbuf; + int vsiz; + TCLISTVAL(vbuf, rest, i, vsiz); + TCLISTPUSH(vals, vbuf, vsiz); + } + } else { + vals = tclistnew2(1); + TCLISTPUSH(vals, (char *) rec + sizeof (*rec) + rec->ksiz + TCALIGNPAD(rec->ksiz), rec->vsiz); + } + return vals; } - /* Get keys of ranged records in a B+ tree database object. `bdb' specifies the B+ tree database object. `bkbuf' specifies the pointer to the region of the key of the beginning border. @@ -3346,53 +3217,52 @@ static TCLIST *tcbdbgetlist(TCBDB *bdb, const char *kbuf, int ksiz){ `keys' specifies a list object to store the result. If successful, the return value is true, else, it is false. */ static bool tcbdbrangeimpl(TCBDB *bdb, const char *bkbuf, int bksiz, bool binc, - const char *ekbuf, int eksiz, bool einc, int max, TCLIST *keys){ - assert(bdb && keys); - bool err = false; - BDBCUR *cur = tcbdbcurnew(bdb); - if(bkbuf){ - tcbdbcurjumpimpl(cur, bkbuf, bksiz, true); - } else { - tcbdbcurfirstimpl(cur); - } - TCCMP cmp = bdb->cmp; - void *cmpop = bdb->cmpop; - const char *lbuf = NULL; - int lsiz = 0; - while(cur->id > 0){ - const char *kbuf, *vbuf; - int ksiz, vsiz; - if(!tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - if(tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; - break; - } - if(bkbuf && !binc){ - if(cmp(kbuf, ksiz, bkbuf, bksiz, cmpop) == 0){ + const char *ekbuf, int eksiz, bool einc, int max, TCLIST *keys) { + assert(bdb && keys); + bool err = false; + BDBCUR *cur = tcbdbcurnew(bdb); + if (bkbuf) { + tcbdbcurjumpimpl(cur, bkbuf, bksiz, true); + } else { + tcbdbcurfirstimpl(cur); + } + TCCMP cmp = bdb->cmp; + void *cmpop = bdb->cmpop; + const char *lbuf = NULL; + int lsiz = 0; + while (cur->id > 0) { + const char *kbuf, *vbuf; + int ksiz, vsiz; + if (!tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + if (tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; + break; + } + if (bkbuf && !binc) { + if (cmp(kbuf, ksiz, bkbuf, bksiz, cmpop) == 0) { + tcbdbcurnextimpl(cur); + continue; + } + bkbuf = NULL; + } + if (ekbuf) { + if (einc) { + if (cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) > 0) break; + } else { + if (cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) >= 0) break; + } + } + if (!lbuf || lsiz != ksiz || memcmp(kbuf, lbuf, ksiz)) { + TCLISTPUSH(keys, kbuf, ksiz); + if (max >= 0 && TCLISTNUM(keys) >= max) break; + lbuf = kbuf; + lsiz = ksiz; + } tcbdbcurnextimpl(cur); - continue; - } - bkbuf = NULL; - } - if(ekbuf){ - if(einc){ - if(cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) > 0) break; - } else { - if(cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) >= 0) break; - } } - if(!lbuf || lsiz != ksiz || memcmp(kbuf, lbuf, ksiz)){ - TCLISTPUSH(keys, kbuf, ksiz); - if(max >= 0 && TCLISTNUM(keys) >= max) break; - lbuf = kbuf; - lsiz = ksiz; - } - tcbdbcurnextimpl(cur); - } - tcbdbcurdel(cur); - return !err; + tcbdbcurdel(cur); + return !err; } - /* Get forward matching keys in a B+ tree database object. `bdb' specifies the B+ tree database object. `pbuf' specifies the pointer to the region of the prefix. @@ -3400,36 +3270,35 @@ static bool tcbdbrangeimpl(TCBDB *bdb, const char *bkbuf, int bksiz, bool binc, `max' specifies the maximum number of keys to be fetched. `keys' specifies a list object to store the result. If successful, the return value is true, else, it is false. */ -static bool tcbdbrangefwm(TCBDB *bdb, const char *pbuf, int psiz, int max, TCLIST *keys){ - assert(bdb && pbuf && psiz >= 0 && keys); - bool err = false; - if(max < 0) max = INT_MAX; - if(max < 1) return true; - BDBCUR *cur = tcbdbcurnew(bdb); - tcbdbcurjumpimpl(cur, pbuf, psiz, true); - const char *lbuf = NULL; - int lsiz = 0; - while(cur->id > 0){ - const char *kbuf, *vbuf; - int ksiz, vsiz; - if(!tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - if(tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; - break; - } - if(ksiz < psiz || memcmp(kbuf, pbuf, psiz)) break; - if(!lbuf || lsiz != ksiz || memcmp(kbuf, lbuf, ksiz)){ - TCLISTPUSH(keys, kbuf, ksiz); - if(TCLISTNUM(keys) >= max) break; - lbuf = kbuf; - lsiz = ksiz; +static bool tcbdbrangefwm(TCBDB *bdb, const char *pbuf, int psiz, int max, TCLIST *keys) { + assert(bdb && pbuf && psiz >= 0 && keys); + bool err = false; + if (max < 0) max = INT_MAX; + if (max < 1) return true; + BDBCUR *cur = tcbdbcurnew(bdb); + tcbdbcurjumpimpl(cur, pbuf, psiz, true); + const char *lbuf = NULL; + int lsiz = 0; + while (cur->id > 0) { + const char *kbuf, *vbuf; + int ksiz, vsiz; + if (!tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + if (tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; + break; + } + if (ksiz < psiz || memcmp(kbuf, pbuf, psiz)) break; + if (!lbuf || lsiz != ksiz || memcmp(kbuf, lbuf, ksiz)) { + TCLISTPUSH(keys, kbuf, ksiz); + if (TCLISTNUM(keys) >= max) break; + lbuf = kbuf; + lsiz = ksiz; + } + tcbdbcurnextimpl(cur); } - tcbdbcurnextimpl(cur); - } - tcbdbcurdel(cur); - return !err; + tcbdbcurdel(cur); + return !err; } - /* Optimize the file of a B+ tree database object. `bdb' specifies the B+ tree database object. `lmemb' specifies the number of members in each leaf page. @@ -3440,547 +3309,533 @@ static bool tcbdbrangefwm(TCBDB *bdb, const char *pbuf, int psiz, int max, TCLIS `opts' specifies options by bitwise-or. If successful, the return value is true, else, it is false. */ static bool tcbdboptimizeimpl(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(bdb); - char *opath = tcstrdup(tchdbpath(bdb->hdb)); - char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", opath, MYEXTCHR, MYEXTCHR, tchdbinode(bdb->hdb)); - int omode = (tchdbomode(bdb->hdb) & ~BDBOCREAT) & ~BDBOTRUNC; - TCBDB *tbdb = tcbdbnew(); - HANDLE dbgfd = tchdbdbgfd(bdb->hdb); - if(!INVALIDHANDLE(dbgfd)) tcbdbsetdbgfd(tbdb, dbgfd); - tcbdbsetcmpfunc(tbdb, bdb->cmp, bdb->cmpop); - TCCODEC enc, dec; - void *encop, *decop; - tchdbcodecfunc(bdb->hdb, &enc, &encop, &dec, &decop); - if(enc && dec) tcbdbsetcodecfunc(tbdb, enc, encop, dec, decop); - if(lmemb < 1) lmemb = bdb->lmemb; - if(nmemb < 1) nmemb = bdb->nmemb; - if(bnum < 1) bnum = tchdbrnum(bdb->hdb) * 2 + 1; - if(apow < 0) apow = tclog2l(tchdbalign(bdb->hdb)); - if(fpow < 0) fpow = tclog2l(tchdbfbpmax(bdb->hdb)); - if(opts == UINT8_MAX) opts = bdb->opts; - tcbdbtune(tbdb, lmemb, nmemb, bnum, apow, fpow, opts); - tcbdbsetcache(tbdb, 1, 1); - tcbdbsetlsmax(tbdb, bdb->lsmax); - uint32_t lcnum = bdb->lcnum; - uint32_t ncnum = bdb->ncnum; - bdb->lcnum = BDBLEVELMAX; - bdb->ncnum = BDBCACHEOUT * 2; - tbdb->lcnum = BDBLEVELMAX; - tbdb->ncnum = BDBCACHEOUT * 2; - if(!tcbdbopen(tbdb, tpath, BDBOWRITER | BDBOCREAT | BDBOTRUNC) || - !tchdbcopyopaque(tbdb->hdb, bdb->hdb, 0, -1)){ + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(bdb); + char *opath = tcstrdup(tchdbpath(bdb->hdb)); + char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", opath, MYEXTCHR, MYEXTCHR, tchdbinode(bdb->hdb)); + int omode = (tchdbomode(bdb->hdb) & ~BDBOCREAT) & ~BDBOTRUNC; + TCBDB *tbdb = tcbdbnew(); + HANDLE dbgfd = tchdbdbgfd(bdb->hdb); + if (!INVALIDHANDLE(dbgfd)) tcbdbsetdbgfd(tbdb, dbgfd); + tcbdbsetcmpfunc(tbdb, bdb->cmp, bdb->cmpop); + TCCODEC enc, dec; + void *encop, *decop; + tchdbcodecfunc(bdb->hdb, &enc, &encop, &dec, &decop); + if (enc && dec) tcbdbsetcodecfunc(tbdb, enc, encop, dec, decop); + if (lmemb < 1) lmemb = bdb->lmemb; + if (nmemb < 1) nmemb = bdb->nmemb; + if (bnum < 1) bnum = tchdbrnum(bdb->hdb) * 2 + 1; + if (apow < 0) apow = tclog2l(tchdbalign(bdb->hdb)); + if (fpow < 0) fpow = tclog2l(tchdbfbpmax(bdb->hdb)); + if (opts == UINT8_MAX) opts = bdb->opts; + tcbdbtune(tbdb, lmemb, nmemb, bnum, apow, fpow, opts); + tcbdbsetcache(tbdb, 1, 1); + tcbdbsetlsmax(tbdb, bdb->lsmax); + uint32_t lcnum = bdb->lcnum; + uint32_t ncnum = bdb->ncnum; + bdb->lcnum = BDBLEVELMAX; + bdb->ncnum = BDBCACHEOUT * 2; + tbdb->lcnum = BDBLEVELMAX; + tbdb->ncnum = BDBCACHEOUT * 2; + if (!tcbdbopen(tbdb, tpath, BDBOWRITER | BDBOCREAT | BDBOTRUNC) || + !tchdbcopyopaque(tbdb->hdb, bdb->hdb, 0, -1)) { + tcbdbdel(tbdb); + TCFREE(tpath); + TCFREE(opath); + return false; + } + bool err = false; + BDBCUR *cur = tcbdbcurnew(bdb); + tcbdbcurfirstimpl(cur); + const char *kbuf, *vbuf; + int ksiz, vsiz; + int cnt = 0; + while (!err && cur->id > 0 && tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + if (!tcbdbputdup(tbdb, kbuf, ksiz, vbuf, vsiz)) { + tcbdbsetecode(bdb, tcbdbecode(tbdb), __FILE__, __LINE__, __func__); + err = true; + } + tcbdbcurnextimpl(cur); + if ((++cnt % 0xf == 0) && !tcbdbcacheadjust(bdb)) err = true; + } + tcbdbcurdel(cur); + if (!tcbdbclose(tbdb)) { + tcbdbsetecode(bdb, tcbdbecode(tbdb), __FILE__, __LINE__, __func__); + err = true; + } + bdb->lcnum = lcnum; + bdb->ncnum = ncnum; tcbdbdel(tbdb); + if (err) { + TCFREE(tpath); + TCFREE(opath); + return false; + } + if (!tcbdbcloseimpl(bdb)) { + TCFREE(opath); + return false; + } + if (!tcunlinkfile(opath)) { + tcbdbsetecode(bdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + if (!tcrenamefile(tpath, opath)) { + tcbdbsetecode(bdb, TCERENAME, __FILE__, __LINE__, __func__); + err = true; + } TCFREE(tpath); + if (err) { + TCFREE(opath); + return false; + } + bool rv = tcbdbopenimpl(bdb, opath, omode); TCFREE(opath); - return false; - } - bool err = false; - BDBCUR *cur = tcbdbcurnew(bdb); - tcbdbcurfirstimpl(cur); - const char *kbuf, *vbuf; - int ksiz, vsiz; - int cnt = 0; - while(!err && cur->id > 0 && tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - if(!tcbdbputdup(tbdb, kbuf, ksiz, vbuf, vsiz)){ - tcbdbsetecode(bdb, tcbdbecode(tbdb), __FILE__, __LINE__, __func__); - err = true; - } - tcbdbcurnextimpl(cur); - if((++cnt % 0xf == 0) && !tcbdbcacheadjust(bdb)) err = true; - } - tcbdbcurdel(cur); - if(!tcbdbclose(tbdb)){ - tcbdbsetecode(bdb, tcbdbecode(tbdb), __FILE__, __LINE__, __func__); - err = true; - } - bdb->lcnum = lcnum; - bdb->ncnum = ncnum; - tcbdbdel(tbdb); - if(err){ - TCFREE(tpath); - TCFREE(opath); - return false; - } - if(!tcbdbcloseimpl(bdb)){ - TCFREE(opath); - return false; - } - if(!tcunlinkfile(opath)){ - tcbdbsetecode(bdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - if(!tcrenamefile(tpath, opath)){ - tcbdbsetecode(bdb, TCERENAME, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(tpath); - if(err){ - TCFREE(opath); - return false; - } - bool rv = tcbdbopenimpl(bdb, opath, omode); - TCFREE(opath); - return rv; + return rv; } - /* Remove all records of a B+ tree database object. `bdb' specifies the B+ tree database object. If successful, the return value is true, else, it is false. */ -static bool tcbdbvanishimpl(TCBDB *bdb){ - assert(bdb); - char *path = tcstrdup(tchdbpath(bdb->hdb)); - int omode = tchdbomode(bdb->hdb); - bool err = false; - if(!tcbdbcloseimpl(bdb)) err = true; - if(!tcbdbopenimpl(bdb, path, BDBOTRUNC | omode)) err = true; - TCFREE(path); - return !err; +static bool tcbdbvanishimpl(TCBDB *bdb) { + assert(bdb); + char *path = tcstrdup(tchdbpath(bdb->hdb)); + int omode = tchdbomode(bdb->hdb); + bool err = false; + if (!tcbdbcloseimpl(bdb)) err = true; + if (!tcbdbopenimpl(bdb, path, BDBOTRUNC | omode)) err = true; + TCFREE(path); + return !err; } - /* Lock a method of the B+ tree database object. `bdb' specifies the B+ tree database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -static bool tcbdblockmethod(TCBDB *bdb, bool wr){ - assert(bdb); - if(wr ? pthread_rwlock_wrlock(bdb->mmtx) != 0 : pthread_rwlock_rdlock(bdb->mmtx) != 0){ - tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +static bool tcbdblockmethod(TCBDB *bdb, bool wr) { + assert(bdb); + if (wr ? pthread_rwlock_wrlock(bdb->mmtx) != 0 : pthread_rwlock_rdlock(bdb->mmtx) != 0) { + tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock a method of the B+ tree database object. `bdb' specifies the B+ tree database object. If successful, the return value is true, else, it is false. */ -static bool tcbdbunlockmethod(TCBDB *bdb){ - assert(bdb); - if(pthread_rwlock_unlock(bdb->mmtx) != 0){ - tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +static bool tcbdbunlockmethod(TCBDB *bdb) { + assert(bdb); + if (pthread_rwlock_unlock(bdb->mmtx) != 0) { + tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock the cache of the B+ tree database object. `bdb' specifies the B+ tree database object. If successful, the return value is true, else, it is false. */ -static bool tcbdblockcache(TCBDB *bdb){ - assert(bdb); - if(pthread_mutex_lock(bdb->cmtx) != 0){ - tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +static bool tcbdblockcache(TCBDB *bdb) { + assert(bdb); + if (pthread_mutex_lock(bdb->cmtx) != 0) { + tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock the cache of the B+ tree database object. `bdb' specifies the B+ tree database object. If successful, the return value is true, else, it is false. */ -static bool tcbdbunlockcache(TCBDB *bdb){ - assert(bdb); - if(pthread_mutex_unlock(bdb->cmtx) != 0){ - tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +static bool tcbdbunlockcache(TCBDB *bdb) { + assert(bdb); + if (pthread_mutex_unlock(bdb->cmtx) != 0) { + tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Move a cursor object to the first record. `cur' specifies the cursor object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurfirstimpl(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - cur->clock = bdb->clock; - cur->id = bdb->first; - cur->kidx = 0; - cur->vidx = 0; - return tcbdbcuradjust(cur, true); +static bool tcbdbcurfirstimpl(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + cur->clock = bdb->clock; + cur->id = bdb->first; + cur->kidx = 0; + cur->vidx = 0; + return tcbdbcuradjust(cur, true); } - /* Move a cursor object to the last record. `cur' specifies the cursor object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurlastimpl(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - cur->clock = bdb->clock; - cur->id = bdb->last; - cur->kidx = INT_MAX; - cur->vidx = INT_MAX; - return tcbdbcuradjust(cur, false); +static bool tcbdbcurlastimpl(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + cur->clock = bdb->clock; + cur->id = bdb->last; + cur->kidx = INT_MAX; + cur->vidx = INT_MAX; + return tcbdbcuradjust(cur, false); } - /* Move a cursor object to around records corresponding a key. `cur' specifies the cursor object. `kbuf' specifies the pointer to the region of the key. `ksiz' specifies the size of the region of the key. `forward' specifies whether the cursor is to be the front of records. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurjumpimpl(BDBCUR *cur, const char *kbuf, int ksiz, bool forward){ - assert(cur && kbuf && ksiz >= 0); - TCBDB *bdb = cur->bdb; - cur->clock = bdb->clock; - uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); - if(pid < 1){ - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; - } - BDBLEAF *leaf = tcbdbleafload(bdb, pid); - if(!leaf){ - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; - } - if(leaf->dead || TCPTRLISTNUM(leaf->recs) < 1){ - cur->id = pid; - cur->kidx = 0; - cur->vidx = 0; - return forward ? tcbdbcurnextimpl(cur) : tcbdbcurprevimpl(cur); - } - int ri; - BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); - if(rec){ - cur->id = pid; +static bool tcbdbcurjumpimpl(BDBCUR *cur, const char *kbuf, int ksiz, bool forward) { + assert(cur && kbuf && ksiz >= 0); + TCBDB *bdb = cur->bdb; + cur->clock = bdb->clock; + uint64_t pid = tcbdbsearchleaf(bdb, kbuf, ksiz); + if (pid < 1) { + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; + } + BDBLEAF *leaf = tcbdbleafload(bdb, pid); + if (!leaf) { + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; + } + if (leaf->dead || TCPTRLISTNUM(leaf->recs) < 1) { + cur->id = pid; + cur->kidx = 0; + cur->vidx = 0; + return forward ? tcbdbcurnextimpl(cur) : tcbdbcurprevimpl(cur); + } + int ri; + BDBREC *rec = tcbdbsearchrec(bdb, leaf, kbuf, ksiz, &ri); + if (rec) { + cur->id = pid; + cur->kidx = ri; + if (forward) { + cur->vidx = 0; + } else { + cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; + } + return true; + } + cur->id = leaf->id; + if (ri > 0 && ri >= TCPTRLISTNUM(leaf->recs)) ri = TCPTRLISTNUM(leaf->recs) - 1; cur->kidx = ri; - if(forward){ - cur->vidx = 0; - } else { - cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; + rec = TCPTRLISTVAL(leaf->recs, ri); + char *dbuf = (char *) rec + sizeof (*rec); + if (forward) { + int rv; + if (bdb->cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + } else { + rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); + } + if (rv < 0) { + cur->vidx = 0; + return true; + } + cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; + return tcbdbcurnextimpl(cur); } - return true; - } - cur->id = leaf->id; - if(ri > 0 && ri >= TCPTRLISTNUM(leaf->recs)) ri = TCPTRLISTNUM(leaf->recs) - 1; - cur->kidx = ri; - rec = TCPTRLISTVAL(leaf->recs, ri); - char *dbuf = (char *)rec + sizeof(*rec); - if(forward){ int rv; - if(bdb->cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); + if (bdb->cmp == tccmplexical) { + TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); } else { - rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); - } - if(rv < 0){ - cur->vidx = 0; - return true; - } - cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; - return tcbdbcurnextimpl(cur); - } - int rv; - if(bdb->cmp == tccmplexical){ - TCCMPLEXICAL(rv, kbuf, ksiz, dbuf, rec->ksiz); - } else { - rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); - } - if(rv > 0){ - cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; - return true; - } - cur->vidx = 0; - return tcbdbcurprevimpl(cur); + rv = bdb->cmp(kbuf, ksiz, dbuf, rec->ksiz, bdb->cmpop); + } + if (rv > 0) { + cur->vidx = rec->rest ? TCLISTNUM(rec->rest) : 0; + return true; + } + cur->vidx = 0; + return tcbdbcurprevimpl(cur); } - /* Adjust a cursor object forward to the suitable record. `cur' specifies the cursor object. `forward' specifies the direction is forward or not. If successful, the return value is true, else, it is false. */ -static bool tcbdbcuradjust(BDBCUR *cur, bool forward){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(cur->clock != bdb->clock){ - if(!tcbdbleafcheck(bdb, cur->id)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; - } - cur->clock = bdb->clock; - } - while(true){ - if(cur->id < 1){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; - } - BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); - if(!leaf) return false; - TCPTRLIST *recs = leaf->recs; - int knum = TCPTRLISTNUM(recs); - if(leaf->dead){ - if(forward){ - cur->id = leaf->next; - cur->kidx = 0; - cur->vidx = 0; - } else { - cur->id = leaf->prev; - cur->kidx = INT_MAX; - cur->vidx = INT_MAX; - } - } else if(cur->kidx < 0){ - if(forward){ - cur->kidx = 0; - cur->vidx = 0; - } else { - cur->id = leaf->prev; - cur->kidx = INT_MAX; - cur->vidx = INT_MAX; - } - } else if(cur->kidx >= knum){ - if(forward){ - cur->id = leaf->next; - cur->kidx = 0; - cur->vidx = 0; - } else { - cur->kidx = knum - 1; - cur->vidx = INT_MAX; - } - } else { - BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); - int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; - if(cur->vidx < 0){ - if(forward){ - cur->vidx = 0; - } else { - cur->kidx--; - cur->vidx = INT_MAX; +static bool tcbdbcuradjust(BDBCUR *cur, bool forward) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (cur->clock != bdb->clock) { + if (!tcbdbleafcheck(bdb, cur->id)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; } - } else if(cur->vidx >= vnum){ - if(forward){ - cur->kidx++; - cur->vidx = 0; - if(cur->kidx >= knum){ - cur->id = leaf->next; + cur->clock = bdb->clock; + } + while (true) { + if (cur->id < 1) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + cur->id = 0; cur->kidx = 0; cur->vidx = 0; - } else { - break; - } + return false; + } + BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); + if (!leaf) return false; + TCPTRLIST *recs = leaf->recs; + int knum = TCPTRLISTNUM(recs); + if (leaf->dead) { + if (forward) { + cur->id = leaf->next; + cur->kidx = 0; + cur->vidx = 0; + } else { + cur->id = leaf->prev; + cur->kidx = INT_MAX; + cur->vidx = INT_MAX; + } + } else if (cur->kidx < 0) { + if (forward) { + cur->kidx = 0; + cur->vidx = 0; + } else { + cur->id = leaf->prev; + cur->kidx = INT_MAX; + cur->vidx = INT_MAX; + } + } else if (cur->kidx >= knum) { + if (forward) { + cur->id = leaf->next; + cur->kidx = 0; + cur->vidx = 0; + } else { + cur->kidx = knum - 1; + cur->vidx = INT_MAX; + } } else { - cur->vidx = vnum - 1; - if(cur->vidx >= 0) break; + BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); + int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; + if (cur->vidx < 0) { + if (forward) { + cur->vidx = 0; + } else { + cur->kidx--; + cur->vidx = INT_MAX; + } + } else if (cur->vidx >= vnum) { + if (forward) { + cur->kidx++; + cur->vidx = 0; + if (cur->kidx >= knum) { + cur->id = leaf->next; + cur->kidx = 0; + cur->vidx = 0; + } else { + break; + } + } else { + cur->vidx = vnum - 1; + if (cur->vidx >= 0) break; + } + } else { + break; + } } - } else { - break; - } } - } - return true; + return true; } - /* Move a cursor object to the previous record. `cur' specifies the cursor object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurprevimpl(BDBCUR *cur){ - assert(cur); - cur->vidx--; - return tcbdbcuradjust(cur, false); +static bool tcbdbcurprevimpl(BDBCUR *cur) { + assert(cur); + cur->vidx--; + return tcbdbcuradjust(cur, false); } - /* Move a cursor object to the next record. `cur' specifies the cursor object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurnextimpl(BDBCUR *cur){ - assert(cur); - cur->vidx++; - return tcbdbcuradjust(cur, true); +static bool tcbdbcurnextimpl(BDBCUR *cur) { + assert(cur); + cur->vidx++; + return tcbdbcuradjust(cur, true); } - /* Insert a record around a cursor object. `cur' specifies the cursor object. `vbuf' specifies the pointer to the region of the value. `vsiz' specifies the size of the region of the value. `cpmode' specifies detail adjustment. If successful, the return value is true, else, it is false. */ -static bool tcbdbcurputimpl(BDBCUR *cur, const char *vbuf, int vsiz, int cpmode){ - assert(cur && vbuf && vsiz >= 0); - TCBDB *bdb = cur->bdb; - if(cur->clock != bdb->clock){ - if(!tcbdbleafcheck(bdb, cur->id)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; - } - cur->clock = bdb->clock; - } - BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); - if(!leaf) return false; - TCPTRLIST *recs = leaf->recs; - if(cur->kidx >= TCPTRLISTNUM(recs)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); - int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; - if(cur->vidx >= vnum){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - char *dbuf = (char *)rec + sizeof(*rec); - int psiz = TCALIGNPAD(rec->ksiz); - BDBREC *orec = rec; - switch(cpmode){ - case BDBCPCURRENT: - if(cur->vidx < 1){ - leaf->size += vsiz - rec->vsiz; - if(vsiz > rec->vsiz){ - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(recs, cur->kidx, rec); - dbuf = (char *)rec + sizeof(*rec); - } - } - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - } else { - leaf->size += vsiz - TCLISTVALSIZ(rec->rest, cur->vidx - 1); - tclistover(rec->rest, cur->vidx - 1, vbuf, vsiz); - } - break; - case BDBCPBEFORE: - leaf->size += vsiz; - if(cur->vidx < 1){ - if(!rec->rest) rec->rest = tclistnew2(1); - tclistunshift(rec->rest, dbuf + rec->ksiz + psiz, rec->vsiz); - if(vsiz > rec->vsiz){ - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(recs, cur->kidx, rec); - dbuf = (char *)rec + sizeof(*rec); - } +static bool tcbdbcurputimpl(BDBCUR *cur, const char *vbuf, int vsiz, int cpmode) { + assert(cur && vbuf && vsiz >= 0); + TCBDB *bdb = cur->bdb; + if (cur->clock != bdb->clock) { + if (!tcbdbleafcheck(bdb, cur->id)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; } - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - } else { - TCLISTINSERT(rec->rest, cur->vidx - 1, vbuf, vsiz); - } - bdb->rnum++; - break; - case BDBCPAFTER: - leaf->size += vsiz; - if(!rec->rest) rec->rest = tclistnew2(1); - TCLISTINSERT(rec->rest, cur->vidx, vbuf, vsiz); - cur->vidx++; - bdb->rnum++; - break; - } - leaf->dirty = true; - return true; + cur->clock = bdb->clock; + } + BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); + if (!leaf) return false; + TCPTRLIST *recs = leaf->recs; + if (cur->kidx >= TCPTRLISTNUM(recs)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); + int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; + if (cur->vidx >= vnum) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + char *dbuf = (char *) rec + sizeof (*rec); + int psiz = TCALIGNPAD(rec->ksiz); + BDBREC *orec = rec; + switch (cpmode) { + case BDBCPCURRENT: + if (cur->vidx < 1) { + leaf->size += vsiz - rec->vsiz; + if (vsiz > rec->vsiz) { + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(recs, cur->kidx, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + } else { + leaf->size += vsiz - TCLISTVALSIZ(rec->rest, cur->vidx - 1); + tclistover(rec->rest, cur->vidx - 1, vbuf, vsiz); + } + break; + case BDBCPBEFORE: + leaf->size += vsiz; + if (cur->vidx < 1) { + if (!rec->rest) rec->rest = tclistnew2(1); + tclistunshift(rec->rest, dbuf + rec->ksiz + psiz, rec->vsiz); + if (vsiz > rec->vsiz) { + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(recs, cur->kidx, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + } else { + TCLISTINSERT(rec->rest, cur->vidx - 1, vbuf, vsiz); + } + bdb->rnum++; + break; + case BDBCPAFTER: + leaf->size += vsiz; + if (!rec->rest) rec->rest = tclistnew2(1); + TCLISTINSERT(rec->rest, cur->vidx, vbuf, vsiz); + cur->vidx++; + bdb->rnum++; + break; + } + leaf->dirty = true; + return true; } - /* Delete the record where a cursor object is. `cur' specifies the cursor object. If successful, the return value is true, else, it is false. */ -static bool tcbdbcuroutimpl(BDBCUR *cur){ - assert(cur); - TCBDB *bdb = cur->bdb; - if(cur->clock != bdb->clock){ - if(!tcbdbleafcheck(bdb, cur->id)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; +static bool tcbdbcuroutimpl(BDBCUR *cur) { + assert(cur); + TCBDB *bdb = cur->bdb; + if (cur->clock != bdb->clock) { + if (!tcbdbleafcheck(bdb, cur->id)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; + } + cur->clock = bdb->clock; } - cur->clock = bdb->clock; - } - BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); - if(!leaf) return false; - TCPTRLIST *recs = leaf->recs; - if(cur->kidx >= TCPTRLISTNUM(recs)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); - char *dbuf = (char *)rec + sizeof(*rec); - int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; - if(cur->vidx >= vnum){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - if(rec->rest){ - if(cur->vidx < 1){ - leaf->size -= rec->vsiz; - int vsiz; - char *vbuf = tclistshift(rec->rest, &vsiz); - int psiz = TCALIGNPAD(rec->ksiz); - if(vsiz > rec->vsiz){ - BDBREC *orec = rec; - TCREALLOC(rec, rec, sizeof(*rec) + rec->ksiz + psiz + vsiz + 1); - if(rec != orec){ - tcptrlistover(leaf->recs, cur->kidx, rec); - dbuf = (char *)rec + sizeof(*rec); + BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); + if (!leaf) return false; + TCPTRLIST *recs = leaf->recs; + if (cur->kidx >= TCPTRLISTNUM(recs)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); + char *dbuf = (char *) rec + sizeof (*rec); + int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; + if (cur->vidx >= vnum) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + if (rec->rest) { + if (cur->vidx < 1) { + leaf->size -= rec->vsiz; + int vsiz; + char *vbuf = tclistshift(rec->rest, &vsiz); + int psiz = TCALIGNPAD(rec->ksiz); + if (vsiz > rec->vsiz) { + BDBREC *orec = rec; + TCREALLOC(rec, rec, sizeof (*rec) + rec->ksiz + psiz + vsiz + 1); + if (rec != orec) { + tcptrlistover(leaf->recs, cur->kidx, rec); + dbuf = (char *) rec + sizeof (*rec); + } + } + memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); + dbuf[rec->ksiz + psiz + vsiz] = '\0'; + rec->vsiz = vsiz; + TCFREE(vbuf); + } else { + int vsiz; + char *vbuf = tclistremove(rec->rest, cur->vidx - 1, &vsiz); + leaf->size -= vsiz; + TCFREE(vbuf); + } + if (TCLISTNUM(rec->rest) < 1) { + tclistdel(rec->rest); + rec->rest = NULL; } - } - memcpy(dbuf + rec->ksiz + psiz, vbuf, vsiz); - dbuf[rec->ksiz+psiz+vsiz] = '\0'; - rec->vsiz = vsiz; - TCFREE(vbuf); } else { - int vsiz; - char *vbuf = tclistremove(rec->rest, cur->vidx - 1, &vsiz); - leaf->size -= vsiz; - TCFREE(vbuf); - } - if(TCLISTNUM(rec->rest) < 1){ - tclistdel(rec->rest); - rec->rest = NULL; - } - } else { - leaf->size -= rec->ksiz + rec->vsiz; - if(TCPTRLISTNUM(recs) < 2){ - uint64_t pid = tcbdbsearchleaf(bdb, dbuf, rec->ksiz); - if(pid < 1) return false; - if(bdb->hnum > 0){ - if(!(leaf = tcbdbleafload(bdb, pid))) return false; - if(!tcbdbleafkill(bdb, leaf)) return false; - if(leaf->next != 0){ - cur->id = leaf->next; - cur->kidx = 0; - cur->vidx = 0; - cur->clock = bdb->clock; + leaf->size -= rec->ksiz + rec->vsiz; + if (TCPTRLISTNUM(recs) < 2) { + uint64_t pid = tcbdbsearchleaf(bdb, dbuf, rec->ksiz); + if (pid < 1) return false; + if (bdb->hnum > 0) { + if (!(leaf = tcbdbleafload(bdb, pid))) return false; + if (!tcbdbleafkill(bdb, leaf)) return false; + if (leaf->next != 0) { + cur->id = leaf->next; + cur->kidx = 0; + cur->vidx = 0; + cur->clock = bdb->clock; + } + } } - } + TCFREE(tcptrlistremove(leaf->recs, cur->kidx)); } - TCFREE(tcptrlistremove(leaf->recs, cur->kidx)); - } - bdb->rnum--; - leaf->dirty = true; - return tcbdbcuradjust(cur, true) || tchdbecode(bdb->hdb) == TCENOREC; + bdb->rnum--; + leaf->dirty = true; + return tcbdbcuradjust(cur, true) || tchdbecode(bdb->hdb) == TCENOREC; } - /* Get the key and the value of the current record of the cursor object. `cur' specifies the cursor object. `kbp' specifies the pointer to the variable into which the pointer to the region of the key is @@ -3990,83 +3845,82 @@ static bool tcbdbcuroutimpl(BDBCUR *cur){ is assgined. `vsp' specifies the pointer to the variable into which the size of the value region is assigned. */ -static bool tcbdbcurrecimpl(BDBCUR *cur, const char **kbp, int *ksp, const char **vbp, int *vsp){ - assert(cur && kbp && ksp && vbp && vsp); - TCBDB *bdb = cur->bdb; - if(cur->clock != bdb->clock){ - if(!tcbdbleafcheck(bdb, cur->id)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - cur->id = 0; - cur->kidx = 0; - cur->vidx = 0; - return false; +static bool tcbdbcurrecimpl(BDBCUR *cur, const char **kbp, int *ksp, const char **vbp, int *vsp) { + assert(cur && kbp && ksp && vbp && vsp); + TCBDB *bdb = cur->bdb; + if (cur->clock != bdb->clock) { + if (!tcbdbleafcheck(bdb, cur->id)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + cur->id = 0; + cur->kidx = 0; + cur->vidx = 0; + return false; + } + cur->clock = bdb->clock; } - cur->clock = bdb->clock; - } - BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); - if(!leaf) return false; - TCPTRLIST *recs = leaf->recs; - if(cur->kidx >= TCPTRLISTNUM(recs)){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); - char *dbuf = (char *)rec + sizeof(*rec); - int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; - if(cur->vidx >= vnum){ - tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - *kbp = dbuf; - *ksp = rec->ksiz; - if(cur->vidx > 0){ - *vbp = tclistval(rec->rest, cur->vidx - 1, vsp); - } else { - *vbp = dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz); - *vsp = rec->vsiz; - } - return true; + BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); + if (!leaf) return false; + TCPTRLIST *recs = leaf->recs; + if (cur->kidx >= TCPTRLISTNUM(recs)) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + BDBREC *rec = TCPTRLISTVAL(recs, cur->kidx); + char *dbuf = (char *) rec + sizeof (*rec); + int vnum = rec->rest ? TCLISTNUM(rec->rest) + 1 : 1; + if (cur->vidx >= vnum) { + tcbdbsetecode(bdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + *kbp = dbuf; + *ksp = rec->ksiz; + if (cur->vidx > 0) { + *vbp = tclistval(rec->rest, cur->vidx - 1, vsp); + } else { + *vbp = dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz); + *vsp = rec->vsiz; + } + return true; } - /* Process each record atomically of a B+ tree database object. `func' specifies the pointer to the iterator function called for each record. `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If successful, the return value is true, else, it is false. */ -static bool tcbdbforeachimpl(TCBDB *bdb, TCITER iter, void *op){ - assert(bdb && iter); - bool err = false; - BDBCUR *cur = tcbdbcurnew(bdb); - tcbdbcurfirstimpl(cur); - const char *kbuf, *vbuf; - int ksiz, vsiz; - while(cur->id > 0){ - if(tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)){ - if(!iter(kbuf, ksiz, vbuf, vsiz, op)) break; - tcbdbcurnextimpl(cur); - if(bdb->tran){ - if(cur->id > 0){ - BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); - if(!leaf){ - err = true; - break; - } - if(!leaf->dirty && !tcbdbleafcacheout(bdb, leaf)){ - err = false; +static bool tcbdbforeachimpl(TCBDB *bdb, TCITER iter, void *op) { + assert(bdb && iter); + bool err = false; + BDBCUR *cur = tcbdbcurnew(bdb); + tcbdbcurfirstimpl(cur); + const char *kbuf, *vbuf; + int ksiz, vsiz; + while (cur->id > 0) { + if (tcbdbcurrecimpl(cur, &kbuf, &ksiz, &vbuf, &vsiz)) { + if (!iter(kbuf, ksiz, vbuf, vsiz, op)) break; + tcbdbcurnextimpl(cur); + if (bdb->tran) { + if (cur->id > 0) { + BDBLEAF *leaf = tcbdbleafload(bdb, cur->id); + if (!leaf) { + err = true; + break; + } + if (!leaf->dirty && !tcbdbleafcacheout(bdb, leaf)) { + err = false; + break; + } + } + } else if (TCMAPRNUM(bdb->leafc) > bdb->lcnum && !tcbdbcacheadjust(bdb)) { + err = true; + break; + } + } else { + if (tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; break; - } } - } else if(TCMAPRNUM(bdb->leafc) > bdb->lcnum && !tcbdbcacheadjust(bdb)){ - err = true; - break; - } - } else { - if(tchdbecode(bdb->hdb) != TCEINVALID && tchdbecode(bdb->hdb) != TCENOREC) err = true; - break; } - } - tcbdbcurdel(cur); - return !err; + tcbdbcurdel(cur); + return !err; } @@ -4075,128 +3929,125 @@ static bool tcbdbforeachimpl(TCBDB *bdb, TCITER iter, void *op){ * debugging functions *************************************************************************************************/ - /* Print meta data of the header into the debugging output. `bdb' specifies the B+ tree database object. */ -void tcbdbprintmeta(TCBDB *bdb){ - assert(bdb); - HANDLE dbgfd = tchdbdbgfd(bdb->hdb); - if (INVALIDHANDLE(dbgfd)) { - dbgfd = GET_STDOUT_HANDLE(); - } - char buf[BDBPAGEBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "META:"); - wp += sprintf(wp, " mmtx=%p", (void *)bdb->mmtx); - wp += sprintf(wp, " cmtx=%p", (void *)bdb->cmtx); - wp += sprintf(wp, " hdb=%p", (void *)bdb->hdb); - //wp += sprintf(wp, " opaque=%p", (void *)bdb->opaque); - wp += sprintf(wp, " open=%d", bdb->open); - wp += sprintf(wp, " wmode=%d", bdb->wmode); - wp += sprintf(wp, " lmemb=%u", bdb->lmemb); - wp += sprintf(wp, " nmemb=%u", bdb->nmemb); - wp += sprintf(wp, " opts=%u", bdb->opts); - wp += sprintf(wp, " root=%" PRIxMAX "", (unsigned long long)bdb->root); - wp += sprintf(wp, " first=%" PRIxMAX "", (unsigned long long)bdb->first); - wp += sprintf(wp, " last=%" PRIxMAX "", (unsigned long long)bdb->last); - wp += sprintf(wp, " lnum=%" PRIuMAX "", (unsigned long long)bdb->lnum); - wp += sprintf(wp, " nnum=%" PRIuMAX "", (unsigned long long)bdb->nnum); - wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long)bdb->rnum); - wp += sprintf(wp, " leafc=%p", (void *)bdb->leafc); - wp += sprintf(wp, " nodec=%p", (void *)bdb->nodec); - wp += sprintf(wp, " cmp=%p", (void *)(intptr_t)bdb->cmp); - wp += sprintf(wp, " cmpop=%p", (void *)bdb->cmpop); - wp += sprintf(wp, " lcnum=%u", bdb->lcnum); - wp += sprintf(wp, " ncnum=%u", bdb->ncnum); - wp += sprintf(wp, " lsmax=%u", bdb->lsmax); - wp += sprintf(wp, " lschk=%u", bdb->lschk); - wp += sprintf(wp, " capnum=%" PRIuMAX "", (unsigned long long)bdb->capnum); - wp += sprintf(wp, " hist=%p", (void *)bdb->hist); - wp += sprintf(wp, " hnum=%d", bdb->hnum); - wp += sprintf(wp, " hleaf=%" PRIuMAX "", (unsigned long long)bdb->hleaf); - wp += sprintf(wp, " lleaf=%" PRIuMAX "", (unsigned long long)bdb->lleaf); - wp += sprintf(wp, " tran=%d", bdb->tran); - //wp += sprintf(wp, " rbopaque=%p", (void *)bdb->rbopaque); - wp += sprintf(wp, " clock=%" PRIuMAX "", (unsigned long long)bdb->clock); - wp += sprintf(wp, " cnt_saveleaf=%" PRIdMAX "", (long long)bdb->cnt_saveleaf); - wp += sprintf(wp, " cnt_loadleaf=%" PRIdMAX "", (long long)bdb->cnt_loadleaf); - wp += sprintf(wp, " cnt_killleaf=%" PRIdMAX "", (long long)bdb->cnt_killleaf); - wp += sprintf(wp, " cnt_adjleafc=%" PRIdMAX "", (long long)bdb->cnt_adjleafc); - wp += sprintf(wp, " cnt_savenode=%" PRIdMAX "", (long long)bdb->cnt_savenode); - wp += sprintf(wp, " cnt_loadnode=%" PRIdMAX "", (long long)bdb->cnt_loadnode); - wp += sprintf(wp, " cnt_adjnodec=%" PRIdMAX "", (long long)bdb->cnt_adjnodec); - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); +void tcbdbprintmeta(TCBDB *bdb) { + assert(bdb); + HANDLE dbgfd = tchdbdbgfd(bdb->hdb); + if (INVALIDHANDLE(dbgfd)) { + dbgfd = GET_STDOUT_HANDLE(); + } + char buf[BDBPAGEBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "META:"); + wp += sprintf(wp, " mmtx=%p", (void *) bdb->mmtx); + wp += sprintf(wp, " cmtx=%p", (void *) bdb->cmtx); + wp += sprintf(wp, " hdb=%p", (void *) bdb->hdb); + //wp += sprintf(wp, " opaque=%p", (void *)bdb->opaque); + wp += sprintf(wp, " open=%d", bdb->open); + wp += sprintf(wp, " wmode=%d", bdb->wmode); + wp += sprintf(wp, " lmemb=%u", bdb->lmemb); + wp += sprintf(wp, " nmemb=%u", bdb->nmemb); + wp += sprintf(wp, " opts=%u", bdb->opts); + wp += sprintf(wp, " root=%" PRIxMAX "", (unsigned long long) bdb->root); + wp += sprintf(wp, " first=%" PRIxMAX "", (unsigned long long) bdb->first); + wp += sprintf(wp, " last=%" PRIxMAX "", (unsigned long long) bdb->last); + wp += sprintf(wp, " lnum=%" PRIuMAX "", (unsigned long long) bdb->lnum); + wp += sprintf(wp, " nnum=%" PRIuMAX "", (unsigned long long) bdb->nnum); + wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long) bdb->rnum); + wp += sprintf(wp, " leafc=%p", (void *) bdb->leafc); + wp += sprintf(wp, " nodec=%p", (void *) bdb->nodec); + wp += sprintf(wp, " cmp=%p", (void *) (intptr_t) bdb->cmp); + wp += sprintf(wp, " cmpop=%p", (void *) bdb->cmpop); + wp += sprintf(wp, " lcnum=%u", bdb->lcnum); + wp += sprintf(wp, " ncnum=%u", bdb->ncnum); + wp += sprintf(wp, " lsmax=%u", bdb->lsmax); + wp += sprintf(wp, " lschk=%u", bdb->lschk); + wp += sprintf(wp, " capnum=%" PRIuMAX "", (unsigned long long) bdb->capnum); + wp += sprintf(wp, " hist=%p", (void *) bdb->hist); + wp += sprintf(wp, " hnum=%d", bdb->hnum); + wp += sprintf(wp, " hleaf=%" PRIuMAX "", (unsigned long long) bdb->hleaf); + wp += sprintf(wp, " lleaf=%" PRIuMAX "", (unsigned long long) bdb->lleaf); + wp += sprintf(wp, " tran=%d", bdb->tran); + //wp += sprintf(wp, " rbopaque=%p", (void *)bdb->rbopaque); + wp += sprintf(wp, " clock=%" PRIuMAX "", (unsigned long long) bdb->clock); + wp += sprintf(wp, " cnt_saveleaf=%" PRIdMAX "", (long long) bdb->cnt_saveleaf); + wp += sprintf(wp, " cnt_loadleaf=%" PRIdMAX "", (long long) bdb->cnt_loadleaf); + wp += sprintf(wp, " cnt_killleaf=%" PRIdMAX "", (long long) bdb->cnt_killleaf); + wp += sprintf(wp, " cnt_adjleafc=%" PRIdMAX "", (long long) bdb->cnt_adjleafc); + wp += sprintf(wp, " cnt_savenode=%" PRIdMAX "", (long long) bdb->cnt_savenode); + wp += sprintf(wp, " cnt_loadnode=%" PRIdMAX "", (long long) bdb->cnt_loadnode); + wp += sprintf(wp, " cnt_adjnodec=%" PRIdMAX "", (long long) bdb->cnt_adjnodec); + *(wp++) = '\n'; + tcwrite(dbgfd, buf, wp - buf); } - /* Print records of a leaf object into the debugging output. `bdb' specifies the B+ tree database object. `leaf' specifies the leaf object. */ -void tcbdbprintleaf(TCBDB *bdb, BDBLEAF *leaf){ - assert(bdb && leaf); - HANDLE dbgfd = tchdbdbgfd(bdb->hdb); - TCPTRLIST *recs = leaf->recs; - if(INVALIDHANDLE(dbgfd)) { - dbgfd = GET_STDOUT_HANDLE(); - } - char buf[BDBPAGEBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "LEAF:"); - wp += sprintf(wp, " id:%" PRIxMAX "", (unsigned long long)leaf->id); - wp += sprintf(wp, " size:%u", leaf->size); - wp += sprintf(wp, " prev:%" PRIxMAX "", (unsigned long long)leaf->prev); - wp += sprintf(wp, " next:%" PRIxMAX "", (unsigned long long)leaf->next); - wp += sprintf(wp, " dirty:%d", leaf->dirty); - wp += sprintf(wp, " dead:%d", leaf->dead); - wp += sprintf(wp, " rnum:%d", TCPTRLISTNUM(recs)); - *(wp++) = ' '; - for(int i = 0; i < TCPTRLISTNUM(recs); i++){ - tcwrite(dbgfd, buf, wp - buf); - wp = buf; - BDBREC *rec = TCPTRLISTVAL(recs, i); - char *dbuf = (char *)rec + sizeof(*rec); - wp += sprintf(wp, " [%s:%s]", dbuf, dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz)); - TCLIST *rest = rec->rest; - if(rest){ - for(int j = 0; j < TCLISTNUM(rest); j++){ - wp += sprintf(wp, ":%s", (char *)TCLISTVALPTR(rest, j)); - } +void tcbdbprintleaf(TCBDB *bdb, BDBLEAF *leaf) { + assert(bdb && leaf); + HANDLE dbgfd = tchdbdbgfd(bdb->hdb); + TCPTRLIST *recs = leaf->recs; + if (INVALIDHANDLE(dbgfd)) { + dbgfd = GET_STDOUT_HANDLE(); + } + char buf[BDBPAGEBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "LEAF:"); + wp += sprintf(wp, " id:%" PRIxMAX "", (unsigned long long) leaf->id); + wp += sprintf(wp, " size:%u", leaf->size); + wp += sprintf(wp, " prev:%" PRIxMAX "", (unsigned long long) leaf->prev); + wp += sprintf(wp, " next:%" PRIxMAX "", (unsigned long long) leaf->next); + wp += sprintf(wp, " dirty:%d", leaf->dirty); + wp += sprintf(wp, " dead:%d", leaf->dead); + wp += sprintf(wp, " rnum:%d", TCPTRLISTNUM(recs)); + *(wp++) = ' '; + for (int i = 0; i < TCPTRLISTNUM(recs); i++) { + tcwrite(dbgfd, buf, wp - buf); + wp = buf; + BDBREC *rec = TCPTRLISTVAL(recs, i); + char *dbuf = (char *) rec + sizeof (*rec); + wp += sprintf(wp, " [%s:%s]", dbuf, dbuf + rec->ksiz + TCALIGNPAD(rec->ksiz)); + TCLIST *rest = rec->rest; + if (rest) { + for (int j = 0; j < TCLISTNUM(rest); j++) { + wp += sprintf(wp, ":%s", (char *) TCLISTVALPTR(rest, j)); + } + } } - } - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); + *(wp++) = '\n'; + tcwrite(dbgfd, buf, wp - buf); } - /* Print indices of a node object into the debugging output. `bdb' specifies the B+ tree database object. `node' specifies the node object. */ -void tcbdbprintnode(TCBDB *bdb, BDBNODE *node){ - assert(bdb && node); - HANDLE dbgfd = tchdbdbgfd(bdb->hdb); - TCPTRLIST *idxs = node->idxs; - if(INVALIDHANDLE(dbgfd)) { - dbgfd = GET_STDOUT_HANDLE(); - } - char buf[BDBPAGEBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "NODE:"); - wp += sprintf(wp, " id:%" PRIxMAX "", (unsigned long long)node->id); - wp += sprintf(wp, " heir:%" PRIxMAX "", (unsigned long long)node->heir); - wp += sprintf(wp, " dirty:%d", node->dirty); - wp += sprintf(wp, " dead:%d", node->dead); - wp += sprintf(wp, " rnum:%d", TCPTRLISTNUM(idxs)); - *(wp++) = ' '; - for(int i = 0; i < TCPTRLISTNUM(idxs); i++){ +void tcbdbprintnode(TCBDB *bdb, BDBNODE *node) { + assert(bdb && node); + HANDLE dbgfd = tchdbdbgfd(bdb->hdb); + TCPTRLIST *idxs = node->idxs; + if (INVALIDHANDLE(dbgfd)) { + dbgfd = GET_STDOUT_HANDLE(); + } + char buf[BDBPAGEBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "NODE:"); + wp += sprintf(wp, " id:%" PRIxMAX "", (unsigned long long) node->id); + wp += sprintf(wp, " heir:%" PRIxMAX "", (unsigned long long) node->heir); + wp += sprintf(wp, " dirty:%d", node->dirty); + wp += sprintf(wp, " dead:%d", node->dead); + wp += sprintf(wp, " rnum:%d", TCPTRLISTNUM(idxs)); + *(wp++) = ' '; + for (int i = 0; i < TCPTRLISTNUM(idxs); i++) { + tcwrite(dbgfd, buf, wp - buf); + wp = buf; + BDBIDX *idx = TCPTRLISTVAL(idxs, i); + char *ebuf = (char *) idx + sizeof (*idx); + wp += sprintf(wp, " [%" PRIxMAX ":%s]", (unsigned long long) idx->pid, ebuf); + } + *(wp++) = '\n'; tcwrite(dbgfd, buf, wp - buf); - wp = buf; - BDBIDX *idx = TCPTRLISTVAL(idxs, i); - char *ebuf = (char *)idx + sizeof(*idx); - wp += sprintf(wp, " [%" PRIxMAX ":%s]", (unsigned long long)idx->pid, ebuf); - } - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); } diff --git a/tcejdb/tcbdb.h b/tcejdb/tcbdb.h index 940df67..2da2b54 100644 --- a/tcejdb/tcbdb.h +++ b/tcejdb/tcbdb.h @@ -24,6 +24,7 @@ #define __TCBDB_CLINKAGEBEGIN #define __TCBDB_CLINKAGEEND #endif + __TCBDB_CLINKAGEBEGIN @@ -37,81 +38,81 @@ __TCBDB_CLINKAGEBEGIN *************************************************************************************************/ -typedef struct { /* type of structure for a B+ tree database */ - void *mmtx; /* mutex for method */ - void *cmtx; /* mutex for cache */ - TCHDB *hdb; /* internal database object */ - bool open; /* whether the internal database is opened */ - bool wmode; /* whether to be writable */ - uint32_t lmemb; /* number of members in each leaf */ - uint32_t nmemb; /* number of members in each node */ - uint8_t opts; /* options */ - uint64_t root; /* ID number of the root page */ - uint64_t first; /* ID number of the first leaf */ - uint64_t last; /* ID number of the last leaf */ - uint64_t lnum; /* number of leaves */ - uint64_t nnum; /* number of nodes */ - uint64_t rnum; /* number of records */ - TCMAP *leafc; /* cache for leaves */ - TCMAP *nodec; /* cache for nodes */ - TCCMP cmp; /* pointer to the comparison function */ - void *cmpop; /* opaque object for the comparison function */ - uint32_t lcnum; /* maximum number of cached leaves */ - uint32_t ncnum; /* maximum number of cached nodes */ - uint32_t lsmax; /* maximum size of each leaf */ - uint32_t lschk; /* counter for leaf size checking */ - uint64_t capnum; /* capacity number of records */ - uint64_t *hist; /* history array of visited nodes */ - int hnum; /* number of element of the history array */ - volatile uint64_t hleaf; /* ID number of the leaf referred by the history */ - volatile uint64_t lleaf; /* ID number of the last visited leaf */ - bool tran; /* whether in the transaction */ - char *rbopaque; /* opaque for rollback */ - volatile uint64_t clock; /* logical clock */ - volatile int64_t cnt_saveleaf; /* tesing counter for leaf save times */ - volatile int64_t cnt_loadleaf; /* tesing counter for leaf load times */ - volatile int64_t cnt_killleaf; /* tesing counter for leaf kill times */ - volatile int64_t cnt_adjleafc; /* tesing counter for node cache adjust times */ - volatile int64_t cnt_savenode; /* tesing counter for node save times */ - volatile int64_t cnt_loadnode; /* tesing counter for node load times */ - volatile int64_t cnt_adjnodec; /* tesing counter for node cache adjust times */ +typedef struct { /* type of structure for a B+ tree database */ + void *mmtx; /* mutex for method */ + void *cmtx; /* mutex for cache */ + TCHDB *hdb; /* internal database object */ + bool open; /* whether the internal database is opened */ + bool wmode; /* whether to be writable */ + uint32_t lmemb; /* number of members in each leaf */ + uint32_t nmemb; /* number of members in each node */ + uint8_t opts; /* options */ + uint64_t root; /* ID number of the root page */ + uint64_t first; /* ID number of the first leaf */ + uint64_t last; /* ID number of the last leaf */ + uint64_t lnum; /* number of leaves */ + uint64_t nnum; /* number of nodes */ + uint64_t rnum; /* number of records */ + TCMAP *leafc; /* cache for leaves */ + TCMAP *nodec; /* cache for nodes */ + TCCMP cmp; /* pointer to the comparison function */ + void *cmpop; /* opaque object for the comparison function */ + uint32_t lcnum; /* maximum number of cached leaves */ + uint32_t ncnum; /* maximum number of cached nodes */ + uint32_t lsmax; /* maximum size of each leaf */ + uint32_t lschk; /* counter for leaf size checking */ + uint64_t capnum; /* capacity number of records */ + uint64_t *hist; /* history array of visited nodes */ + int hnum; /* number of element of the history array */ + volatile uint64_t hleaf; /* ID number of the leaf referred by the history */ + volatile uint64_t lleaf; /* ID number of the last visited leaf */ + bool tran; /* whether in the transaction */ + char *rbopaque; /* opaque for rollback */ + volatile uint64_t clock; /* logical clock */ + volatile int64_t cnt_saveleaf; /* tesing counter for leaf save times */ + volatile int64_t cnt_loadleaf; /* tesing counter for leaf load times */ + volatile int64_t cnt_killleaf; /* tesing counter for leaf kill times */ + volatile int64_t cnt_adjleafc; /* tesing counter for node cache adjust times */ + volatile int64_t cnt_savenode; /* tesing counter for node save times */ + volatile int64_t cnt_loadnode; /* tesing counter for node load times */ + volatile int64_t cnt_adjnodec; /* tesing counter for node cache adjust times */ } TCBDB; -enum { /* enumeration for additional flags */ - BDBFOPEN = HDBFOPEN, /* whether opened */ - BDBFFATAL = HDBFFATAL /* whether with fatal error */ +enum { /* enumeration for additional flags */ + BDBFOPEN = HDBFOPEN, /* whether opened */ + BDBFFATAL = HDBFFATAL /* whether with fatal error */ }; -enum { /* enumeration for tuning options */ - BDBTLARGE = 1 << 0, /* use 64-bit bucket array */ - BDBTDEFLATE = 1 << 1, /* compress each page with Deflate */ - BDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ - BDBTTCBS = 1 << 3, /* compress each page with TCBS */ - BDBTEXCODEC = 1 << 4 /* compress each record with outer functions */ +enum { /* enumeration for tuning options */ + BDBTLARGE = 1 << 0, /* use 64-bit bucket array */ + BDBTDEFLATE = 1 << 1, /* compress each page with Deflate */ + BDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ + BDBTTCBS = 1 << 3, /* compress each page with TCBS */ + BDBTEXCODEC = 1 << 4 /* compress each record with outer functions */ }; -enum { /* enumeration for open modes */ - BDBOREADER = 1 << 0, /* open as a reader */ - BDBOWRITER = 1 << 1, /* open as a writer */ - BDBOCREAT = 1 << 2, /* writer creating */ - BDBOTRUNC = 1 << 3, /* writer truncating */ - BDBONOLCK = 1 << 4, /* open without locking */ - BDBOLCKNB = 1 << 5, /* lock without blocking */ - BDBOTSYNC = 1 << 6 /* synchronize every transaction */ +enum { /* enumeration for open modes */ + BDBOREADER = 1 << 0, /* open as a reader */ + BDBOWRITER = 1 << 1, /* open as a writer */ + BDBOCREAT = 1 << 2, /* writer creating */ + BDBOTRUNC = 1 << 3, /* writer truncating */ + BDBONOLCK = 1 << 4, /* open without locking */ + BDBOLCKNB = 1 << 5, /* lock without blocking */ + BDBOTSYNC = 1 << 6 /* synchronize every transaction */ }; -typedef struct { /* type of structure for a B+ tree cursor */ - TCBDB *bdb; /* database object */ - uint64_t clock; /* logical clock */ - uint64_t id; /* ID number of the leaf */ - int32_t kidx; /* number of the key */ - int32_t vidx; /* number of the value */ +typedef struct { /* type of structure for a B+ tree cursor */ + TCBDB *bdb; /* database object */ + uint64_t clock; /* logical clock */ + uint64_t id; /* ID number of the leaf */ + int32_t kidx; /* number of the key */ + int32_t vidx; /* number of the value */ } BDBCUR; -enum { /* enumeration for cursor put mode */ - BDBCPCURRENT, /* current */ - BDBCPBEFORE, /* before */ - BDBCPAFTER /* after */ +enum { /* enumeration for cursor put mode */ + BDBCPCURRENT, /* current */ + BDBCPBEFORE, /* before */ + BDBCPAFTER /* after */ }; @@ -194,7 +195,7 @@ EJDB_EXPORT bool tcbdbsetcmpfunc(TCBDB *bdb, TCCMP cmp, void *cmpop); If successful, the return value is true, else, it is false. Note that the tuning parameters should be set before the database is opened. */ EJDB_EXPORT bool tcbdbtune(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); /* Set the caching parameters of a B+ tree database object. @@ -472,7 +473,7 @@ EJDB_EXPORT int tcbdbvsiz2(TCBDB *bdb, const char *kstr); Because the object of the return value is created with the function `tclistnew', it should be deleted with the function `tclistdel' when it is no longer in use. */ EJDB_EXPORT TCLIST *tcbdbrange(TCBDB *bdb, const void *bkbuf, int bksiz, bool binc, - const void *ekbuf, int eksiz, bool einc, int max); + const void *ekbuf, int eksiz, bool einc, int max); /* Get string keys of ranged records in a B+ tree database object. @@ -490,7 +491,7 @@ EJDB_EXPORT TCLIST *tcbdbrange(TCBDB *bdb, const void *bkbuf, int bksiz, bool bi Because the object of the return value is created with the function `tclistnew', it should be deleted with the function `tclistdel' when it is no longer in use. */ EJDB_EXPORT TCLIST *tcbdbrange2(TCBDB *bdb, const char *bkstr, bool binc, - const char *ekstr, bool einc, int max); + const char *ekstr, bool einc, int max); /* Get forward matching keys in a B+ tree database object. @@ -568,7 +569,7 @@ EJDB_EXPORT bool tcbdbsync(TCBDB *bdb); This function is useful to reduce the size of the database file with data fragmentation by successive updating. */ EJDB_EXPORT bool tcbdboptimize(TCBDB *bdb, int32_t lmemb, int32_t nmemb, - int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); /* Remove all records of a B+ tree database object. @@ -1046,7 +1047,7 @@ EJDB_EXPORT bool tcbdbputdupback2(TCBDB *bdb, const char *kstr, const char *vstr Note that the callback function can not perform any database operation because the function is called in the critical section guarded by the same locks of database operations. */ EJDB_EXPORT bool tcbdbputproc(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - TCPDPROC proc, void *op); + TCPDPROC proc, void *op); /* Move a cursor object to the rear of records corresponding a key. diff --git a/tcejdb/tcbmgr.c b/tcejdb/tcbmgr.c index 55458aa..9877b5c 100644 --- a/tcejdb/tcbmgr.c +++ b/tcejdb/tcbmgr.c @@ -665,8 +665,12 @@ static int procinform(const char *path, int omode){ printf("leaf number: %" PRIuMAX "\n", (unsigned long long)tcbdblnum(bdb)); printf("node number: %" PRIuMAX "\n", (unsigned long long)tcbdbnnum(bdb)); printf("bucket number: %" PRIuMAX "\n", (unsigned long long)tcbdbbnum(bdb)); + +#ifndef NDEBUG if(bdb->hdb->cnt_writerec >= 0) printf("used bucket number: %" PRIdMAX "\n", (long long)tcbdbbnumused(bdb)); +#endif + printf("alignment: %u\n", tcbdbalign(bdb)); printf("free block pool: %u\n", tcbdbfbpmax(bdb)); printf("inode number: %" PRIdMAX "\n", (long long)tcbdbinode(bdb)); diff --git a/tcejdb/tcfdb.c b/tcejdb/tcfdb.c index 87b77dc..f41f445 100644 --- a/tcejdb/tcfdb.c +++ b/tcejdb/tcfdb.c @@ -22,7 +22,7 @@ #define FDBIOBUFSIZ 8192 // size of an I/O buffer #define FDBMAGICDATA "ToKyO CaBiNeT" // magic data for identification -#define FDBHEADSIZ 256 // size of the reagion of the header +#define FDBHEADSIZ 256 // size of the region of the header #define FDBTYPEOFF 32 // offset of the region for the database type #define FDBFLAGSOFF 33 // offset of the region for the additional flags #define FDBRNUMOFF 48 // offset of the region for the record number @@ -32,28 +32,38 @@ #define FDBMINOFF 80 // offset of the region for the minimum ID offset #define FDBMAXOFF 88 // offset of the region for the maximum ID offset #define FDBOPAQUEOFF 128 // offset of the region for the opaque field +#define FDBOPAQUESZ FDBHEADSIZ - FDBOPAQUEOFF // size of opaque data +#define FDBXFSIZINC 1048576 // 1MB increment of extra file size #define FDBDEFWIDTH 255 // default value width #define FDBDEFLIMSIZ (256LL<<20) // default limit size #define FDBRMTXNUM 127 // number of record mutexes -#define FDBTRUNCALW 256 // number of record for truncate allowance #define FDBIDARYUNIT 2048 // size of ID array allocation unit #define FDBWALSUFFIX "wal" // suffix of write ahead logging file -enum { // enumeration for duplication behavior - FDBPDOVER, // overwrite an existing value - FDBPDKEEP, // keep the existing value - FDBPDCAT, // concatenate values - FDBPDADDINT, // add an integer - FDBPDADDDBL, // add a real number - FDBPDPROC // process by a callback function +//pointer to the array region +#define FDBARR(TC_fdb) ((unsigned char *) ((TC_fdb)->map + FDBHEADSIZ)) +#define FDBRP(TC_fdb, TC_id) FDBARR(TC_fdb) + ((TC_id) - 1) * ((TC_fdb)->rsiz) + +enum { // enumeration for duplication behavior + FDBPDOVER, // overwrite an existing value + FDBPDKEEP, // keep the existing value + FDBPDCAT, // concatenate values + FDBPDADDINT, // add an integer + FDBPDADDDBL, // add a real number + FDBPDPROC // process by a callback function }; -typedef struct { // type of structure for a duplication callback - TCPDPROC proc; // function pointer - void *op; // opaque pointer +typedef struct { // type of structure for a duplication callback + TCPDPROC proc; // function pointer + void *op; // opaque pointer } FDBPDPROCOP; +enum { + FDBWRITENOWALL = 1, //do not write into wal file + FDBWRITENOLOCK = 1 << 1, //do not use shared write lock in tcfdbftruncate + FDBTRALLOWSHRINK = 1 << 2 //resize file on truncation +}; /* private macros */ #define FDBLOCKMETHOD(TC_fdb, TC_wr) \ @@ -78,7 +88,12 @@ typedef struct { // type of structure for a duplication ((TC_fdb)->mmtx ? tcfdbunlockwal(TC_fdb) : true) #define FDBTHREADYIELD(TC_fdb) \ do { if((TC_fdb)->mmtx) sched_yield(); } while(false) - +#define FDBLOCKSMEM(TC_fdb, TC_wr) \ + ((TC_fdb)->smtx ? tcfdblocksmem((TC_fdb), (TC_wr)) : ((TC_fdb)->map != NULL)) +#define FDBLOCKSMEM2(TC_fdb, TC_wr) \ + ((TC_fdb)->smtx ? tcfdblocksmem2((TC_fdb), (TC_wr)) : true) +#define FDBUNLOCKSMEM(TC_fdb) \ + ((TC_fdb)->smtx ? tcfdbunlocksmem(TC_fdb) : true) /* private function prototypes */ static void tcfdbdumpmeta(TCFDB *fdb, char *hbuf); @@ -104,17 +119,22 @@ static bool tcfdbvanishimpl(TCFDB *fdb); static bool tcfdbcopyimpl(TCFDB *fdb, const char *path); static bool tcfdbiterjumpimpl(TCFDB *fdb, int64_t id); static bool tcfdbforeachimpl(TCFDB *fdb, TCITER iter, void *op); -static bool tcfdblockmethod(TCFDB *fdb, bool wr); -static bool tcfdbunlockmethod(TCFDB *fdb); -static bool tcfdblockattr(TCFDB *fdb); -static bool tcfdbunlockattr(TCFDB *fdb); -static bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id); -static bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id); -static bool tcfdblockallrecords(TCFDB *fdb, bool wr); -static bool tcfdbunlockallrecords(TCFDB *fdb); -static bool tcfdblockwal(TCFDB *fdb); -static bool tcfdbunlockwal(TCFDB *fdb); - +static bool tcfdbftruncate(TCFDB *fdb, off_t length); +static bool tcfdbftruncate2(TCFDB *fdb, off_t length, int opts); + +EJDB_INLINE bool tcfdblockmethod(TCFDB *fdb, bool wr); +EJDB_INLINE bool tcfdbunlockmethod(TCFDB *fdb); +EJDB_INLINE bool tcfdblockattr(TCFDB *fdb); +EJDB_INLINE bool tcfdbunlockattr(TCFDB *fdb); +EJDB_INLINE bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id); +EJDB_INLINE bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id); +EJDB_INLINE bool tcfdblockallrecords(TCFDB *fdb, bool wr); +EJDB_INLINE bool tcfdbunlockallrecords(TCFDB *fdb); +EJDB_INLINE bool tcfdblockwal(TCFDB *fdb); +EJDB_INLINE bool tcfdbunlockwal(TCFDB *fdb); +EJDB_INLINE bool tcfdblocksmem(TCFDB *fdb, bool wr); +EJDB_INLINE bool tcfdblocksmem2(TCFDB *fdb, bool wr); +EJDB_INLINE bool tcfdbunlocksmem(TCFDB *fdb); /* debugging function prototypes */ void tcfdbprintmeta(TCFDB *fdb); @@ -125,943 +145,932 @@ void tcfdbprintmeta(TCFDB *fdb); * API *************************************************************************************************/ - /* Get the message string corresponding to an error code. */ -const char *tcfdberrmsg(int ecode){ - return tcerrmsg(ecode); +const char *tcfdberrmsg(int ecode) { + return tcerrmsg(ecode); } - /* Create a fixed-length database object. */ -TCFDB *tcfdbnew(void){ - TCFDB *fdb; - TCMALLOC(fdb, sizeof(*fdb)); - tcfdbclear(fdb); - return fdb; +TCFDB *tcfdbnew(void) { + TCFDB *fdb; + TCMALLOC(fdb, sizeof (*fdb)); + tcfdbclear(fdb); + return fdb; } - /* Delete a fixed-length database object. */ -void tcfdbdel(TCFDB *fdb){ - assert(fdb); - if(!INVALIDHANDLE(fdb->fd)) tcfdbclose(fdb); - if(fdb->mmtx){ - pthread_key_delete(*(pthread_key_t *)fdb->eckey); - pthread_mutex_destroy(fdb->wmtx); - pthread_mutex_destroy(fdb->tmtx); - for(int i = FDBRMTXNUM - 1; i >= 0; i--){ - pthread_rwlock_destroy((pthread_rwlock_t *)fdb->rmtxs + i); - } - pthread_mutex_destroy(fdb->amtx); - pthread_rwlock_destroy(fdb->mmtx); - TCFREE(fdb->eckey); - TCFREE(fdb->wmtx); - TCFREE(fdb->tmtx); - TCFREE(fdb->rmtxs); - TCFREE(fdb->amtx); - TCFREE(fdb->mmtx); - } - TCFREE(fdb); +void tcfdbdel(TCFDB *fdb) { + assert(fdb); + if (!INVALIDHANDLE(fdb->fd)) tcfdbclose(fdb); + if (fdb->mmtx) { + pthread_key_delete(*(pthread_key_t *) fdb->eckey); + pthread_mutex_destroy(fdb->wmtx); + pthread_mutex_destroy(fdb->smtx); + pthread_mutex_destroy(fdb->tmtx); + for (int i = FDBRMTXNUM - 1; i >= 0; i--) { + pthread_rwlock_destroy((pthread_rwlock_t *) fdb->rmtxs + i); + } + pthread_mutex_destroy(fdb->amtx); + pthread_rwlock_destroy(fdb->mmtx); + TCFREE(fdb->eckey); + TCFREE(fdb->wmtx); + TCFREE(fdb->smtx); + TCFREE(fdb->tmtx); + TCFREE(fdb->rmtxs); + TCFREE(fdb->amtx); + TCFREE(fdb->mmtx); + } + TCFREE(fdb); } - /* Get the last happened error code of a fixed-length database object. */ -int tcfdbecode(TCFDB *fdb){ - assert(fdb); - return fdb->mmtx ? - (int)(intptr_t)pthread_getspecific(*(pthread_key_t *)fdb->eckey) : fdb->ecode; +int tcfdbecode(TCFDB *fdb) { + assert(fdb); + return fdb->mmtx ? + (int) (intptr_t) pthread_getspecific(*(pthread_key_t *) fdb->eckey) : fdb->ecode; } - /* Set mutual exclusion control of a fixed-length database object for threading. */ -bool tcfdbsetmutex(TCFDB *fdb){ - assert(fdb); - if(fdb->mmtx || !INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - TCMALLOC(fdb->mmtx, sizeof(pthread_rwlock_t)); - TCMALLOC(fdb->amtx, sizeof(pthread_mutex_t)); - TCMALLOC(fdb->rmtxs, sizeof(pthread_rwlock_t) * FDBRMTXNUM); - TCMALLOC(fdb->tmtx, sizeof(pthread_mutex_t)); - TCMALLOC(fdb->wmtx, sizeof(pthread_mutex_t)); - TCMALLOC(fdb->eckey, sizeof(pthread_key_t)); - bool err = false; - if(pthread_rwlock_init(fdb->mmtx, NULL) != 0) err = true; - if(pthread_mutex_init(fdb->amtx, NULL) != 0) err = true; - for(int i = 0; i < FDBRMTXNUM; i++){ - if(pthread_rwlock_init((pthread_rwlock_t *)fdb->rmtxs + i, NULL) != 0) err = true; - } - if(pthread_mutex_init(fdb->tmtx, NULL) != 0) err = true; - if(pthread_mutex_init(fdb->wmtx, NULL) != 0) err = true; - if(pthread_key_create(fdb->eckey, NULL) != 0) err = true; - if(err){ - TCFREE(fdb->eckey); - TCFREE(fdb->wmtx); - TCFREE(fdb->tmtx); - TCFREE(fdb->rmtxs); - TCFREE(fdb->amtx); - TCFREE(fdb->mmtx); - fdb->eckey = NULL; - fdb->wmtx = NULL; - fdb->tmtx = NULL; - fdb->rmtxs = NULL; - fdb->amtx = NULL; - fdb->mmtx = NULL; - return false; - } - return true; +bool tcfdbsetmutex(TCFDB *fdb) { + assert(fdb); + if (fdb->mmtx || !INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + TCMALLOC(fdb->mmtx, sizeof (pthread_rwlock_t)); + TCMALLOC(fdb->amtx, sizeof (pthread_mutex_t)); + TCMALLOC(fdb->rmtxs, sizeof (pthread_rwlock_t) * FDBRMTXNUM); + TCMALLOC(fdb->tmtx, sizeof (pthread_mutex_t)); + TCMALLOC(fdb->wmtx, sizeof (pthread_mutex_t)); + TCMALLOC(fdb->smtx, sizeof (pthread_rwlock_t)); + TCMALLOC(fdb->eckey, sizeof (pthread_key_t)); + bool err = false; + if (pthread_rwlock_init(fdb->mmtx, NULL) != 0) err = true; + if (pthread_rwlock_init(fdb->smtx, NULL) != 0) err = true; + if (pthread_mutex_init(fdb->amtx, NULL) != 0) err = true; + for (int i = 0; i < FDBRMTXNUM; i++) { + if (pthread_rwlock_init((pthread_rwlock_t *) fdb->rmtxs + i, NULL) != 0) err = true; + } + if (pthread_mutex_init(fdb->tmtx, NULL) != 0) err = true; + if (pthread_mutex_init(fdb->wmtx, NULL) != 0) err = true; + if (pthread_key_create(fdb->eckey, NULL) != 0) err = true; + if (err) { + TCFREE(fdb->eckey); + TCFREE(fdb->wmtx); + TCFREE(fdb->smtx); + TCFREE(fdb->tmtx); + TCFREE(fdb->rmtxs); + TCFREE(fdb->amtx); + TCFREE(fdb->mmtx); + fdb->eckey = NULL; + fdb->wmtx = NULL; + fdb->smtx = NULL; + fdb->tmtx = NULL; + fdb->rmtxs = NULL; + fdb->amtx = NULL; + fdb->mmtx = NULL; + return false; + } + return true; } - /* Set the tuning parameters of a fixed-length database object. */ -bool tcfdbtune(TCFDB *fdb, int32_t width, int64_t limsiz){ - assert(fdb); - if(!INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - fdb->width = (width > 0) ? width : FDBDEFWIDTH; - fdb->limsiz = (limsiz > 0) ? limsiz : FDBDEFLIMSIZ; - if(fdb->limsiz < FDBHEADSIZ + fdb->width + sizeof(uint32_t)) - fdb->limsiz = FDBHEADSIZ + fdb->width + sizeof(uint32_t); - fdb->limsiz = tcpagealign(fdb->limsiz); - return true; +bool tcfdbtune(TCFDB *fdb, int32_t width, int64_t limsiz) { + assert(fdb); + if (!INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + fdb->width = (width > 0) ? width : FDBDEFWIDTH; + fdb->limsiz = (limsiz > 0) ? limsiz : FDBDEFLIMSIZ; + if (fdb->limsiz < FDBHEADSIZ + fdb->width + sizeof (uint32_t)) { + fdb->limsiz = FDBHEADSIZ + fdb->width + sizeof (uint32_t); + } + fdb->limsiz = tcpagealign(fdb->limsiz); + return true; } - /* Open a database file and connect a fixed-length database object. */ -bool tcfdbopen(TCFDB *fdb, const char *path, int omode){ - assert(fdb && path); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(!INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - char *rpath = tcrealpath(path); - if(!rpath){ - int ecode = TCEOPEN; - switch(errno){ - case EACCES: ecode = TCENOPERM; break; - case ENOENT: ecode = TCENOFILE; break; - case ENOTDIR: ecode = TCENOFILE; break; - } - tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!tcpathlock(rpath)){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - TCFREE(rpath); +bool tcfdbopen(TCFDB *fdb, const char *path, int omode) { + assert(fdb && path); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (!INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + char *rpath = tcrealpath(path); + if (!rpath) { + tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + if (!tcpathlock(rpath)) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + TCFREE(rpath); + FDBUNLOCKMETHOD(fdb); + return false; + } + bool rv = tcfdbopenimpl(fdb, path, omode); + if (rv) { + fdb->rpath = rpath; + } else { + tcpathunlock(rpath); + TCFREE(rpath); + } FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbopenimpl(fdb, path, omode); - if(rv){ - fdb->rpath = rpath; - } else { - tcpathunlock(rpath); - TCFREE(rpath); - } - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Close a fixed-length database object. */ -bool tcfdbclose(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbclose(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + bool rv = tcfdbcloseimpl(fdb); + tcpathunlock(fdb->rpath); + TCFREE(fdb->rpath); + fdb->rpath = NULL; FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbcloseimpl(fdb); - tcpathunlock(fdb->rpath); - TCFREE(fdb->rpath); - fdb->rpath = NULL; - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Store a record into a fixed-length database object. */ -bool tcfdbput(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){ - assert(fdb && vbuf && vsiz >= 0); - if(!FDBLOCKMETHOD(fdb, id < 1)) return false; - if(INVALIDHANDLE(fdb->fd) || !(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)){ +bool tcfdbput(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz) { + assert(fdb && vbuf && vsiz >= 0); + if (!FDBLOCKMETHOD(fdb, id < 1)) return false; + if (INVALIDHANDLE(fdb->fd) || !(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; + } + bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDOVER); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDOVER); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Store a record with a decimal key into a fixed-length database object. */ -bool tcfdbput2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - return tcfdbput(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); +bool tcfdbput2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + return tcfdbput(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); } - /* Store a string record with a decimal key into a fixed-length database object. */ -bool tcfdbput3(TCFDB *fdb, const char *kstr, const void *vstr){ - assert(fdb && kstr && vstr); - return tcfdbput(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); +bool tcfdbput3(TCFDB *fdb, const char *kstr, const void *vstr) { + assert(fdb && kstr && vstr); + return tcfdbput(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); } - /* Store a new record into a fixed-length database object. */ -bool tcfdbputkeep(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){ - assert(fdb && vbuf && vsiz >= 0); - if(!FDBLOCKMETHOD(fdb, id < 1)) return false; - if(INVALIDHANDLE(fdb->fd) || !(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)){ +bool tcfdbputkeep(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz) { + assert(fdb && vbuf && vsiz >= 0); + if (!FDBLOCKMETHOD(fdb, id < 1)) return false; + if (INVALIDHANDLE(fdb->fd) || !(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; + } + bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDKEEP); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDKEEP); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Store a new record with a decimal key into a fixed-length database object. */ -bool tcfdbputkeep2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - return tcfdbputkeep(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); +bool tcfdbputkeep2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + return tcfdbputkeep(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); } - /* Store a new string record with a decimal key into a fixed-length database object. */ -bool tcfdbputkeep3(TCFDB *fdb, const char *kstr, const void *vstr){ - assert(fdb && kstr && vstr); - return tcfdbputkeep(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); +bool tcfdbputkeep3(TCFDB *fdb, const char *kstr, const void *vstr) { + assert(fdb && kstr && vstr); + return tcfdbputkeep(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); } - /* Concatenate a value at the end of the existing record in a fixed-length database object. */ -bool tcfdbputcat(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){ - assert(fdb && vbuf && vsiz >= 0); - if(!FDBLOCKMETHOD(fdb, id < 1)) return false; - if(INVALIDHANDLE(fdb->fd) || !(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)){ +bool tcfdbputcat(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz) { + assert(fdb && vbuf && vsiz >= 0); + if (!FDBLOCKMETHOD(fdb, id < 1)) return false; + if (INVALIDHANDLE(fdb->fd) || !(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; + } + bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDCAT); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDCAT); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Concatenate a value with a decimal key in a fixed-length database object. */ -bool tcfdbputcat2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - return tcfdbputcat(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); +bool tcfdbputcat2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + return tcfdbputcat(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz); } - /* Concatenate a string value with a decimal key in a fixed-length database object. */ -bool tcfdbputcat3(TCFDB *fdb, const char *kstr, const void *vstr){ - assert(fdb && kstr && vstr); - return tcfdbputcat(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); +bool tcfdbputcat3(TCFDB *fdb, const char *kstr, const void *vstr) { + assert(fdb && kstr && vstr); + return tcfdbputcat(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr)); } - /* Remove a record of a fixed-length database object. */ -bool tcfdbout(TCFDB *fdb, int64_t id){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(id == FDBIDMIN){ - id = fdb->min; - } else if(id == FDBIDMAX){ - id = fdb->max; - } - if(id < 1 || id > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKRECORD(fdb, true, id)){ +bool tcfdbout(TCFDB *fdb, int64_t id) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + if (id == FDBIDMIN) { + id = fdb->min; + } else if (id == FDBIDMAX) { + id = fdb->max; + } + 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; + } + bool rv = tcfdboutimpl(fdb, id); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdboutimpl(fdb, id); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Remove a record with a decimal key of a fixed-length database object. */ -bool tcfdbout2(TCFDB *fdb, const void *kbuf, int ksiz){ - assert(fdb && kbuf && ksiz >= 0); - return tcfdbout(fdb, tcfdbkeytoid(kbuf, ksiz)); +bool tcfdbout2(TCFDB *fdb, const void *kbuf, int ksiz) { + assert(fdb && kbuf && ksiz >= 0); + return tcfdbout(fdb, tcfdbkeytoid(kbuf, ksiz)); } - /* Remove a string record with a decimal key of a fixed-length database object. */ -bool tcfdbout3(TCFDB *fdb, const char *kstr){ - assert(fdb && kstr); - return tcfdbout(fdb, tcfdbkeytoid(kstr, strlen(kstr))); +bool tcfdbout3(TCFDB *fdb, const char *kstr) { + assert(fdb && kstr); + return tcfdbout(fdb, tcfdbkeytoid(kstr, strlen(kstr))); } - /* Retrieve a record in a fixed-length database object. */ -void *tcfdbget(TCFDB *fdb, int64_t id, int *sp){ - assert(fdb && sp); - if(!FDBLOCKMETHOD(fdb, false)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(id == FDBIDMIN){ - id = fdb->min; - } else if(id == FDBIDMAX){ - id = fdb->max; - } - if(id < 1 || id > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKRECORD(fdb, false, id)){ +void *tcfdbget(TCFDB *fdb, int64_t id, int *sp) { + assert(fdb && sp); + if (!FDBLOCKMETHOD(fdb, false)) { + return NULL; + } + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return NULL; + } + if (id == FDBIDMIN) { + id = fdb->min; + } else if (id == FDBIDMAX) { + id = fdb->max; + } + if (id < 1 || id > fdb->limid) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return NULL; + } + if (!FDBLOCKRECORD(fdb, false, id)) { + FDBUNLOCKMETHOD(fdb); + return NULL; + } + if (!FDBLOCKSMEM(fdb, false)) { + FDBUNLOCKRECORD(fdb, id); + FDBUNLOCKMETHOD(fdb); + return false; + } + + const void *vbuf = tcfdbgetimpl(fdb, id, sp); + char *rv = vbuf ? tcmemdup(vbuf, *sp) : NULL; + + FDBUNLOCKSMEM(fdb); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - const void *vbuf = tcfdbgetimpl(fdb, id, sp); - char *rv = vbuf ? tcmemdup(vbuf, *sp) : NULL; - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Retrieve a record with a decimal key in a fixed-length database object. */ -void *tcfdbget2(TCFDB *fdb, const void *kbuf, int ksiz, int *sp){ - assert(fdb && kbuf && ksiz >= 0 && sp); - return tcfdbget(fdb, tcfdbkeytoid(kbuf, ksiz), sp); +void *tcfdbget2(TCFDB *fdb, const void *kbuf, int ksiz, int *sp) { + assert(fdb && kbuf && ksiz >= 0 && sp); + return tcfdbget(fdb, tcfdbkeytoid(kbuf, ksiz), sp); } - /* Retrieve a string record with a decimal key in a fixed-length database object. */ -char *tcfdbget3(TCFDB *fdb, const char *kstr){ - assert(fdb && kstr); - int vsiz; - return tcfdbget(fdb, tcfdbkeytoid(kstr, strlen(kstr)), &vsiz); +char *tcfdbget3(TCFDB *fdb, const char *kstr) { + assert(fdb && kstr); + int vsiz; + return tcfdbget(fdb, tcfdbkeytoid(kstr, strlen(kstr)), &vsiz); } - /* Retrieve a record in a fixed-length database object and write the value into a buffer. */ -int tcfdbget4(TCFDB *fdb, int64_t id, void *vbuf, int max){ - assert(fdb && vbuf && max >= 0); - if(!FDBLOCKMETHOD(fdb, false)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(id == FDBIDMIN){ - id = fdb->min; - } else if(id == FDBIDMAX){ - id = fdb->max; - } - if(id < 1 || id > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKRECORD(fdb, false, id)){ +int tcfdbget4(TCFDB *fdb, int64_t id, void *vbuf, int max) { + assert(fdb && vbuf && max >= 0); + if (!FDBLOCKMETHOD(fdb, false)) { + return -1; + } + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (id == FDBIDMIN) { + id = fdb->min; + } else if (id == FDBIDMAX) { + id = fdb->max; + } + if (id < 1 || id > fdb->limid) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (!FDBLOCKRECORD(fdb, false, id)) { + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (!FDBLOCKSMEM(fdb, false)) { + FDBUNLOCKRECORD(fdb, id); + FDBUNLOCKMETHOD(fdb); + return -1; + } + int vsiz; + const void *rbuf = tcfdbgetimpl(fdb, id, &vsiz); + if (rbuf) { + if (vsiz > max) vsiz = max; + memcpy(vbuf, rbuf, vsiz); + } else { + vsiz = -1; + } + FDBUNLOCKSMEM(fdb); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - int vsiz; - const void *rbuf = tcfdbgetimpl(fdb, id, &vsiz); - if(rbuf){ - if(vsiz > max) vsiz = max; - memcpy(vbuf, rbuf, vsiz); - } else { - vsiz = -1; - } - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return vsiz; + return vsiz; } - /* Get the size of the value of a record in a fixed-length database object. */ -int tcfdbvsiz(TCFDB *fdb, int64_t id){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, false)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(id == FDBIDMIN){ - id = fdb->min; - } else if(id == FDBIDMAX){ - id = fdb->max; - } - if(id < 1 || id > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKRECORD(fdb, false, id)){ +int tcfdbvsiz(TCFDB *fdb, int64_t id) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, false)) { + return -1; + } + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (id == FDBIDMIN) { + id = fdb->min; + } else if (id == FDBIDMAX) { + id = fdb->max; + } + if (id < 1 || id > fdb->limid) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (!FDBLOCKRECORD(fdb, false, id)) { + FDBUNLOCKMETHOD(fdb); + return -1; + } + if (!FDBLOCKSMEM(fdb, false)) { + FDBUNLOCKRECORD(fdb, id); + FDBUNLOCKMETHOD(fdb); + return -1; + } + + int vsiz; + const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz); + if (!vbuf) vsiz = -1; + + FDBUNLOCKSMEM(fdb); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return false; - } - int vsiz; - const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz); - if(!vbuf) vsiz = -1; - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return vsiz; + return vsiz; } - /* Get the size of the value with a decimal key in a fixed-length database object. */ -int tcfdbvsiz2(TCFDB *fdb, const void *kbuf, int ksiz){ - assert(fdb && kbuf && ksiz >= 0); - return tcfdbvsiz(fdb, tcfdbkeytoid(kbuf, ksiz)); +int tcfdbvsiz2(TCFDB *fdb, const void *kbuf, int ksiz) { + assert(fdb && kbuf && ksiz >= 0); + return tcfdbvsiz(fdb, tcfdbkeytoid(kbuf, ksiz)); } - /* Get the size of the string value with a decimal key in a fixed-length database object. */ -int tcfdbvsiz3(TCFDB *fdb, const char *kstr){ - assert(fdb && kstr); - return tcfdbvsiz(fdb, tcfdbkeytoid(kstr, strlen(kstr))); +int tcfdbvsiz3(TCFDB *fdb, const char *kstr) { + assert(fdb && kstr); + return tcfdbvsiz(fdb, tcfdbkeytoid(kstr, strlen(kstr))); } - /* Initialize the iterator of a fixed-length database object. */ -bool tcfdbiterinit(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbiterinit(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + bool rv = tcfdbiterinitimpl(fdb); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbiterinitimpl(fdb); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Get the next ID number of the iterator of a fixed-length database object. */ -uint64_t tcfdbiternext(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tcfdbiternext(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) { + return 0; + } + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return 0; + } + if (!FDBLOCKSMEM(fdb, false)) { + FDBUNLOCKMETHOD(fdb); + return 0; + } + uint64_t rv = tcfdbiternextimpl(fdb); + FDBUNLOCKSMEM(fdb); FDBUNLOCKMETHOD(fdb); - return false; - } - uint64_t rv = tcfdbiternextimpl(fdb); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Get the next decimay key of the iterator of a fixed-length database object. */ -void *tcfdbiternext2(TCFDB *fdb, int *sp){ - assert(fdb && sp); - uint64_t id = tcfdbiternextimpl(fdb); - if(id < 1) return NULL; - char kbuf[TCNUMBUFSIZ]; - int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long)id); - *sp = ksiz; - return tcmemdup(kbuf, ksiz); +void *tcfdbiternext2(TCFDB *fdb, int *sp) { + assert(fdb && sp); + uint64_t id = tcfdbiternext(fdb); + if (id < 1) return NULL; + char kbuf[TCNUMBUFSIZ]; + int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long) id); + *sp = ksiz; + return tcmemdup(kbuf, ksiz); } - /* Get the next decimay key string of the iterator of a fixed-length database object. */ -char *tcfdbiternext3(TCFDB *fdb){ - assert(fdb); - int ksiz; - return tcfdbiternext2(fdb, &ksiz); +char *tcfdbiternext3(TCFDB *fdb) { + assert(fdb); + int ksiz; + return tcfdbiternext2(fdb, &ksiz); } - /* Get range matching decimal keys in a fixed-length database object. */ -uint64_t *tcfdbrange(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np){ - assert(fdb && np); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - *np = 0; - return tcmalloc(1); - } - if(lower == FDBIDMIN) lower = fdb->min; - if(upper == FDBIDMAX) upper = fdb->max; - if(lower < 1 || lower > fdb->limid || upper < 1 || upper > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t *tcfdbrange(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np) { + assert(fdb && np); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + *np = 0; + return tcmalloc(1); + } + if (lower == FDBIDMIN) lower = fdb->min; + if (upper == FDBIDMAX) upper = fdb->max; + if (lower < 1 || lower > fdb->limid || upper < 1 || upper > fdb->limid) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + *np = 0; + return tcmalloc(1); + } + uint64_t *rv = tcfdbrangeimpl(fdb, lower, upper, max, np); + if (rv == NULL) { + *np = 0; + rv = tcmalloc(1); + } FDBUNLOCKMETHOD(fdb); - *np = 0; - return tcmalloc(1); - } - uint64_t *rv = tcfdbrangeimpl(fdb, lower, upper, max, np); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Get range matching decimal keys in a fixed-length database object. */ -TCLIST *tcfdbrange2(TCFDB *fdb, const void *lbuf, int lsiz, const void *ubuf, int usiz, int max){ - assert(fdb && lbuf && lsiz >= 0 && ubuf && usiz >= 0); - int num; - uint64_t *ids = tcfdbrange(fdb, tcfdbkeytoid(lbuf, lsiz), tcfdbkeytoid(ubuf, usiz), max, &num); - TCLIST *keys = tclistnew2(num); - for(int i = 0; i < num; i++){ - char kbuf[TCNUMBUFSIZ]; - int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long)ids[i]); - TCLISTPUSH(keys, kbuf, ksiz); - } - TCFREE(ids); - return keys; +TCLIST *tcfdbrange2(TCFDB *fdb, const void *lbuf, int lsiz, const void *ubuf, int usiz, int max) { + assert(fdb && lbuf && lsiz >= 0 && ubuf && usiz >= 0); + int num; + uint64_t *ids = tcfdbrange(fdb, tcfdbkeytoid(lbuf, lsiz), tcfdbkeytoid(ubuf, usiz), max, &num); + TCLIST *keys = tclistnew2(num); + for (int i = 0; i < num; i++) { + char kbuf[TCNUMBUFSIZ]; + int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long) ids[i]); + TCLISTPUSH(keys, kbuf, ksiz); + } + TCFREE(ids); + return keys; } - /* Get range matching decimal keys with strings in a fixed-length database object. */ -TCLIST *tcfdbrange3(TCFDB *fdb, const char *lstr, const char *ustr, int max){ - assert(fdb && lstr && ustr); - return tcfdbrange2(fdb, lstr, strlen(lstr), ustr, strlen(ustr), max); +TCLIST *tcfdbrange3(TCFDB *fdb, const char *lstr, const char *ustr, int max) { + assert(fdb && lstr && ustr); + return tcfdbrange2(fdb, lstr, strlen(lstr), ustr, strlen(ustr), max); } - /* Get keys with an interval notation in a fixed-length database object. */ -TCLIST *tcfdbrange4(TCFDB *fdb, const void *ibuf, int isiz, int max){ - assert(fdb && ibuf && isiz >= 0); - char *expr; - TCMEMDUP(expr, ibuf, isiz); - char *pv = expr; - while(*pv > '\0' && *pv <= ' '){ +TCLIST *tcfdbrange4(TCFDB *fdb, const void *ibuf, int isiz, int max) { + assert(fdb && ibuf && isiz >= 0); + char *expr; + TCMEMDUP(expr, ibuf, isiz); + char *pv = expr; + while (*pv > '\0' && *pv <= ' ') { + pv++; + } + bool linc = false; + if (*pv == '[') { + linc = true; + } else if (*pv != '(') { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + TCFREE(expr); + return tclistnew(); + } pv++; - } - bool linc = false; - if(*pv == '['){ - linc = true; - } else if(*pv != '('){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - TCFREE(expr); - return tclistnew(); - } - pv++; - char *sep = strchr(pv, ','); - if(!sep){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - TCFREE(expr); - return tclistnew(); - } - *sep = '\0'; - tcstrtrim(pv); - int64_t lower = tcfdbkeytoid(pv, strlen(pv)); - pv = sep + 1; - bool uinc = false; - if((sep = strchr(pv, ']')) != NULL){ - uinc = true; - *sep = '\0'; - } else if((sep = strchr(pv, ')')) != NULL){ + char *sep = strchr(pv, ','); + if (!sep) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + TCFREE(expr); + return tclistnew(); + } *sep = '\0'; - } else { - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + tcstrtrim(pv); + int64_t lower = tcfdbkeytoid(pv, strlen(pv)); + pv = sep + 1; + bool uinc = false; + if ((sep = strchr(pv, ']')) != NULL) { + uinc = true; + *sep = '\0'; + } else if ((sep = strchr(pv, ')')) != NULL) { + *sep = '\0'; + } else { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + TCFREE(expr); + return tclistnew(); + } + tcstrtrim(pv); + int64_t upper = tcfdbkeytoid(pv, strlen(pv)); + if (lower == FDBIDMIN) { + lower = fdb->min; + } else if (lower == FDBIDPREV) { + lower = fdb->min - 1; + } else if (lower == FDBIDMAX) { + lower = fdb->max; + } else if (lower == FDBIDNEXT) { + lower = fdb->max + 1; + } + if (!linc) lower++; + if (upper == FDBIDMIN) { + upper = fdb->min; + } else if (upper == FDBIDPREV) { + upper = fdb->min - 1; + } else if (upper == FDBIDMAX) { + upper = fdb->max; + } else if (upper == FDBIDNEXT) { + upper = fdb->max + 1; + } + if (!uinc) upper--; TCFREE(expr); - return tclistnew(); - } - tcstrtrim(pv); - int64_t upper = tcfdbkeytoid(pv, strlen(pv)); - if(lower == FDBIDMIN){ - lower = fdb->min; - } else if(lower == FDBIDPREV){ - lower = fdb->min - 1; - } else if(lower == FDBIDMAX){ - lower = fdb->max; - } else if(lower == FDBIDNEXT){ - lower = fdb->max + 1; - } - if(!linc) lower++; - if(upper == FDBIDMIN){ - upper = fdb->min; - } else if(upper == FDBIDPREV){ - upper = fdb->min - 1; - } else if(upper == FDBIDMAX){ - upper = fdb->max; - } else if(upper == FDBIDNEXT){ - upper = fdb->max + 1; - } - if(!uinc) upper--; - TCFREE(expr); - int num; - uint64_t *ids = tcfdbrange(fdb, lower, upper, max, &num); - TCLIST *keys = tclistnew2(num); - for(int i = 0; i < num; i++){ - char kbuf[TCNUMBUFSIZ]; - int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long)ids[i]); - TCLISTPUSH(keys, kbuf, ksiz); - } - TCFREE(ids); - return keys; + int num; + uint64_t *ids = tcfdbrange(fdb, lower, upper, max, &num); + TCLIST *keys = tclistnew2(num); + for (int i = 0; i < num; i++) { + char kbuf[TCNUMBUFSIZ]; + int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long) ids[i]); + TCLISTPUSH(keys, kbuf, ksiz); + } + TCFREE(ids); + return keys; } - /* Get keys with an interval notation string in a fixed-length database object. */ -TCLIST *tcfdbrange5(TCFDB *fdb, const void *istr, int max){ - assert(fdb && istr); - return tcfdbrange4(fdb, istr, strlen(istr), max); +TCLIST *tcfdbrange5(TCFDB *fdb, const void *istr, int max) { + assert(fdb && istr); + return tcfdbrange4(fdb, istr, strlen(istr), max); } - /* Add an integer to a record in a fixed-length database object. */ -int tcfdbaddint(TCFDB *fdb, int64_t id, int num){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, id < 1)) return INT_MIN; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return INT_MIN; - } - 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 INT_MIN; - } - if(!FDBLOCKRECORD(fdb, true, id)){ +int tcfdbaddint(TCFDB *fdb, int64_t id, int num) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, id < 1)) return INT_MIN; + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return INT_MIN; + } + 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 INT_MIN; + } + if (!FDBLOCKRECORD(fdb, true, id)) { + FDBUNLOCKMETHOD(fdb); + return INT_MIN; + } + bool rv = tcfdbputimpl(fdb, id, (char *) &num, sizeof (num), FDBPDADDINT); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return INT_MIN; - } - bool rv = tcfdbputimpl(fdb, id, (char *)&num, sizeof(num), FDBPDADDINT); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv ? num : INT_MIN; + return rv ? num : INT_MIN; } - /* Add a real number to a record in a fixed-length database object. */ -double tcfdbadddouble(TCFDB *fdb, int64_t id, double num){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, id < 1)) return nan(""); - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return nan(""); - } - 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 nan(""); - } - if(!FDBLOCKRECORD(fdb, true, id)){ +double tcfdbadddouble(TCFDB *fdb, int64_t id, double num) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, id < 1)) return nan(""); + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return nan(""); + } + 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 nan(""); + } + if (!FDBLOCKRECORD(fdb, true, id)) { + FDBUNLOCKMETHOD(fdb); + return nan(""); + } + bool rv = tcfdbputimpl(fdb, id, (char *) &num, sizeof (num), FDBPDADDDBL); + FDBUNLOCKRECORD(fdb, id); FDBUNLOCKMETHOD(fdb); - return nan(""); - } - bool rv = tcfdbputimpl(fdb, id, (char *)&num, sizeof(num), FDBPDADDDBL); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv ? num : nan(""); + return rv ? num : nan(""); } - /* Synchronize updated contents of a fixed-length database object with the file and the device. */ -bool tcfdbsync(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbsync(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + bool rv = tcfdbmemsync(fdb, true); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbmemsync(fdb, true); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Optimize the file of a fixed-length database object. */ -bool tcfdboptimize(TCFDB *fdb, int32_t width, int64_t limsiz){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdboptimize(TCFDB *fdb, int32_t width, int64_t limsiz) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + FDBTHREADYIELD(fdb); + bool rv = tcfdboptimizeimpl(fdb, width, limsiz); FDBUNLOCKMETHOD(fdb); - return false; - } - FDBTHREADYIELD(fdb); - bool rv = tcfdboptimizeimpl(fdb, width, limsiz); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Remove all records of a fixed-length database object. */ -bool tcfdbvanish(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbvanish(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->tran) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + FDBTHREADYIELD(fdb); + bool rv = tcfdbvanishimpl(fdb); FDBUNLOCKMETHOD(fdb); - return false; - } - FDBTHREADYIELD(fdb); - bool rv = tcfdbvanishimpl(fdb); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Copy the database file of a fixed-length database object. */ -bool tcfdbcopy(TCFDB *fdb, const char *path){ - assert(fdb && path); - if(!FDBLOCKMETHOD(fdb, false)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKALLRECORDS(fdb, false)){ +bool tcfdbcopy(TCFDB *fdb, const char *path) { + assert(fdb && path); + if (!FDBLOCKMETHOD(fdb, false)) return false; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + if (!FDBLOCKALLRECORDS(fdb, false)) { + FDBUNLOCKMETHOD(fdb); + return false; + } + FDBTHREADYIELD(fdb); + bool rv = tcfdbcopyimpl(fdb, path); + FDBUNLOCKALLRECORDS(fdb); FDBUNLOCKMETHOD(fdb); - return false; - } - FDBTHREADYIELD(fdb); - bool rv = tcfdbcopyimpl(fdb, path); - FDBUNLOCKALLRECORDS(fdb); - FDBUNLOCKMETHOD(fdb); - return rv; + 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(INVALIDHANDLE(fdb->fd) || !(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); - } - if(!tcfdbmemsync(fdb, false)){ - FDBUNLOCKMETHOD(fdb); - return false; - } - if((fdb->omode & FDBOTSYNC) && fsync(fdb->fd)){ - tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); - return false; - } - if(INVALIDHANDLE(fdb->walfd)){ - char *tpath = tcsprintf("%s%c%s", fdb->path, MYEXTCHR, FDBWALSUFFIX); - HANDLE walfd; +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 (INVALIDHANDLE(fdb->fd) || !(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); + } + if (!tcfdbmemsync(fdb, false)) { + FDBUNLOCKMETHOD(fdb); + return false; + } + if ((fdb->omode & FDBOTSYNC) && fsync(fdb->fd)) { + tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); + return false; + } + if (INVALIDHANDLE(fdb->walfd)) { + char *tpath = tcsprintf("%s%c%s", fdb->path, MYEXTCHR, FDBWALSUFFIX); + HANDLE walfd; #ifndef _WIN32 - walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, FDBFILEMODE); + walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, FDBFILEMODE); #else - walfd = CreateFile(tpath, (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + walfd = CreateFile(tpath, (GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); #endif - TCFREE(tpath); - if(INVALIDHANDLE(walfd)){ - tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - fdb->walfd = walfd; - } - tcfdbsetflag(fdb, FDBFOPEN, false); - if(!tcfdbwalinit(fdb)){ + TCFREE(tpath); + if (INVALIDHANDLE(walfd)) { + tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + fdb->walfd = walfd; + } + tcfdbsetflag(fdb, FDBFOPEN, false); + if (!tcfdbwalinit(fdb)) { + tcfdbsetflag(fdb, FDBFOPEN, true); + FDBUNLOCKMETHOD(fdb); + return false; + } tcfdbsetflag(fdb, FDBFOPEN, true); + fdb->tran = true; FDBUNLOCKMETHOD(fdb); - return false; - } - tcfdbsetflag(fdb, FDBFOPEN, true); - fdb->tran = true; - FDBUNLOCKMETHOD(fdb); - return true; + return true; } - /* Commit the transaction of a fixed-length database object. */ -bool tcfdbtrancommit(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || fdb->fatal || !fdb->tran){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbtrancommit(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(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 (FDBLOCKWAL(fdb)) { + if (!err && !tcftruncate(fdb->walfd, 0)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + FDBUNLOCKWAL(fdb); + } else { + err = true; + } + fdb->tran = false; FDBUNLOCKMETHOD(fdb); - return false; - } - bool err = false; - if(!tcfdbmemsync(fdb, fdb->omode & FDBOTSYNC)) err = true; - if(!err && !tcftruncate(fdb->walfd, 0)){ - tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); - err = true; - } - fdb->tran = false; - FDBUNLOCKMETHOD(fdb); - return !err; + return !err; } - /* Abort the transaction of a fixed-length database object. */ -bool tcfdbtranabort(TCFDB *fdb){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER) || !fdb->tran){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbtranabort(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd) || !(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; + fdb->tran = false; FDBUNLOCKMETHOD(fdb); - return false; - } - bool err = false; - if(!tcfdbmemsync(fdb, false)) err = true; - if(!tcfdbwalrestore(fdb, fdb->path)) err = true; - char hbuf[FDBHEADSIZ]; - if(!tcfseek(fdb->fd, 0, TCFSTART)){ - 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; + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +const char *tcfdbpath(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, false)) return NULL; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return NULL; + } + const char *rv = fdb->path; FDBUNLOCKMETHOD(fdb); - return NULL; - } - const char *rv = fdb->path; - FDBUNLOCKMETHOD(fdb); - return rv; + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tcfdbrnum(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, false)) return 0; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return 0; + } + uint64_t rv = fdb->rnum; FDBUNLOCKMETHOD(fdb); - return 0; - } - uint64_t rv = fdb->rnum; - FDBUNLOCKMETHOD(fdb); - return rv; + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tcfdbfsiz(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, false)) return 0; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return 0; + } + uint64_t rv = fdb->fsiz; FDBUNLOCKMETHOD(fdb); - return 0; - } - uint64_t rv = fdb->fsiz; - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } @@ -1070,17 +1079,16 @@ uint64_t tcfdbfsiz(TCFDB *fdb){ * 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) { - if (fdb->eckey) { - pthread_setspecific(*(pthread_key_t *)fdb->eckey, (void *)(intptr_t)ecode); - } - fdb->ecode = ecode; - } - switch (ecode) { //Fatal errors +void tcfdbsetecode(TCFDB *fdb, int ecode, const char *filename, int line, const char *func) { + assert(fdb && filename && line >= 1 && func); + if (!fdb->fatal) { + if (fdb->eckey) { + pthread_setspecific(*(pthread_key_t *) fdb->eckey, (void *) (intptr_t) ecode); + } + fdb->ecode = ecode; + } + switch (ecode) { //Fatal errors case TCETHREAD: case TCENOFILE: case TCENOPERM: @@ -1108,359 +1116,392 @@ void tcfdbsetecode(TCFDB *fdb, int ecode, const char *filename, int line, const case TCESUCCESS: case TCENOREC: case TCEKEEP: - return; - break; + return; + break; default: - break; - } + break; + } #ifdef _WIN32 - DWORD winerrno = GetLastError(); + DWORD winerrno = GetLastError(); #endif - int stderrno = errno; - if(!INVALIDHANDLE(fdb->dbgfd) || fdb->fatal) { - HANDLE dbgfd = INVALIDHANDLE(fdb->dbgfd) ? GET_STDERR_HANDLE() : (fdb->dbgfd); - char obuf[FDBIOBUFSIZ]; + int stderrno = errno; + if (!INVALIDHANDLE(fdb->dbgfd) || fdb->fatal) { + HANDLE dbgfd = INVALIDHANDLE(fdb->dbgfd) ? GET_STDERR_HANDLE() : (fdb->dbgfd); + char obuf[FDBIOBUFSIZ]; #ifdef _WIN32 - LPTSTR errorText = NULL; - if (winerrno > 0) { - DWORD ret = FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, winerrno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &errorText, 0, NULL); - if (!ret) { - if (errorText) LocalFree(errorText); - errorText = NULL; + LPTSTR errorText = NULL; + if (winerrno > 0) { + DWORD ret = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, winerrno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & errorText, 0, NULL); + if (!ret) { + if (errorText) LocalFree(errorText); + errorText = NULL; + } } - } - int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s:%d:%s\n", - filename, line, - func, (fdb->path ? fdb->path : "-"), - ecode, tcfdberrmsg(ecode), - winerrno, (errorText ? errorText : "-"), - stderrno, (stderrno > 0 ? strerror(stderrno) : "-")); - if (errorText) LocalFree(errorText); + int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s:%d:%s\n", + filename, line, + func, (fdb->path ? fdb->path : "-"), + ecode, tcfdberrmsg(ecode), + winerrno, (errorText ? errorText : "-"), + stderrno, (stderrno > 0 ? strerror(stderrno) : "-")); + if (errorText) LocalFree(errorText); #else - int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s\n", - filename, line, - func, (fdb->path ? fdb->path : "-"), - ecode, tcfdberrmsg(ecode), - stderrno, strerror(stderrno)); + int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s\n", + filename, line, + func, (fdb->path ? fdb->path : "-"), + ecode, tcfdberrmsg(ecode), + stderrno, strerror(stderrno)); #endif - tcwrite(dbgfd, obuf, osiz); - } + tcwrite(dbgfd, obuf, osiz); + } } - /* Set the file descriptor for debugging output. */ -void tcfdbsetdbgfd(TCFDB *fdb, HANDLE fd){ - assert(fdb); - fdb->dbgfd = fd; +void tcfdbsetdbgfd(TCFDB *fdb, HANDLE fd) { + assert(fdb); + fdb->dbgfd = fd; } - /* Get the file descriptor for debugging output. */ -HANDLE tcfdbdbgfd(TCFDB *fdb){ - assert(fdb); - return fdb->dbgfd; +HANDLE 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; +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(INVALIDHANDLE(fdb->fd) || !(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){ -#ifdef _WIN32 - if(!FlushViewOfFile(fdb->map, fdb->limsiz)){ - tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; +bool tcfdbmemsync(TCFDB *fdb, bool phys) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd) || !(fdb->omode & FDBOWRITER)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; } -#elif !defined __GNU__ - if(msync(fdb->map, fdb->limsiz, MS_SYNC)){ - tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; + if (!FDBLOCKSMEM(fdb, false)) { + return false; } + bool err = false; + char hbuf[FDBHEADSIZ]; + tcfdbdumpmeta(fdb, hbuf); + memcpy((void *) fdb->map, hbuf, FDBOPAQUEOFF); + if (phys) { +#ifdef _WIN32 + if (!FlushViewOfFile((PCVOID) fdb->map, 0)) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + } +#elif !defined __GNU__ + if (msync(fdb->map, fdb->limsiz, MS_SYNC)) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + } #endif - if(fsync(fdb->fd)){ - tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); - err = true; + if (fsync(fdb->fd)) { + tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); + err = true; + } } - } - return !err; + FDBUNLOCKSMEM(fdb); + return !err; } - /* Get the minimum ID number of records of a fixed-length database object. */ -uint64_t tcfdbmin(TCFDB *fdb){ - assert(fdb); - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->min; +uint64_t tcfdbmin(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->max; +uint64_t tcfdbmax(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->width; +uint32_t tcfdbwidth(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->limsiz; +uint64_t tcfdblimsiz(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->limid; +uint64_t tcfdblimid(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->inode; +uint64_t tcfdbinode(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->mtime; +time_t tcfdbmtime(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->omode; +int tcfdbomode(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->type; +uint8_t tcfdbtype(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return fdb->flags; +uint8_t tcfdbflags(TCFDB *fdb) { + assert(fdb); + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return fdb->flags; } +bool tcfdbcopyopaque(TCFDB *dst, TCFDB *src, int off, int rsz) { + assert(dst && src); + if (rsz == -1) { + rsz = FDBOPAQUESZ; + } + char odata[FDBOPAQUESZ]; + rsz = tcfdbreadopaque(src, odata, off, rsz); + if (rsz == -1) { + tcfdbsetecode(dst, tcfdbecode(src), __FILE__, __LINE__, __func__); + return false; + } + return (tcfdbwriteopaque(dst, odata, off, rsz) == rsz); +} -/* Get the pointer to the opaque field of a fixed-length database object. */ -char *tcfdbopaque(TCFDB *fdb){ - assert(fdb); - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return NULL; - } - return fdb->map + FDBOPAQUEOFF; +int tcfdbreadopaque(TCFDB *fdb, void *dst, int off, int bsiz) { + assert(fdb && dst); + if (bsiz == -1) { + bsiz = FDBOPAQUESZ; + } + if (off > FDBOPAQUESZ) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return -1; + } + bsiz = MIN(bsiz, FDBOPAQUESZ - off); + if (bsiz <= 0) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return -1; + } + if (!FDBLOCKSMEM(fdb, false)) return -1; + assert(fdb->map); + memcpy((void *) dst, (void *) (fdb->map + FDBOPAQUEOFF + off), bsiz); + FDBUNLOCKSMEM(fdb); + return bsiz; } +int tcfdbwriteopaque(TCFDB *fdb, const void *src, int off, int nb) { + assert(fdb && src); + if (nb == -1) { + nb = FDBOPAQUESZ; + } + if (off > FDBOPAQUESZ) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return -1; + } + nb = MIN(nb, FDBOPAQUESZ - off); + if (nb <= 0) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return -1; + } + if (!FDBLOCKSMEM(fdb, true)) return -1; + memcpy((void *) (fdb->map + FDBOPAQUEOFF + off), src, nb); + FDBUNLOCKSMEM(fdb); + return nb; +} /* 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(INVALIDHANDLE(fdb->fd) || !(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; - tcgeneric_t stack[(FDBDEFWIDTH+TCNUMBUFSIZ)/sizeof(tcgeneric_t)+1]; - char *rbuf; - if(vbuf){ - if(vsiz <= sizeof(stack) - sizeof(procptr)){ - rbuf = (char *)stack; +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 (INVALIDHANDLE(fdb->fd) || !(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; + tcgeneric_t stack[(FDBDEFWIDTH + TCNUMBUFSIZ) / sizeof (tcgeneric_t) + 1]; + char *rbuf; + if (vbuf) { + if (vsiz <= sizeof (stack) - sizeof (procptr)) { + rbuf = (char *) 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 { - 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 = (char *)stack; - memcpy(rbuf, &procptr, sizeof(procptr)); - vbuf = rbuf + sizeof(procptr); - vsiz = -1; - } - bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDPROC); - if(rbuf != (char *)stack) TCFREE(rbuf); - FDBUNLOCKRECORD(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + rbuf = (char *) stack; + memcpy(rbuf, &procptr, sizeof (procptr)); + vbuf = rbuf + sizeof (procptr); + vsiz = -1; + } + bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDPROC); + if (rbuf != (char *) stack) TCFREE(rbuf); + FDBUNLOCKRECORD(fdb, id); + FDBUNLOCKMETHOD(fdb); + return rv; } - /* Move the iterator to the record corresponding a key of a fixed-length database object. */ -bool tcfdbiterinit2(TCFDB *fdb, int64_t id){ - assert(fdb); - if(!FDBLOCKMETHOD(fdb, true)) return false; - if(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(id == FDBIDMIN){ - id = fdb->min; - } else if(id == FDBIDMAX){ - id = fdb->max; - } - if(id < 1 || id > fdb->limid){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tcfdbiterinit2(TCFDB *fdb, int64_t id) { + assert(fdb); + if (!FDBLOCKMETHOD(fdb, true)) return false; + if (INVALIDHANDLE(fdb->fd)) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + if (id == FDBIDMIN) { + id = fdb->min; + } else if (id == FDBIDMAX) { + id = fdb->max; + } + if (id < 1 || id > fdb->limid) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + FDBUNLOCKMETHOD(fdb); + return false; + } + if (!FDBLOCKSMEM(fdb, false)) { + FDBUNLOCKMETHOD(fdb); + return false; + } + bool rv = tcfdbiterjumpimpl(fdb, id); + FDBUNLOCKSMEM(fdb); FDBUNLOCKMETHOD(fdb); - return false; - } - bool rv = tcfdbiterjumpimpl(fdb, id); - FDBUNLOCKMETHOD(fdb); - return rv; + return rv; } - /* Move the iterator to the decimal record of a fixed-length database object. */ -bool tcfdbiterinit3(TCFDB *fdb, const void *kbuf, int ksiz){ - assert(fdb && kbuf && ksiz >= 0); - return tcfdbiterinit2(fdb, tcfdbkeytoid(kbuf, ksiz)); +bool tcfdbiterinit3(TCFDB *fdb, const void *kbuf, int ksiz) { + assert(fdb && kbuf && ksiz >= 0); + return tcfdbiterinit2(fdb, tcfdbkeytoid(kbuf, ksiz)); } - /* Move the iterator to the decimal string record of a fixed-length database object. */ -bool tcfdbiterinit4(TCFDB *fdb, const char *kstr){ - assert(fdb && kstr); - return tcfdbiterinit2(fdb, tcfdbkeytoid(kstr, strlen(kstr))); +bool tcfdbiterinit4(TCFDB *fdb, const char *kstr) { + assert(fdb && kstr); + return tcfdbiterinit2(fdb, tcfdbkeytoid(kstr, strlen(kstr))); } - /* 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(INVALIDHANDLE(fdb->fd)){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - FDBUNLOCKMETHOD(fdb); - return false; - } - if(!FDBLOCKALLRECORDS(fdb, false)){ +bool tcfdbforeach(TCFDB *fdb, TCITER iter, void *op) { + assert(fdb && iter); + if (!FDBLOCKMETHOD(fdb, false)) return false; + if (INVALIDHANDLE(fdb->fd)) { + 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 false; - } - FDBTHREADYIELD(fdb); - bool rv = tcfdbforeachimpl(fdb, iter, op); - FDBUNLOCKALLRECORDS(fdb); - FDBUNLOCKMETHOD(fdb); - return rv; + 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; +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; } @@ -1469,595 +1510,629 @@ int64_t tcfdbkeytoid(const char *kbuf, int ksiz){ * private features *************************************************************************************************/ - /* Serialize meta data into a buffer. `fdb' specifies the fixed-length database object. `hbuf' specifies the buffer. */ -static void tcfdbdumpmeta(TCFDB *fdb, char *hbuf){ - memset(hbuf, 0, FDBHEADSIZ); - sprintf(hbuf, "%s\n%s:%d\n", FDBMAGICDATA, _TC_FORMATVER, _TC_LIBVER); - memcpy(hbuf + FDBTYPEOFF, &(fdb->type), sizeof(fdb->type)); - memcpy(hbuf + FDBFLAGSOFF, &(fdb->flags), sizeof(fdb->flags)); - uint64_t llnum; - llnum = fdb->rnum; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBRNUMOFF, &llnum, sizeof(llnum)); - llnum = fdb->fsiz; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBFSIZOFF, &llnum, sizeof(llnum)); - llnum = fdb->width; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBWIDTHOFF, &llnum, sizeof(llnum)); - llnum = fdb->limsiz; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBLIMSIZOFF, &llnum, sizeof(llnum)); - llnum = fdb->min; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBMINOFF, &llnum, sizeof(llnum)); - llnum = fdb->max; - llnum = TCHTOILL(llnum); - memcpy(hbuf + FDBMAXOFF, &llnum, sizeof(llnum)); +static void tcfdbdumpmeta(TCFDB *fdb, char *hbuf) { + memset(hbuf, 0, FDBHEADSIZ); + sprintf(hbuf, "%s\n%s:%d\n", FDBMAGICDATA, _TC_FORMATVER, _TC_LIBVER); + memcpy(hbuf + FDBTYPEOFF, &(fdb->type), sizeof (fdb->type)); + memcpy(hbuf + FDBFLAGSOFF, &(fdb->flags), sizeof (fdb->flags)); + uint64_t llnum; + llnum = fdb->rnum; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBRNUMOFF, &llnum, sizeof (llnum)); + llnum = fdb->fsiz; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBFSIZOFF, &llnum, sizeof (llnum)); + llnum = fdb->width; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBWIDTHOFF, &llnum, sizeof (llnum)); + llnum = fdb->limsiz; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBLIMSIZOFF, &llnum, sizeof (llnum)); + llnum = fdb->min; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBMINOFF, &llnum, sizeof (llnum)); + llnum = fdb->max; + llnum = TCHTOILL(llnum); + memcpy(hbuf + FDBMAXOFF, &llnum, sizeof (llnum)); } - /* Deserialize meta data from a buffer. `fdb' specifies the fixed-length database object. `hbuf' specifies the buffer. */ -static void tcfdbloadmeta(TCFDB *fdb, const char *hbuf){ - memcpy(&(fdb->type), hbuf + FDBTYPEOFF, sizeof(fdb->type)); - memcpy(&(fdb->flags), hbuf + FDBFLAGSOFF, sizeof(fdb->flags)); - uint64_t llnum; - memcpy(&llnum, hbuf + FDBRNUMOFF, sizeof(llnum)); - fdb->rnum = TCITOHLL(llnum); - memcpy(&llnum, hbuf + FDBFSIZOFF, sizeof(llnum)); - fdb->fsiz = TCITOHLL(llnum); - memcpy(&llnum, hbuf + FDBWIDTHOFF, sizeof(llnum)); - fdb->width = TCITOHLL(llnum); - memcpy(&llnum, hbuf + FDBLIMSIZOFF, sizeof(llnum)); - fdb->limsiz = TCITOHLL(llnum); - memcpy(&llnum, hbuf + FDBMINOFF, sizeof(llnum)); - fdb->min = TCITOHLL(llnum); - memcpy(&llnum, hbuf + FDBMAXOFF, sizeof(llnum)); - fdb->max = TCITOHLL(llnum); +static void tcfdbloadmeta(TCFDB *fdb, const char *hbuf) { + memcpy(&(fdb->type), hbuf + FDBTYPEOFF, sizeof (fdb->type)); + memcpy(&(fdb->flags), hbuf + FDBFLAGSOFF, sizeof (fdb->flags)); + uint64_t llnum; + memcpy(&llnum, hbuf + FDBRNUMOFF, sizeof (llnum)); + fdb->rnum = TCITOHLL(llnum); + memcpy(&llnum, hbuf + FDBFSIZOFF, sizeof (llnum)); + fdb->fsiz = TCITOHLL(llnum); + memcpy(&llnum, hbuf + FDBWIDTHOFF, sizeof (llnum)); + fdb->width = TCITOHLL(llnum); + memcpy(&llnum, hbuf + FDBLIMSIZOFF, sizeof (llnum)); + fdb->limsiz = TCITOHLL(llnum); + memcpy(&llnum, hbuf + FDBMINOFF, sizeof (llnum)); + fdb->min = TCITOHLL(llnum); + memcpy(&llnum, hbuf + FDBMAXOFF, sizeof (llnum)); + fdb->max = TCITOHLL(llnum); } - /* Clear all members. `fdb' specifies the fixed-length database object. */ -static void tcfdbclear(TCFDB *fdb){ - assert(fdb); - fdb->mmtx = NULL; - fdb->amtx = NULL; - fdb->rmtxs = NULL; - fdb->tmtx = NULL; - fdb->wmtx = NULL; - fdb->eckey = NULL; - fdb->rpath = NULL; - fdb->type = TCDBTFIXED; - fdb->flags = 0; - fdb->width = FDBDEFWIDTH; - fdb->limsiz = FDBDEFLIMSIZ; - fdb->wsiz = 0; - fdb->rsiz = 0; - fdb->limid = 0; - fdb->path = NULL; - fdb->fd = INVALID_HANDLE_VALUE; - fdb->omode = 0; - fdb->rnum = 0; - fdb->fsiz = 0; - fdb->min = 0; - fdb->max = 0; - fdb->iter = 0; - fdb->map = NULL; - fdb->array = NULL; - fdb->ecode = TCESUCCESS; - fdb->fatal = false; - fdb->inode = 0; - fdb->mtime = 0; - fdb->tran = false; - fdb->walfd = INVALID_HANDLE_VALUE; - fdb->walend = 0; - fdb->dbgfd = INVALID_HANDLE_VALUE; - fdb->cnt_writerec = -1; - fdb->cnt_readrec = -1; - fdb->cnt_truncfile = -1; - TCDODEBUG(fdb->cnt_writerec = 0); - TCDODEBUG(fdb->cnt_readrec = 0); - TCDODEBUG(fdb->cnt_truncfile = 0); +static void tcfdbclear(TCFDB *fdb) { + assert(fdb); + fdb->mmtx = NULL; + fdb->amtx = NULL; + fdb->rmtxs = NULL; + fdb->tmtx = NULL; + fdb->wmtx = NULL; + fdb->smtx = NULL; + fdb->eckey = NULL; + fdb->rpath = NULL; + fdb->type = TCDBTFIXED; + fdb->flags = 0; + fdb->width = FDBDEFWIDTH; + fdb->limsiz = FDBDEFLIMSIZ; + fdb->wsiz = 0; + fdb->rsiz = 0; + fdb->limid = 0; + fdb->path = NULL; + fdb->fd = INVALID_HANDLE_VALUE; + fdb->omode = 0; + fdb->rnum = 0; + fdb->fsiz = 0; + fdb->min = 0; + fdb->max = 0; + fdb->iter = 0; + fdb->map = NULL; + fdb->w32hmap = NULL; + fdb->ecode = TCESUCCESS; + fdb->fatal = false; + fdb->inode = 0; + fdb->mtime = 0; + fdb->tran = false; + fdb->walfd = INVALID_HANDLE_VALUE; + fdb->walend = 0; + fdb->dbgfd = INVALID_HANDLE_VALUE; + fdb->cnt_writerec = -1; + fdb->cnt_readrec = -1; + fdb->cnt_truncfile = -1; + TCDODEBUG(fdb->cnt_writerec = 0); + TCDODEBUG(fdb->cnt_readrec = 0); + TCDODEBUG(fdb->cnt_truncfile = 0); } - /* Set the open flag. `fdb' specifies the fixed-length database object. `flag' specifies the flag value. `sign' specifies the sign. */ -static void tcfdbsetflag(TCFDB *fdb, int flag, bool sign){ - assert(fdb); - char *fp = (char *)fdb->map + FDBFLAGSOFF; - if(sign){ - *fp |= (uint8_t)flag; - } else { - *fp &= ~(uint8_t)flag; - } - fdb->flags = *fp; +static void tcfdbsetflag(TCFDB *fdb, int flag, bool sign) { + assert(fdb); + if (!FDBLOCKSMEM(fdb, true)) return; + char *fp = (char *) fdb->map + FDBFLAGSOFF; + if (sign) { + *fp |= (uint8_t) flag; + } else { + *fp &= ~(uint8_t) flag; + } + fdb->flags = *fp; + FDBUNLOCKSMEM(fdb); } - /* Initialize the write ahead logging file. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbwalinit(TCFDB *fdb){ - assert(fdb); - if(!tcfseek(fdb->walfd, 0, TCFSTART)){ - tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); - return false; - } - if(!tcftruncate(fdb->walfd, 0)){ - tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); - return false; - } - uint64_t llnum = fdb->fsiz; - llnum = TCHTOILL(llnum); - if(!tcwrite(fdb->walfd, &llnum, sizeof(llnum))){ - tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); - return false; - } - fdb->walend = fdb->fsiz; - if(!tcfdbwalwrite(fdb, 0, FDBHEADSIZ)) return false; - return true; +static bool tcfdbwalinit(TCFDB *fdb) { + assert(fdb); + if (!FDBLOCKWAL(fdb)) return false; + if (!tcfseek(fdb->walfd, 0, TCFSTART)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + FDBUNLOCKWAL(fdb); + return false; + } + if (!tcftruncate(fdb->walfd, 0)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + FDBUNLOCKWAL(fdb); + return false; + } + uint64_t llnum = fdb->fsiz; + llnum = TCHTOILL(llnum); + if (!tcwrite(fdb->walfd, &llnum, sizeof (llnum))) { + tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); + FDBUNLOCKWAL(fdb); + return false; + } + FDBUNLOCKWAL(fdb); + fdb->walend = fdb->fsiz; + if (!tcfdbwalwrite(fdb, 0, FDBHEADSIZ)) { + return false; + } + return true; } - /* Write an event into the write ahead logging file. `fdb' specifies the fixed-length database object. `off' specifies the offset of the region to be updated. `size' specifies the size of the region. If successful, the return value is true, else, it is false. */ -static bool tcfdbwalwrite(TCFDB *fdb, uint64_t off, int64_t size){ - assert(fdb && off >= 0 && size >= 0); - if(off + size > fdb->walend) size = fdb->walend - off; - if(size < 1) return true; - char stack[FDBIOBUFSIZ]; - char *buf; - if(size + sizeof(off) + sizeof(size) <= FDBIOBUFSIZ){ - buf = stack; - } else { - TCMALLOC(buf, size + sizeof(off) + sizeof(size)); - } - char *wp = buf; - uint64_t llnum = TCHTOILL(off); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - uint32_t lnum = TCHTOIL(size); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - memcpy(wp, fdb->map + off, size); - wp += size; - if(!FDBLOCKWAL(fdb)) return false; - if(!tcwrite(fdb->walfd, buf, wp - buf)){ - tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); - if(buf != stack) TCFREE(buf); - FDBUNLOCKWAL(fdb); - return false; - } - if(buf != stack) TCFREE(buf); - if((fdb->omode & FDBOTSYNC) && fsync(fdb->walfd)){ - tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); +static bool tcfdbwalwrite(TCFDB *fdb, uint64_t off, int64_t size) { + assert(fdb && off >= 0 && size >= 0); + if (off + size > fdb->walend) size = fdb->walend - off; + if (size < 1) return true; + char stack[FDBIOBUFSIZ]; + char *buf; + if (size + sizeof (off) + sizeof (size) <= FDBIOBUFSIZ) { + buf = stack; + } else { + TCMALLOC(buf, size + sizeof (off) + sizeof (size)); + } + char *wp = buf; + uint64_t llnum = TCHTOILL(off); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + uint32_t lnum = TCHTOIL(size); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + memcpy(wp, (void *) (fdb->map + off), size); + wp += size; + if (!FDBLOCKWAL(fdb)) return false; + if (!tcwrite(fdb->walfd, buf, wp - buf)) { + tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); + if (buf != stack) TCFREE(buf); + FDBUNLOCKWAL(fdb); + return false; + } + if (buf != stack) TCFREE(buf); + if ((fdb->omode & FDBOTSYNC) && fsync(fdb->walfd)) { + tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); + FDBUNLOCKWAL(fdb); + return false; + } FDBUNLOCKWAL(fdb); - return false; - } - FDBUNLOCKWAL(fdb); - return true; + return true; } - /* Restore the database from the write ahead logging file. `fdb' specifies the fixed-length database object. `path' specifies the path of the database file. If successful, the return value is true, else, it is false. */ -static int tcfdbwalrestore(TCFDB *fdb, const char *path){ - assert(fdb && path); - char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX); - HANDLE walfd; -#ifndef _WIN32 - walfd = open(tpath, O_RDONLY, FDBFILEMODE); -#else - walfd = CreateFile(tpath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -#endif - TCFREE(tpath); - if(INVALIDHANDLE(walfd)) return false; - bool err = false; - uint64_t walsiz = 0; - struct stat sbuf; - if(!fstat(walfd, &sbuf)){ - walsiz = sbuf.st_size; - } else { - tcfdbsetecode(fdb, TCESTAT, __FILE__, __LINE__, __func__); - err = true; - } - if(walsiz >= sizeof(walsiz) + FDBHEADSIZ){ - HANDLE dbfd = fdb->fd; - HANDLE tfd = INVALID_HANDLE_VALUE; - if(!(fdb->omode & FDBOWRITER)){ +static int tcfdbwalrestore(TCFDB *fdb, const char *path) { + assert(fdb && path); + bool err = false; + char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX); + HANDLE walfd; + if (!FDBLOCKWAL(fdb)) { + return false; + } #ifndef _WIN32 - tfd = open(path, O_WRONLY, FDBFILEMODE); + walfd = open(tpath, O_RDONLY, FDBFILEMODE); #else - tfd = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + walfd = CreateFile(tpath, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); #endif - if(!INVALIDHANDLE(tfd)){ - dbfd = tfd; - } else { - tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + TCFREE(tpath); + if (INVALIDHANDLE(walfd)) { + FDBUNLOCKWAL(fdb); err = true; - } + goto finish; + } + uint64_t walsiz = 0; + struct stat sbuf; + if (!fstat(walfd, &sbuf)) { + walsiz = sbuf.st_size; + } + if (!(fdb->omode & FDBOWRITER) || walsiz < sizeof (walsiz) + FDBHEADSIZ) { + FDBUNLOCKWAL(fdb); + err = true; + goto finish; } uint64_t fsiz = 0; - if(tcread(walfd, &fsiz, sizeof(fsiz))){ - fsiz = TCITOHLL(fsiz); + if (tcread(walfd, &fsiz, sizeof (fsiz))) { + fsiz = TCITOHLL(fsiz); } else { - tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); - err = true; + FDBUNLOCKWAL(fdb); + tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); + err = true; + goto finish; } TCLIST *list = tclistnew(); - uint64_t waloff = sizeof(fsiz); + uint64_t waloff = sizeof (fsiz); char stack[FDBIOBUFSIZ]; - while(waloff < walsiz){ - uint64_t off; - uint32_t size; - if(!tcread(walfd, stack, sizeof(off) + sizeof(size))){ - tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); - err = true; - break; - } - memcpy(&off, stack, sizeof(off)); - off = TCITOHLL(off); - memcpy(&size, stack + sizeof(off), sizeof(size)); - size = TCITOHL(size); - char *buf; - if(sizeof(off) + size <= FDBIOBUFSIZ){ - buf = stack; - } else { - TCMALLOC(buf, sizeof(off) + size); - } - *(uint64_t *)buf = off; - if(!tcread(walfd, buf + sizeof(off), size)){ - tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); - err = true; - if(buf != stack) TCFREE(buf); - break; - } - TCLISTPUSH(list, buf, sizeof(off) + size); - if(buf != stack) TCFREE(buf); - waloff += sizeof(off) + sizeof(size) + size; - } - for(int i = TCLISTNUM(list) - 1; i >= 0; i--){ - const char *rec; - int size; - TCLISTVAL(rec, list, i, size); - uint64_t off = *(uint64_t *)rec; - rec += sizeof(off); - size -= sizeof(off); - if(!tcfseek(dbfd, off, TCFSTART)){ - tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + while (waloff < walsiz) { + uint64_t off; + uint32_t size; + if (!tcread(walfd, stack, sizeof (off) + sizeof (size))) { + tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); + err = true; + break; + } + memcpy(&off, stack, sizeof (off)); + off = TCITOHLL(off); + memcpy(&size, stack + sizeof (off), sizeof (size)); + size = TCITOHL(size); + char *buf; + if (sizeof (off) + size <= FDBIOBUFSIZ) { + buf = stack; + } else { + TCMALLOC(buf, sizeof (off) + size); + } + *(uint64_t *) buf = off; + if (!tcread(walfd, buf + sizeof (off), size)) { + tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); + err = true; + if (buf != stack) TCFREE(buf); + break; + } + TCLISTPUSH(list, buf, sizeof (off) + size); + if (buf != stack) TCFREE(buf); + waloff += sizeof (off) + sizeof (size) + size; + } + if (!CLOSEFH(walfd)) { + tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); err = true; - break; - } - if(!tcwrite(dbfd, rec, size)){ - tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); + } else { + walfd = INVALID_HANDLE_VALUE; + } + FDBUNLOCKWAL(fdb); + + if (FDBLOCKSMEM(fdb, true)) { + for (int i = TCLISTNUM(list) - 1; i >= 0; i--) { + const char *rec; + int size; + TCLISTVAL(rec, list, i, size); + uint64_t off = *(uint64_t *) rec; + rec += sizeof (off); + size -= sizeof (off); + if (!tcfseek(fdb->fd, off, TCFSTART)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + err = true; + break; + } + if (!tcwrite(fdb->fd, rec, size)) { + tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); + err = true; + break; + } + } + if (!tcfdbftruncate2(fdb, fsiz, FDBWRITENOLOCK)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + char hbuf[FDBHEADSIZ]; + if (!tcfseek(fdb->fd, 0, TCFSTART)) { + 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); + } + FDBUNLOCKSMEM(fdb); + } else { err = true; - break; - } } tclistdel(list); - if(!tcftruncate(dbfd, fsiz)){ - tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); - err = true; - } - if((fdb->omode & FDBOTSYNC) && fsync(dbfd)){ - tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); - err = true; + + if (!tcfdbmemsync(fdb, (fdb->omode & FDBOTSYNC))) { + tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__); + err = true; } - if(!INVALIDHANDLE(tfd) && !CLOSEFH(tfd)){ - tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; +finish: + if (!INVALIDHANDLE(walfd) && !CLOSEFH(walfd)) { + err = true; } - } else { - err = true; - } - if(!CLOSEFH(walfd)){ - tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; - } - return !err; + return !err; } - /* Remove the write ahead logging file. `fdb' specifies the fixed-length database object. `path' specifies the path of the database file. If successful, the return value is true, else, it is false. */ -static bool tcfdbwalremove(TCFDB *fdb, const char *path){ - assert(fdb && path); - char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX); - bool err = false; - if(unlink(tpath) && errno != ENOENT){ - tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(tpath); - return !err; +static bool tcfdbwalremove(TCFDB *fdb, const char *path) { + assert(fdb && path); + if (!FDBLOCKWAL(fdb)) return false; + char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX); + bool err = false; + if (!tcunlinkfile(tpath) && errno != ENOENT) { + tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + FDBUNLOCKWAL(fdb); + TCFREE(tpath); + return !err; } - /* Open a database file and connect a fixed-length database object. `fdb' specifies the fixed-length database object. `path' specifies the path of the database file. `omode' specifies the connection mode. If successful, the return value is true, else, it is false. */ -static bool tcfdbopenimpl(TCFDB *fdb, const char *path, int omode){ - assert(fdb && path); - HANDLE fd; +static bool tcfdbopenimpl(TCFDB *fdb, const char *path, int omode) { + assert(fdb && path); + HANDLE fd; #ifndef _WIN32 - int mode = O_RDONLY; - if(omode & FDBOWRITER){ - mode = O_RDWR; - if(omode & FDBOCREAT) mode |= O_CREAT; - } - fd = open(path, mode, FDBFILEMODE); + int mode = O_RDONLY; + if (omode & FDBOWRITER) { + mode = O_RDWR; + if (omode & FDBOCREAT) mode |= O_CREAT; + } + fd = open(path, mode, FDBFILEMODE); #else - DWORD mode, cmode; - mode = GENERIC_READ; - cmode = OPEN_EXISTING; - if(omode & FDBOWRITER) { - mode |= GENERIC_WRITE; - if(omode & (FDBOTRUNC|FDBOCREAT)) - cmode = CREATE_ALWAYS; - else if(omode & FDBOTRUNC) - cmode = TRUNCATE_EXISTING; - else if(omode & FDBOCREAT) - cmode = CREATE_NEW; - } - fd = CreateFile(path, mode, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, cmode, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD mode, cmode; + mode = GENERIC_READ; + cmode = OPEN_EXISTING; + if (omode & FDBOWRITER) { + mode |= GENERIC_WRITE; + if (omode & (FDBOTRUNC | FDBOCREAT)) { + cmode = CREATE_ALWAYS; + } else if (omode & FDBOTRUNC) { + cmode = TRUNCATE_EXISTING; + } else if (omode & FDBOCREAT) { + cmode = CREATE_NEW; + } + } + fd = CreateFile(path, mode, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, cmode, FILE_ATTRIBUTE_NORMAL, NULL); #endif - if(INVALIDHANDLE(fd)){ - tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); - return false; - } - if(!(omode & FDBONOLCK)){ - if(!tclock(fd, omode & FDBOWRITER, omode & FDBOLCKNB)){ - tcfdbsetecode(fdb, TCELOCK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - } - if((omode & FDBOWRITER) && (omode & FDBOTRUNC)){ - if(!tcftruncate(fd, 0)){ - tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tcfdbwalremove(fdb, path)){ - CLOSEFH(fd); - return false; - } - } - struct stat sbuf; - if(fstat(fd, &sbuf) || !S_ISREG(sbuf.st_mode)){ - tcfdbsetecode(fdb, TCESTAT, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - char hbuf[FDBHEADSIZ]; - if((omode & FDBOWRITER) && sbuf.st_size < 1){ - fdb->flags = 0; - fdb->rnum = 0; - fdb->fsiz = FDBHEADSIZ; - fdb->min = 0; - fdb->max = 0; - tcfdbdumpmeta(fdb, hbuf); - if(!tcwrite(fd, hbuf, FDBHEADSIZ)){ - tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - sbuf.st_size = fdb->fsiz; - } - if(!tcfseek(fd, 0, TCFSTART)){ - tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tcread(fd, hbuf, FDBHEADSIZ)){ - tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - int type = fdb->type; - tcfdbloadmeta(fdb, hbuf); - if((fdb->flags & FDBFOPEN) && tcfdbwalrestore(fdb, path)){ - if(!tcfseek(fd, 0, TCFSTART)){ - tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tcread(fd, hbuf, FDBHEADSIZ)){ - tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; + if (INVALIDHANDLE(fd)) { + tcfdbsetecode(fdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + return false; + } + fdb->fd = fd; + fdb->omode = omode; + + if (!(omode & FDBONOLCK)) { + if (!tclock(fd, omode & FDBOWRITER, omode & FDBOLCKNB)) { + tcfdbsetecode(fdb, TCELOCK, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + } + if ((omode & FDBOWRITER) && (omode & FDBOTRUNC)) { + if (!tcfdbftruncate2(fdb, 0, FDBTRALLOWSHRINK)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + if (!tcfdbwalremove(fdb, path)) { + CLOSEFH2(fdb->fd); + return false; + } + } + struct stat sbuf; + if (fstat(fd, &sbuf) || !S_ISREG(sbuf.st_mode)) { + tcfdbsetecode(fdb, TCESTAT, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + char hbuf[FDBHEADSIZ]; + if ((omode & FDBOWRITER) && (sbuf.st_size < 1 || (omode & FDBOTRUNC))) { + fdb->flags = 0; + fdb->rnum = 0; + fdb->fsiz = FDBHEADSIZ; + fdb->min = 0; + fdb->max = 0; + tcfdbdumpmeta(fdb, hbuf); + if (!tcwrite(fd, hbuf, FDBHEADSIZ)) { + tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + sbuf.st_size = fdb->fsiz; } + if (!tcfseek(fd, 0, TCFSTART)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + if (!tcread(fd, hbuf, FDBHEADSIZ)) { + tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + int type = fdb->type; tcfdbloadmeta(fdb, hbuf); - if(!tcfdbwalremove(fdb, path)){ - CLOSEFH(fd); - return false; - } - } - if(!(omode & FDBONOLCK)){ - if(memcmp(hbuf, FDBMAGICDATA, strlen(FDBMAGICDATA)) || fdb->type != type || - fdb->width < 1 || sbuf.st_size < fdb->fsiz || fdb->limsiz < FDBHEADSIZ || - fdb->fsiz > fdb->limsiz){ - tcfdbsetecode(fdb, TCEMETA, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(sbuf.st_size > fdb->fsiz) fdb->fsiz = sbuf.st_size; - } + if ((fdb->flags & FDBFOPEN) && tcfdbwalrestore(fdb, path)) { + if (!tcfseek(fd, 0, TCFSTART)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + if (!tcread(fd, hbuf, FDBHEADSIZ)) { + tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + tcfdbloadmeta(fdb, hbuf); + if (!tcfdbwalremove(fdb, path)) { + CLOSEFH2(fdb->fd); + return false; + } + } + if (!(omode & FDBONOLCK)) { + if (memcmp(hbuf, FDBMAGICDATA, strlen(FDBMAGICDATA)) || fdb->type != type || + fdb->width < 1 || sbuf.st_size < fdb->fsiz || fdb->limsiz < FDBHEADSIZ || + fdb->fsiz > fdb->limsiz) { + tcfdbsetecode(fdb, TCEMETA, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + return false; + } + if (sbuf.st_size > fdb->fsiz) fdb->fsiz = sbuf.st_size; + } #ifndef _WIN32 - void *map = mmap(0, fdb->limsiz, (PROT_READ | ((omode & FDBOWRITER) ? PROT_WRITE : 0)), - MAP_SHARED, fd, 0); - if(map == MAP_FAILED){ + void *map = mmap(0, fdb->limsiz, + (PROT_READ | ((omode & FDBOWRITER) ? PROT_WRITE : 0)), + MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + fdb->fd = INVALID_HANDLE_VALUE; + return false; + } + fdb->map = map; #else - LARGE_INTEGER limit; - limit.QuadPart = fdb->limsiz; - fdb->fileMapping = CreateFileMapping(fd, NULL, - ((omode & FDBOWRITER) ? PAGE_READWRITE : PAGE_READONLY), - limit.HighPart, limit.LowPart, NULL); - void *map = MapViewOfFile(fdb->fileMapping, - ((omode & FDBOWRITER) ? FILE_MAP_WRITE : FILE_MAP_READ), - 0, 0, 0); - if(map == NULL){ + if (!tcfdbftruncate(fdb, sbuf.st_size)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + CLOSEFH2(fdb->fd); + fdb->fd = INVALID_HANDLE_VALUE; + return false; + } #endif - tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(fdb->width <= UINT8_MAX){ - fdb->wsiz = sizeof(uint8_t); - } else if(fdb->width <= UINT16_MAX){ - fdb->wsiz = sizeof(uint16_t); - } else { - fdb->wsiz = sizeof(uint32_t); - } - fdb->rsiz = fdb->width + fdb->wsiz; - fdb->limid = (fdb->limsiz - FDBHEADSIZ) / fdb->rsiz; - fdb->path = tcstrdup(path); - fdb->fd = fd; - fdb->omode = omode; - fdb->iter = 0; - fdb->map = map; - fdb->array = (unsigned char *)map + FDBHEADSIZ; - fdb->ecode = TCESUCCESS; - fdb->fatal = false; - fdb->inode = (uint64_t)sbuf.st_ino; - fdb->mtime = sbuf.st_mtime; - fdb->tran = false; - fdb->walfd = INVALID_HANDLE_VALUE; - fdb->walend = 0; - if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true); - return true; + if (fdb->width <= UINT8_MAX) { + fdb->wsiz = sizeof (uint8_t); + } else if (fdb->width <= UINT16_MAX) { + fdb->wsiz = sizeof (uint16_t); + } else { + fdb->wsiz = sizeof (uint32_t); + } + fdb->rsiz = fdb->width + fdb->wsiz; + fdb->limid = (fdb->limsiz - FDBHEADSIZ) / fdb->rsiz; + fdb->path = tcstrdup(path); + fdb->iter = 0; + fdb->ecode = TCESUCCESS; + fdb->fatal = false; + fdb->inode = (uint64_t) sbuf.st_ino; + fdb->mtime = sbuf.st_mtime; + fdb->tran = false; + fdb->walfd = INVALID_HANDLE_VALUE; + fdb->walend = 0; + if (fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true); + return true; } - /* Close a fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbcloseimpl(TCFDB *fdb){ - assert(fdb); - bool err = false; - if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, false); - if((fdb->omode & FDBOWRITER) && !tcfdbmemsync(fdb, false)) err = true; +static bool tcfdbcloseimpl(TCFDB *fdb) { + assert(fdb); + bool err = false; + if (fdb->tran) { + if (!tcfdbwalrestore(fdb, fdb->path)) err = true; + fdb->tran = false; + } + if (fdb->omode & FDBOWRITER) { + if (!err && !tcfdbftruncate2(fdb, + ((uint64_t) FDBHEADSIZ + (fdb->max > 0 ? fdb->max + 1 : 0) * fdb->rsiz), + FDBTRALLOWSHRINK)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + tcfdbsetflag(fdb, FDBFOPEN, false); + if (!tcfdbmemsync(fdb, false)) err = true; + } + if (!FDBLOCKSMEM2(fdb, true)) err = true; #ifndef _WIN32 - if(munmap(fdb->map, fdb->limsiz)){ + if (fdb->map == NULL || munmap(fdb->map, fdb->limsiz)) { #else - if(UnmapViewOfFile(fdb->map) && CloseHandle(fdb->fileMapping)); - else{ + if (fdb->map) { + FlushViewOfFile((PCVOID) fdb->map, 0); + UnmapViewOfFile((LPVOID) fdb->map); + CLOSEFH2(fdb->w32hmap); + fdb->w32hmap = INVALID_HANDLE_VALUE; + } else { #endif - tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; - } - if(fdb->tran){ - if(!tcfdbwalrestore(fdb, fdb->path)) err = true; - fdb->tran = false; - } - if(!INVALIDHANDLE(fdb->walfd)){ - if(!CLOSEFH(fdb->walfd)){ - tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; } - if(!fdb->fatal && !tcfdbwalremove(fdb, fdb->path)) err = true; - } - if(!CLOSEFH(fdb->fd)){ - tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(fdb->path); - fdb->path = NULL; - fdb->fd = INVALID_HANDLE_VALUE; - return !err; -} + fdb->map = NULL; + FDBUNLOCKSMEM(fdb); + if (!INVALIDHANDLE(fdb->walfd)) { + if (!CLOSEFH(fdb->walfd)) { + tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); + err = true; + } + if (!fdb->fatal && !tcfdbwalremove(fdb, fdb->path)) { + err = true; + } + } + if (!INVALIDHANDLE(fdb->fd) && !CLOSEFH(fdb->fd)) { + tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__); + err = true; + } + TCFREE(fdb->path); + fdb->path = NULL; + fdb->fd = INVALID_HANDLE_VALUE; + fdb->walfd = INVALID_HANDLE_VALUE; + return !err; +} /* Get the previous record of a record. `fdb' specifies the fixed-length database object. `id' specifies the ID number. The return value is the ID number of the previous record or 0 if no record corresponds. */ -static int64_t tcfdbprevid(TCFDB *fdb, int64_t id){ - assert(fdb && id >= 0); - id--; - while(id >= fdb->min){ - TCDODEBUG(fdb->cnt_readrec++); - unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz); - unsigned char *rp = rec; - uint32_t osiz; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ - case 1: - osiz = *(rp++); - break; - case 2: - memcpy(&snum, rp, sizeof(snum)); - osiz = TCITOHS(snum); - rp += sizeof(snum); - break; - default: - memcpy(&lnum, rp, sizeof(lnum)); - osiz = TCITOHL(lnum); - rp += sizeof(lnum); - break; - } - if(osiz > 0 || *rp != 0) return id; +static int64_t tcfdbprevid(TCFDB *fdb, int64_t id) { + assert(fdb && id >= 0); id--; - } - return 0; + while (id >= fdb->min) { + TCDODEBUG(fdb->cnt_readrec++); + unsigned char *rec = FDBRP(fdb, id); + unsigned char *rp = rec; + uint32_t osiz; + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { + case 1: + osiz = *(rp++); + break; + case 2: + memcpy(&snum, rp, sizeof (snum)); + osiz = TCITOHS(snum); + rp += sizeof (snum); + break; + default: + memcpy(&lnum, rp, sizeof (lnum)); + osiz = TCITOHL(lnum); + rp += sizeof (lnum); + break; + } + if (osiz > 0 || *rp != 0) return id; + id--; + } + return 0; } - /* Get the next record of a record. `fdb' specifies the fixed-length database object. `id' specifies the ID number. The return value is the ID number of the next record or 0 if no record corresponds. */ -static int64_t tcfdbnextid(TCFDB *fdb, int64_t id){ - assert(fdb && id >= 0); - id++; - while(id <= fdb->max){ - TCDODEBUG(fdb->cnt_readrec++); - unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz); - unsigned char *rp = rec; - uint32_t osiz; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ - case 1: - osiz = *(rp++); - break; - case 2: - memcpy(&snum, rp, sizeof(snum)); - osiz = TCITOHS(snum); - rp += sizeof(snum); - break; - default: - memcpy(&lnum, rp, sizeof(lnum)); - osiz = TCITOHL(lnum); - rp += sizeof(lnum); - break; - } - if(osiz > 0 || *rp != 0) return id; +static int64_t tcfdbnextid(TCFDB *fdb, int64_t id) { + assert(fdb && id >= 0); id++; - } - return 0; + while (id <= fdb->max) { + TCDODEBUG(fdb->cnt_readrec++); + unsigned char *rec = FDBRP(fdb, id); + unsigned char *rp = rec; + uint32_t osiz; + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { + case 1: + osiz = *(rp++); + break; + case 2: + memcpy(&snum, rp, sizeof (snum)); + osiz = TCITOHS(snum); + rp += sizeof (snum); + break; + default: + memcpy(&lnum, rp, sizeof (lnum)); + osiz = TCITOHL(lnum); + rp += sizeof (lnum); + break; + } + if (osiz > 0 || *rp != 0) return id; + id++; + } + return 0; } - /* Store a record. `fdb' specifies the fixed-length database object. `id' specifies the ID number. @@ -2065,308 +2140,368 @@ static int64_t tcfdbnextid(TCFDB *fdb, int64_t id){ `vsiz' specifies the size of the region of the value. `dmode' specifies behavior when the key overlaps. If successful, the return value is true, else, it is false. */ -static bool tcfdbputimpl(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, int dmode){ - assert(fdb && id > 0); - if(vsiz > (int64_t)fdb->width) vsiz = fdb->width; - TCDODEBUG(fdb->cnt_readrec++); - unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz); - uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; - if(nsiz > fdb->fsiz){ - if(nsiz > fdb->limsiz){ - tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - if(!FDBLOCKATTR(fdb)) return false; - if(nsiz > fdb->fsiz){ - if(vsiz < 0){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - FDBUNLOCKATTR(fdb); - return false; - } - if(nsiz + fdb->rsiz * FDBTRUNCALW < fdb->limsiz) nsiz += fdb->rsiz * FDBTRUNCALW; - if(!tcftruncate(fdb->fd, nsiz)){ - tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); +static bool tcfdbputimpl(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, int dmode) { + assert(fdb && id > 0); + bool err = false; + if (vsiz > (int64_t) fdb->width) vsiz = fdb->width; + TCDODEBUG(fdb->cnt_readrec++); + uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; + if (nsiz > fdb->fsiz) { + if (nsiz > fdb->limsiz) { + tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + //take a WRITE LOCK to change fdb->map in tcfdbftruncate2 + if (!FDBLOCKSMEM(fdb, true)) { + return false; + } + if (!FDBLOCKATTR(fdb)) { + FDBUNLOCKSMEM(fdb); + return false; + } + if (nsiz > fdb->fsiz) { + if (vsiz < 0) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + err = true; + } + if (!err && !tcfdbftruncate2(fdb, nsiz, FDBWRITENOLOCK)) { + tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + if (!err) { + TCDODEBUG(fdb->cnt_truncfile++); + unsigned char *wp = FDBRP(fdb, id); + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { + case 1: + *(wp++) = vsiz; + break; + case 2: + snum = TCHTOIS(vsiz); + memcpy(wp, &snum, sizeof (snum)); + wp += sizeof (snum); + break; + default: + lnum = TCHTOIL(vsiz); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + break; + } + if (vsiz > 0) { + memcpy(wp, vbuf, vsiz); + } else { + *wp = 1; + } + TCDODEBUG(fdb->cnt_writerec++); + fdb->rnum++; + if (fdb->min < 1 || id < fdb->min) fdb->min = id; + if (fdb->max < 1 || id > fdb->max) fdb->max = id; + } + } FDBUNLOCKATTR(fdb); + FDBUNLOCKSMEM(fdb); + return !err; + } + + //Take a read lock on shared mem because + //we would not change fdb->map address by tcfdbftruncate2 + //and our write area is locked by FDBLOCKRECORD + if (!FDBLOCKSMEM(fdb, false)) { return false; - } - TCDODEBUG(fdb->cnt_truncfile++); - fdb->fsiz = nsiz; - unsigned char *wp = rec; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ + } + unsigned char *rp = FDBRP(fdb, id); + uint32_t osiz; + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { case 1: - *(wp++) = vsiz; - break; + osiz = *(rp++); + break; case 2: - snum = TCHTOIS(vsiz); - memcpy(wp, &snum, sizeof(snum)); - wp += sizeof(snum); - break; + memcpy(&snum, rp, sizeof (snum)); + osiz = TCITOHS(snum); + rp += sizeof (snum); + break; default: - lnum = TCHTOIL(vsiz); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - break; - } - if(vsiz > 0){ - memcpy(wp, vbuf, vsiz); - } else { - *wp = 1; - } - TCDODEBUG(fdb->cnt_writerec++); - fdb->rnum++; - if(fdb->min < 1 || id < fdb->min) fdb->min = id; - if(fdb->max < 1 || id > fdb->max) fdb->max = id; - FDBUNLOCKATTR(fdb); - return true; + memcpy(&lnum, rp, sizeof (lnum)); + osiz = TCITOHL(lnum); + rp += sizeof (lnum); + break; } - FDBUNLOCKATTR(fdb); - } - unsigned char *rp = rec; - uint32_t osiz; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ - case 1: - osiz = *(rp++); - break; - case 2: - memcpy(&snum, rp, sizeof(snum)); - osiz = TCITOHS(snum); - rp += sizeof(snum); - break; - default: - memcpy(&lnum, rp, sizeof(lnum)); - osiz = TCITOHL(lnum); - rp += sizeof(lnum); - break; - } - bool miss = osiz == 0 && *rp == 0; - if(dmode != FDBPDOVER && !miss){ - if(dmode == FDBPDKEEP){ - tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - if(dmode == FDBPDCAT){ - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - vsiz = tclmin(vsiz, fdb->width - osiz); - unsigned char *wp = rec; - int usiz = osiz + vsiz; - switch(fdb->wsiz){ + bool miss = osiz == 0 && *rp == 0; + if (dmode != FDBPDOVER && !miss) { + if (dmode == FDBPDKEEP) { + tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + if (dmode == FDBPDCAT) { + unsigned char *rec = FDBRP(fdb, id); + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + vsiz = tclmin(vsiz, fdb->width - osiz); + unsigned char *wp = rec; + int usiz = osiz + vsiz; + switch (fdb->wsiz) { + case 1: + *(wp++) = usiz; + break; + case 2: + snum = TCHTOIS(usiz); + memcpy(wp, &snum, sizeof (snum)); + wp += sizeof (snum); + break; + default: + lnum = TCHTOIL(usiz); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + break; + } + if (usiz > 0) { + memcpy(wp + osiz, vbuf, vsiz); + } else { + *wp = 1; + } + TCDODEBUG(fdb->cnt_writerec++); + goto finish; + } + if (dmode == FDBPDADDINT) { + if (osiz != sizeof (int)) { + tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + int lnum; + memcpy(&lnum, rp, sizeof (lnum)); + if (*(int *) vbuf == 0) { + *(int *) vbuf = lnum; + goto finish; + } + unsigned char *rec = FDBRP(fdb, id); + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + lnum += *(int *) vbuf; + *(int *) vbuf = lnum; + memcpy(rp, &lnum, sizeof (lnum)); + TCDODEBUG(fdb->cnt_writerec++); + goto finish; + } + if (dmode == FDBPDADDDBL) { + if (osiz != sizeof (double)) { + tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + double dnum; + memcpy(&dnum, rp, sizeof (dnum)); + if (*(double *) vbuf == 0.0) { + *(double *) vbuf = dnum; + goto finish; + } + unsigned char *rec = FDBRP(fdb, id); + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + dnum += *(double *) vbuf; + *(double *) vbuf = dnum; + memcpy(rp, &dnum, sizeof (dnum)); + TCDODEBUG(fdb->cnt_writerec++); + goto finish; + } + if (dmode == FDBPDPROC) { + FDBPDPROCOP *procptr = *(FDBPDPROCOP **) ((char *) vbuf - sizeof (procptr)); + int nvsiz; + unsigned char *rec = FDBRP(fdb, id); + char *nvbuf = procptr->proc(rp, osiz, &nvsiz, procptr->op); + if (nvbuf == (void *) - 1) { + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + memset(rec, 0, fdb->wsiz + 1); + TCDODEBUG(fdb->cnt_writerec++); + if (!FDBLOCKATTR(fdb)) { + err = true; + goto finish; + } + fdb->rnum--; + if (fdb->rnum < 1) { + fdb->min = 0; + fdb->max = 0; + } else if (fdb->rnum < 2) { + if (fdb->min == id) { + fdb->min = fdb->max; + } else if (fdb->max == id) { + fdb->max = fdb->min; + } + } else { + if (id == fdb->min) fdb->min = tcfdbnextid(fdb, id); + if (id == fdb->max) fdb->max = tcfdbprevid(fdb, id); + } + FDBUNLOCKATTR(fdb); + goto finish; + } + if (!nvbuf) { + tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + if (nvsiz > fdb->width) nvsiz = fdb->width; + unsigned char *wp = rec; + switch (fdb->wsiz) { + case 1: + *(wp++) = nvsiz; + break; + case 2: + snum = TCHTOIS(nvsiz); + memcpy(wp, &snum, sizeof (snum)); + wp += sizeof (snum); + break; + default: + lnum = TCHTOIL(nvsiz); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + break; + } + if (nvsiz > 0) { + memcpy(wp, nvbuf, nvsiz); + } else { + *wp = 1; + } + TCFREE(nvbuf); + TCDODEBUG(fdb->cnt_writerec++); + goto finish; + } + } + if (vsiz < 0) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + unsigned char *rec = FDBRP(fdb, id); + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + }; + unsigned char *wp = rec; + switch (fdb->wsiz) { case 1: - *(wp++) = usiz; - break; + *(wp++) = vsiz; + break; case 2: - snum = TCHTOIS(usiz); - memcpy(wp, &snum, sizeof(snum)); - wp += sizeof(snum); - break; + snum = TCHTOIS(vsiz); + memcpy(wp, &snum, sizeof (snum)); + wp += sizeof (snum); + break; default: - lnum = TCHTOIL(usiz); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - break; - } - if(usiz > 0){ - memcpy(wp + osiz, vbuf, vsiz); - } else { + lnum = TCHTOIL(vsiz); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + break; + } + if (vsiz > 0) { + memcpy(wp, vbuf, vsiz); + } else { *wp = 1; - } - TCDODEBUG(fdb->cnt_writerec++); - return true; - } - if(dmode == FDBPDADDINT){ - if(osiz != sizeof(int)){ - tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - int lnum; - memcpy(&lnum, rp, sizeof(lnum)); - if(*(int *)vbuf == 0){ - *(int *)vbuf = lnum; - return true; - } - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - lnum += *(int *)vbuf; - *(int *)vbuf = lnum; - memcpy(rp, &lnum, sizeof(lnum)); - TCDODEBUG(fdb->cnt_writerec++); - return true; - } - if(dmode == FDBPDADDDBL){ - if(osiz != sizeof(double)){ - tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - double dnum; - memcpy(&dnum, rp, sizeof(dnum)); - if(*(double *)vbuf == 0.0){ - *(double *)vbuf = dnum; - return true; - } - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - dnum += *(double *)vbuf; - *(double *)vbuf = dnum; - memcpy(rp, &dnum, sizeof(dnum)); - TCDODEBUG(fdb->cnt_writerec++); - return true; - } - if(dmode == FDBPDPROC){ - FDBPDPROCOP *procptr = *(FDBPDPROCOP **)((char *)vbuf - sizeof(procptr)); - int nvsiz; - char *nvbuf = procptr->proc(rp, osiz, &nvsiz, procptr->op); - if(nvbuf == (void *)-1){ - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - memset(rec, 0, fdb->wsiz + 1); - TCDODEBUG(fdb->cnt_writerec++); - if(!FDBLOCKATTR(fdb)) return false; - fdb->rnum--; - if(fdb->rnum < 1){ - fdb->min = 0; - fdb->max = 0; - } else if(fdb->rnum < 2){ - if(fdb->min == id){ - fdb->min = fdb->max; - } else if(fdb->max == id){ - fdb->max = fdb->min; - } - } else { - if(id == fdb->min) fdb->min = tcfdbnextid(fdb, id); - if(id == fdb->max) fdb->max = tcfdbprevid(fdb, id); + } + TCDODEBUG(fdb->cnt_writerec++); + if (miss) { + if (!FDBLOCKATTR(fdb)) { + err = true; + goto finish; } + fdb->rnum++; + if (fdb->min < 1 || id < fdb->min) fdb->min = id; + if (fdb->max < 1 || id > fdb->max) fdb->max = id; FDBUNLOCKATTR(fdb); - return true; - } - if(!nvbuf){ - tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - } - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - if(nvsiz > fdb->width) nvsiz = fdb->width; - unsigned char *wp = rec; - switch(fdb->wsiz){ - case 1: - *(wp++) = nvsiz; - break; - case 2: - snum = TCHTOIS(nvsiz); - memcpy(wp, &snum, sizeof(snum)); - wp += sizeof(snum); - break; - default: - lnum = TCHTOIL(nvsiz); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - break; - } - if(nvsiz > 0){ - memcpy(wp, nvbuf, nvsiz); - } else { - *wp = 1; - } - TCFREE(nvbuf); - TCDODEBUG(fdb->cnt_writerec++); - return true; - } - } - if(vsiz < 0){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - unsigned char *wp = rec; - switch(fdb->wsiz){ - case 1: - *(wp++) = vsiz; - break; - case 2: - snum = TCHTOIS(vsiz); - memcpy(wp, &snum, sizeof(snum)); - wp += sizeof(snum); - break; - default: - lnum = TCHTOIL(vsiz); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - break; - } - if(vsiz > 0){ - memcpy(wp, vbuf, vsiz); - } else { - *wp = 1; - } - TCDODEBUG(fdb->cnt_writerec++); - if(miss){ - if(!FDBLOCKATTR(fdb)) return false; - fdb->rnum++; - if(fdb->min < 1 || id < fdb->min) fdb->min = id; - if(fdb->max < 1 || id > fdb->max) fdb->max = id; - FDBUNLOCKATTR(fdb); - } - return true; + } +finish: + FDBUNLOCKSMEM(fdb); + return !err; } - /* Remove a record of a fixed-length database object. `fdb' specifies the fixed-length database object. `id' specifies the ID number. If successful, the return value is true, else, it is false. */ -static bool tcfdboutimpl(TCFDB *fdb, int64_t id){ - assert(fdb && id >= 0); - TCDODEBUG(fdb->cnt_readrec++); - unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz); - uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; - if(nsiz > fdb->fsiz){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - unsigned char *rp = rec; - uint32_t osiz; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ - case 1: - osiz = *(rp++); - break; - case 2: - memcpy(&snum, rp, sizeof(snum)); - osiz = TCITOHS(snum); - rp += sizeof(snum); - break; - default: - memcpy(&lnum, rp, sizeof(lnum)); - osiz = TCITOHL(lnum); - rp += sizeof(lnum); - break; - } - if(osiz == 0 && *rp == 0){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false; - memset(rec, 0, fdb->wsiz + 1); - TCDODEBUG(fdb->cnt_writerec++); - if(!FDBLOCKATTR(fdb)) return false; - fdb->rnum--; - if(fdb->rnum < 1){ - fdb->min = 0; - fdb->max = 0; - } else if(fdb->rnum < 2){ - if(fdb->min == id){ - fdb->min = fdb->max; - } else if(fdb->max == id){ - fdb->max = fdb->min; +static bool tcfdboutimpl(TCFDB *fdb, int64_t id) { + assert(fdb && id >= 0); + TCDODEBUG(fdb->cnt_readrec++); + uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; + if (nsiz > fdb->fsiz) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + //Take a read lock on shared mem because + //we would not change fdb->map address by tcfdbftruncate2 + //and our write area is locked by FDBLOCKRECORD + if (!FDBLOCKSMEM(fdb, false)) return false; + bool err = false; + unsigned char *rec = FDBRP(fdb, id); + unsigned char *rp = rec; + uint32_t osiz; + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { + case 1: + osiz = *(rp++); + break; + case 2: + memcpy(&snum, rp, sizeof (snum)); + osiz = TCITOHS(snum); + rp += sizeof (snum); + break; + default: + memcpy(&lnum, rp, sizeof (lnum)); + osiz = TCITOHL(lnum); + rp += sizeof (lnum); + break; + } + if (osiz == 0 && *rp == 0) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + err = true; + goto finish; } - } else { - if(id == fdb->min) fdb->min = tcfdbnextid(fdb, id); - if(id == fdb->max) fdb->max = tcfdbprevid(fdb, id); - } - FDBUNLOCKATTR(fdb); - return true; + if (fdb->tran && !tcfdbwalwrite(fdb, (char *) rec - fdb->map, fdb->width)) { + err = true; + goto finish; + } + memset(rec, 0, fdb->wsiz + 1); + TCDODEBUG(fdb->cnt_writerec++); + if (!FDBLOCKATTR(fdb)) { + err = true; + goto finish; + } + fdb->rnum--; + if (fdb->rnum < 1) { + fdb->min = 0; + fdb->max = 0; + } else if (fdb->rnum < 2) { + if (fdb->min == id) { + fdb->min = fdb->max; + } else if (fdb->max == id) { + fdb->max = fdb->min; + } + } else { + if (id == fdb->min) fdb->min = tcfdbnextid(fdb, id); + if (id == fdb->max) fdb->max = tcfdbprevid(fdb, id); + } + FDBUNLOCKATTR(fdb); +finish: + FDBUNLOCKSMEM(fdb); + return !err; } - /* Retrieve a record. `fdb' specifies the fixed-length database object. `id' specifies the ID number. @@ -2374,68 +2509,65 @@ static bool tcfdboutimpl(TCFDB *fdb, int64_t id){ value is assigned. If successful, the return value is the pointer to the region of the value of the corresponding record. */ -static const void *tcfdbgetimpl(TCFDB *fdb, int64_t id, int *sp){ - assert(fdb && id >= 0 && sp); - TCDODEBUG(fdb->cnt_readrec++); - unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz); - uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; - if(nsiz > fdb->fsiz){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - unsigned char *rp = rec; - uint32_t osiz; - uint16_t snum; - uint32_t lnum; - switch(fdb->wsiz){ - case 1: - osiz = *(rp++); - break; - case 2: - memcpy(&snum, rp, sizeof(snum)); - osiz = TCITOHS(snum); - rp += sizeof(snum); - break; - default: - memcpy(&lnum, rp, sizeof(lnum)); - osiz = TCITOHL(lnum); - rp += sizeof(lnum); - break; - } - if(osiz == 0 && *rp == 0){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - *sp = osiz; - return rp; +static const void *tcfdbgetimpl(TCFDB *fdb, int64_t id, int *sp) { + assert(fdb && id >= 0 && sp); + TCDODEBUG(fdb->cnt_readrec++); + unsigned char *rec = FDBRP(fdb, id); + uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz; + if (nsiz > fdb->fsiz) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; + } + unsigned char *rp = rec; + uint32_t osiz; + uint16_t snum; + uint32_t lnum; + switch (fdb->wsiz) { + case 1: + osiz = *(rp++); + break; + case 2: + memcpy(&snum, rp, sizeof (snum)); + osiz = TCITOHS(snum); + rp += sizeof (snum); + break; + default: + memcpy(&lnum, rp, sizeof (lnum)); + osiz = TCITOHL(lnum); + rp += sizeof (lnum); + break; + } + if (osiz == 0 && *rp == 0) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; + } + *sp = osiz; + return rp; } - /* Initialize the iterator of a fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbiterinitimpl(TCFDB *fdb){ - assert(fdb); - fdb->iter = fdb->min; - return true; +static bool tcfdbiterinitimpl(TCFDB *fdb) { + assert(fdb); + fdb->iter = fdb->min; + return true; } - /* Get the next key of the iterator of a fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is the next ID number of the iterator, else, it is 0. */ -static uint64_t tcfdbiternextimpl(TCFDB *fdb){ - assert(fdb); - if(fdb->iter < 1){ - tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); - return 0; - } - uint64_t cur = fdb->iter; - fdb->iter = tcfdbnextid(fdb, fdb->iter); - return cur; +static uint64_t tcfdbiternextimpl(TCFDB *fdb) { + assert(fdb); + if (fdb->iter < 1) { + tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__); + return 0; + } + uint64_t cur = fdb->iter; + fdb->iter = tcfdbnextid(fdb, fdb->iter); + return cur; } - /* Get range matching ID numbers in a fixed-length database object. `fdb' specifies the fixed-length database object. `lower' specifies the lower limit of the range. @@ -2445,396 +2577,528 @@ static uint64_t tcfdbiternextimpl(TCFDB *fdb){ value is assigned. If successful, the return value is the pointer to an array of ID numbers of the corresponding records. */ -static uint64_t *tcfdbrangeimpl(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np){ - assert(fdb && lower > 0 && upper > 0 && np); - if(lower < fdb->min) lower = fdb->min; - if(upper > fdb->max) upper = fdb->max; - if(max < 0) max = INT_MAX; - int anum = FDBIDARYUNIT; - uint64_t *ids; - TCMALLOC(ids, anum * sizeof(*ids)); - int num = 0; - for(int64_t i = lower; i <= upper && num < max; i++){ - int vsiz; - const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz); - if(vbuf){ - if(num >= anum){ - anum *= 2; - TCREALLOC(ids, ids, anum * sizeof(*ids)); - } - ids[num++] = i; +static uint64_t *tcfdbrangeimpl(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np) { + assert(fdb && lower > 0 && upper > 0 && np); + if (!FDBLOCKSMEM(fdb, false)) { + return NULL; } - } - *np = num; - return ids; + if (lower < fdb->min) lower = fdb->min; + if (upper > fdb->max) upper = fdb->max; + if (max < 0) max = INT_MAX; + int anum = FDBIDARYUNIT; + uint64_t *ids; + TCMALLOC(ids, anum * sizeof (*ids)); + int num = 0; + for (int64_t i = lower; i <= upper && num < max; i++) { + int vsiz; + const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz); + if (vbuf) { + if (num >= anum) { + anum *= 2; + TCREALLOC(ids, ids, anum * sizeof (*ids)); + } + ids[num++] = i; + } + } + FDBUNLOCKSMEM(fdb); + *np = num; + return ids; } - /* Optimize the file of a fixed-length database object. `fdb' specifies the fixed-length database object. `width' specifies the width of the value of each record. `limsiz' specifies the limit size of the database file. If successful, the return value is true, else, it is false. */ -static bool tcfdboptimizeimpl(TCFDB *fdb, int32_t width, int64_t limsiz){ - assert(fdb); - char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", fdb->path, MYEXTCHR, MYEXTCHR, fdb->inode); - char *opath; - int omode = (fdb->omode & ~FDBOCREAT) & ~FDBOTRUNC; - TCFDB *tfdb = tcfdbnew(); - tfdb->dbgfd = fdb->dbgfd; - if(width < 1) width = fdb->width; - if(limsiz < 1) limsiz = fdb->limsiz; - tcfdbtune(tfdb, width, limsiz); - if(!tcfdbopen(tfdb, tpath, FDBOWRITER | FDBOCREAT | FDBOTRUNC)){ - tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); +static bool tcfdboptimizeimpl(TCFDB *fdb, int32_t width, int64_t limsiz) { + assert(fdb); + char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", fdb->path, MYEXTCHR, MYEXTCHR, fdb->inode); + char *opath; + int omode = (fdb->omode & ~FDBOCREAT) & ~FDBOTRUNC; + TCFDB *tfdb = tcfdbnew(); + tfdb->dbgfd = fdb->dbgfd; + if (width < 1) width = fdb->width; + if (limsiz < 1) limsiz = fdb->limsiz; + tcfdbtune(tfdb, width, limsiz); + if (!tcfdbopen(tfdb, tpath, FDBOWRITER | FDBOCREAT | FDBOTRUNC)) { + tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); + tcfdbdel(tfdb); + TCFREE(tpath); + return false; + } + bool err = false; + int64_t max = fdb->max; + if (FDBLOCKSMEM(fdb, false)) { + for (int i = fdb->min; !err && i <= max; i++) { + int vsiz; + const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz); + if (vbuf && !tcfdbput(tfdb, i, vbuf, vsiz)) { + tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); + err = true; + } + } + FDBUNLOCKSMEM(fdb); + } else { + err = true; + } + if (!tcfdbclose(tfdb)) { + tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); + err = true; + } tcfdbdel(tfdb); + opath = tcstrdup(fdb->path); + if (!tcfdbcloseimpl(fdb)) { + TCFREE(tpath); + TCFREE(opath); + return false; + } + if (!tcunlinkfile(opath)) { + tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + if (!tcrenamefile(tpath, opath)) { + tcfdbsetecode(fdb, TCERENAME, __FILE__, __LINE__, __func__); + err = true; + } TCFREE(tpath); - return false; - } - bool err = false; - int64_t max = fdb->max; - for(int i = fdb->min; !err && i <= max; i++){ - int vsiz; - const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz); - if(vbuf && !tcfdbput(tfdb, i, vbuf, vsiz)){ - tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); - err = true; - } - } - if(!tcfdbclose(tfdb)){ - tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__); - err = true; - } - tcfdbdel(tfdb); - opath = tcstrdup(fdb->path); - if(!tcfdbcloseimpl(fdb)){ - TCFREE(tpath); + if (err) { + TCFREE(opath); + return false; + } + bool rv = tcfdbopenimpl(fdb, opath, omode); TCFREE(opath); - return false; - } - if(unlink(opath)){ - tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - if(rename(tpath, opath)){ - tcfdbsetecode(fdb, TCERENAME, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(tpath); - if(err) { - TCFREE(opath); - return false; - } - bool rv = tcfdbopenimpl(fdb, opath, omode); - TCFREE(opath); - return rv; + return rv; } - /* Remove all records of a fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbvanishimpl(TCFDB *fdb){ - assert(fdb); - char *path = tcstrdup(fdb->path); - int omode = fdb->omode; - bool err = false; - if(!tcfdbcloseimpl(fdb)) err = true; - if(!tcfdbopenimpl(fdb, path, FDBOTRUNC | omode)){ - tcpathunlock(fdb->rpath); - TCFREE(fdb->rpath); - err = true; - } - TCFREE(path); - return !err; +static bool tcfdbvanishimpl(TCFDB *fdb) { + assert(fdb); + char *path = tcstrdup(fdb->path); + int omode = fdb->omode; + bool err = false; + if (!tcfdbcloseimpl(fdb)) err = true; + if (!tcfdbopenimpl(fdb, path, FDBOTRUNC | omode)) { + tcpathunlock(fdb->rpath); + TCFREE(fdb->rpath); + err = true; + } + TCFREE(path); + return !err; } - /* Copy the database file of a fixed-length database object. `fdb' specifies the fixed-length database object. `path' specifies the path of the destination file. If successful, the return value is true, else, it is false. */ -static bool tcfdbcopyimpl(TCFDB *fdb, const char *path){ - assert(fdb && path); - bool err = false; - if(fdb->omode & FDBOWRITER){ - if(!tcfdbmemsync(fdb, false)) err = true; - tcfdbsetflag(fdb, FDBFOPEN, false); - } - if(*path == '@'){ - char tsbuf[TCNUMBUFSIZ]; - sprintf(tsbuf, "%" PRIuMAX "", (unsigned long long)(tctime() * 1000000)); - const char *args[3]; - args[0] = path + 1; - args[1] = fdb->path; - args[2] = tsbuf; - if(tcsystem(args, sizeof(args) / sizeof(*args)) != 0) err = true; - } else { - if(!tccopyfile(fdb->path, path)){ - tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__); - err = true; - } - } - if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true); - return !err; +static bool tcfdbcopyimpl(TCFDB *fdb, const char *path) { + assert(fdb && path); + bool err = false; + if (fdb->omode & FDBOWRITER) { + if (!tcfdbmemsync(fdb, false)) err = true; + tcfdbsetflag(fdb, FDBFOPEN, false); + } + if (*path == '@') { + char tsbuf[TCNUMBUFSIZ]; + sprintf(tsbuf, "%" PRIuMAX "", (unsigned long long) (tctime() * 1000000)); + const char *args[3]; + args[0] = path + 1; + args[1] = fdb->path; + args[2] = tsbuf; + if (tcsystem(args, sizeof (args) / sizeof (*args)) != 0) err = true; + } else { + if (!tccopyfile(fdb->path, path)) { + tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__); + err = true; + } + } + if (fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true); + return !err; } - /* Move the iterator to the record corresponding a key of a fixed-length database object. `fdb' specifies the fixed-length database object. `id' specifies the ID number. If successful, the return value is true, else, it is false. */ -static bool tcfdbiterjumpimpl(TCFDB *fdb, int64_t id){ - assert(fdb && id >= 0); - if(id <= fdb->min){ - fdb->iter = fdb->min; - } else { - int vsiz; - if(tcfdbgetimpl(fdb, id, &vsiz)){ - fdb->iter = id; +static bool tcfdbiterjumpimpl(TCFDB *fdb, int64_t id) { + assert(fdb && id >= 0); + if (id <= fdb->min) { + fdb->iter = fdb->min; } else { - uint64_t iter = tcfdbnextid(fdb, id); - if(iter > 0){ - fdb->iter = iter; - } else { - return false; - } + int vsiz; + if (tcfdbgetimpl(fdb, id, &vsiz)) { + fdb->iter = id; + } else { + uint64_t iter = tcfdbnextid(fdb, id); + if (iter > 0) { + fdb->iter = iter; + } else { + return false; + } + } } - } - return true; + return true; } - /* Process each record atomically of a fixed-length database object. `fdb' specifies the fixed-length database object. `iter' specifies the pointer to the iterator function called for each record. `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If successful, the return value is true, else, it is false. */ -static bool tcfdbforeachimpl(TCFDB *fdb, TCITER iter, void *op){ - bool err = false; - uint64_t id = fdb->min; - while(id > 0){ - int vsiz; - const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz); - if(vbuf){ - char kbuf[TCNUMBUFSIZ]; - int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long)id); - if(!iter(kbuf, ksiz, vbuf, vsiz, op)) break; - } else { - tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__); - err = true; +static bool tcfdbforeachimpl(TCFDB *fdb, TCITER iter, void *op) { + bool err = false; + uint64_t id = fdb->min; + uint64_t nid = id; + while (id > 0) { + int vsiz; + if (!FDBLOCKSMEM(fdb, false)) { + err = true; + break; + } + const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz); + nid = tcfdbnextid(fdb, id); + FDBUNLOCKSMEM(fdb); + if (vbuf) { + char kbuf[TCNUMBUFSIZ]; + int ksiz = sprintf(kbuf, "%" PRIuMAX "", (unsigned long long) id); + if (!iter(kbuf, ksiz, vbuf, vsiz, op)) { + break; + } + } else { + tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__); + err = true; + } + id = nid; } - id = tcfdbnextid(fdb, id); - } - return !err; + return !err; } - /* Lock a method of the fixed-length database object. `fdb' specifies the fixed-length database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -static bool tcfdblockmethod(TCFDB *fdb, bool wr){ - assert(fdb); - if(wr ? pthread_rwlock_wrlock(fdb->mmtx) != 0 : pthread_rwlock_rdlock(fdb->mmtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdblockmethod(TCFDB *fdb, bool wr) { + assert(fdb); + if (wr ? pthread_rwlock_wrlock(fdb->mmtx) != 0 : pthread_rwlock_rdlock(fdb->mmtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock a method of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbunlockmethod(TCFDB *fdb){ - assert(fdb); - if(pthread_rwlock_unlock(fdb->mmtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdbunlockmethod(TCFDB *fdb) { + assert(fdb); + if (pthread_rwlock_unlock(fdb->mmtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock the attributes of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdblockattr(TCFDB *fdb){ - assert(fdb); - if(pthread_mutex_lock(fdb->amtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdblockattr(TCFDB *fdb) { + assert(fdb); + if (pthread_mutex_lock(fdb->amtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock the attributes of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbunlockattr(TCFDB *fdb){ - assert(fdb); - if(pthread_mutex_unlock(fdb->amtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdbunlockattr(TCFDB *fdb) { + assert(fdb); + if (pthread_mutex_unlock(fdb->amtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock a record of the fixed-length database object. `fdb' specifies the fixed-length database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -static bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id){ - assert(fdb && id > 0); - if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0 : - pthread_rwlock_rdlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id) { + assert(fdb && id > 0); + if (wr ? pthread_rwlock_wrlock((pthread_rwlock_t *) fdb->rmtxs + id % FDBRMTXNUM) != 0 : + pthread_rwlock_rdlock((pthread_rwlock_t *) fdb->rmtxs + id % FDBRMTXNUM) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock a record of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id){ - assert(fdb); - if(pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id) { + assert(fdb); + if (pthread_rwlock_unlock((pthread_rwlock_t *) fdb->rmtxs + id % FDBRMTXNUM) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock all records of the fixed-length database object. `fdb' specifies the fixed-length database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -static bool tcfdblockallrecords(TCFDB *fdb, bool wr){ - assert(fdb); - for(int i = 0; i < FDBRMTXNUM; i++){ - if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)fdb->rmtxs + i) != 0 : - pthread_rwlock_rdlock((pthread_rwlock_t *)fdb->rmtxs + i) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - while(--i >= 0){ - pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + i); - } - return false; +EJDB_INLINE bool tcfdblockallrecords(TCFDB *fdb, bool wr) { + assert(fdb); + for (int i = 0; i < FDBRMTXNUM; i++) { + if (wr ? pthread_rwlock_wrlock((pthread_rwlock_t *) fdb->rmtxs + i) != 0 : + pthread_rwlock_rdlock((pthread_rwlock_t *) fdb->rmtxs + i) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + while (--i >= 0) { + pthread_rwlock_unlock((pthread_rwlock_t *) fdb->rmtxs + i); + } + return false; + } } - } - TCTESTYIELD(); - return true; + TCTESTYIELD(); + return true; } - /* Unlock all records of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbunlockallrecords(TCFDB *fdb){ - assert(fdb); - bool err = false; - for(int i = FDBRMTXNUM - 1; i >= 0; i--){ - if(pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + i)) err = true; - } - TCTESTYIELD(); - if(err){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - return true; +EJDB_INLINE bool tcfdbunlockallrecords(TCFDB *fdb) { + assert(fdb); + bool err = false; + for (int i = FDBRMTXNUM - 1; i >= 0; i--) { + if (pthread_rwlock_unlock((pthread_rwlock_t *) fdb->rmtxs + i)) err = true; + } + TCTESTYIELD(); + if (err) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + return true; } - /* Lock the write ahead logging file of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdblockwal(TCFDB *fdb){ - assert(fdb); - if(pthread_mutex_lock(fdb->wmtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdblockwal(TCFDB *fdb) { + assert(fdb); + if (pthread_mutex_lock(fdb->wmtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock the write ahead logging file of the fixed-length database object. `fdb' specifies the fixed-length database object. If successful, the return value is true, else, it is false. */ -static bool tcfdbunlockwal(TCFDB *fdb){ - assert(fdb); - if(pthread_mutex_unlock(fdb->wmtx) != 0){ - tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tcfdbunlockwal(TCFDB *fdb) { + assert(fdb); + if (pthread_mutex_unlock(fdb->wmtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } +/* Lock shared memory */ +EJDB_INLINE bool tcfdblocksmem(TCFDB *fdb, bool wr) { + assert(fdb); + if (wr ? pthread_rwlock_wrlock(fdb->smtx) != 0 : pthread_rwlock_rdlock(fdb->smtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + if (fdb->map == NULL) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + tcfdbunlocksmem(fdb); + return false; + } + TCTESTYIELD(); + return true; +} + +EJDB_INLINE bool tcfdblocksmem2(TCFDB *fdb, bool wr) { + assert(fdb); + if (wr ? pthread_rwlock_wrlock(fdb->smtx) != 0 : pthread_rwlock_rdlock(fdb->smtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; +} + +/* Unlock shared memory */ +EJDB_INLINE bool tcfdbunlocksmem(TCFDB *fdb) { + assert(fdb); + if (pthread_rwlock_unlock(fdb->smtx) != 0) { + tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; +} +static bool tcfdbftruncate(TCFDB *fdb, off_t length) { + return tcfdbftruncate2(fdb, length, 0); +} + +static bool tcfdbftruncate2(TCFDB *fdb, off_t length, int opts) { +#ifndef _WIN32 + length = length ? tcpagealign(length) : 0; + if (!(fdb->omode & FDBOWRITER) || (length <= fdb->fsiz && !(opts & FDBTRALLOWSHRINK))) { + return true; + } + if (length > fdb->fsiz && !(opts & FDBTRALLOWSHRINK)) { + off_t o1 = tcpagealign((_maxof(off_t) - length < FDBXFSIZINC) ? length : length + FDBXFSIZINC); + off_t o2 = tcpagealign((((uint64_t) length) * 3) >> 1); + length = MAX(o1, o2); + } + if (length > fdb->limsiz) { + length = fdb->limsiz; + } + if (ftruncate(fdb->fd, length) == 0) { + fdb->fsiz = length; + return true; + } else { + return false; + } +#else + bool err = false; + LARGE_INTEGER size; + //MSDN: Applications should test for files with a length of 0 (zero) and reject those files. + size.QuadPart = (fdb->omode & FDBOWRITER) ? tcpagealign((length == 0) ? 1 : length) : length; + if (fdb->map && + length > 0 && + (!(fdb->omode & FDBOWRITER) || (size.QuadPart <= fdb->fsiz && !(opts & FDBTRALLOWSHRINK)))) { + return true; + } + if (!(opts & FDBWRITENOLOCK) && !FDBLOCKSMEM2(fdb, true)) { + return false; + } + if ((fdb->omode & FDBOWRITER) && size.QuadPart > fdb->fsiz && !(opts & FDBTRALLOWSHRINK)) { + off_t o1 = tcpagealign((_maxof(off_t) - (off_t) size.QuadPart < FDBXFSIZINC) ? size.QuadPart : size.QuadPart + FDBXFSIZINC); + off_t o2 = tcpagealign((((uint64_t) size.QuadPart) * 3) >> 1); + size.QuadPart = MAX(o1, o2); + } + if (size.QuadPart > fdb->limsiz) { + size.QuadPart = fdb->limsiz; + } + if (fdb->map) { + FlushViewOfFile((PCVOID) fdb->map, 0); + if (!UnmapViewOfFile((LPCVOID) fdb->map) || !CloseHandle(fdb->w32hmap)) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + fdb->map = NULL; + fdb->w32hmap = INVALID_HANDLE_VALUE; + } + if (fdb->omode & FDBOWRITER) { + if (!SetFilePointerEx(fdb->fd, size, NULL, FILE_BEGIN) || !SetEndOfFile(fdb->fd)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + } + fdb->w32hmap = CreateFileMapping(fdb->fd, NULL, + ((fdb->omode & FDBOWRITER) ? PAGE_READWRITE : PAGE_READONLY), + size.HighPart, size.LowPart, NULL); + if (INVALIDHANDLE(fdb->w32hmap)) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + fdb->map = MapViewOfFile(fdb->w32hmap, + ((fdb->omode & FDBOWRITER) ? FILE_MAP_WRITE : FILE_MAP_READ), + 0, 0, 0); + if (fdb->map == NULL) { + tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + fdb->fsiz = size.QuadPart; + if (length == 0) { + size.QuadPart = 0; + if (!SetFilePointerEx(fdb->fd, size, NULL, FILE_BEGIN)) { + tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__); + err = true; + goto finish; + } + } +finish: + if (!(opts & FDBWRITENOLOCK)) FDBUNLOCKSMEM(fdb); + return !err; +#endif +} /************************************************************************************************* * debugging functions *************************************************************************************************/ - /* Print meta data of the header into the debugging output. `fdb' specifies the fixed-length database object. */ -void tcfdbprintmeta(TCFDB *fdb){ - assert(fdb); - HANDLE dbgfd = INVALIDHANDLE(fdb->dbgfd) ? GET_STDOUT_HANDLE() : fdb->dbgfd; - char buf[FDBIOBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "META:"); - wp += sprintf(wp, " mmtx=%p", (void *)fdb->mmtx); - wp += sprintf(wp, " amtx=%p", (void *)fdb->amtx); - wp += sprintf(wp, " rmtxs=%p", (void *)fdb->rmtxs); - wp += sprintf(wp, " tmtx=%p", (void *)fdb->tmtx); - wp += sprintf(wp, " wmtx=%p", (void *)fdb->wmtx); - wp += sprintf(wp, " eckey=%p", (void *)fdb->eckey); - wp += sprintf(wp, " rpath=%s", fdb->rpath ? fdb->rpath : "-"); - wp += sprintf(wp, " type=%02X", fdb->type); - wp += sprintf(wp, " flags=%02X", fdb->flags); - wp += sprintf(wp, " width=%u", fdb->width); - wp += sprintf(wp, " limsiz=%" PRIuMAX "", (unsigned long long)fdb->limsiz); - wp += sprintf(wp, " wsiz=%u", fdb->wsiz); - wp += sprintf(wp, " rsiz=%u", fdb->rsiz); - wp += sprintf(wp, " limid=%" PRIuMAX "", (unsigned long long)fdb->limid); - wp += sprintf(wp, " path=%s", fdb->path ? fdb->path : "-"); - wp += sprintf(wp, " fd=%d", fdb->fd); - wp += sprintf(wp, " omode=%u", fdb->omode); - wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long)fdb->rnum); - wp += sprintf(wp, " fsiz=%" PRIuMAX "", (unsigned long long)fdb->fsiz); - wp += sprintf(wp, " min=%" PRIuMAX "", (unsigned long long)fdb->min); - wp += sprintf(wp, " max=%" PRIuMAX "", (unsigned long long)fdb->max); - wp += sprintf(wp, " iter=%" PRIuMAX "", (unsigned long long)fdb->iter); - wp += sprintf(wp, " map=%p", (void *)fdb->map); - wp += sprintf(wp, " array=%p", (void *)fdb->array); - wp += sprintf(wp, " ecode=%d", fdb->ecode); - wp += sprintf(wp, " fatal=%u", fdb->fatal); - wp += sprintf(wp, " inode=%" PRIuMAX "", (unsigned long long)fdb->inode); - wp += sprintf(wp, " mtime=%" PRIuMAX "", (unsigned long long)fdb->mtime); - wp += sprintf(wp, " tran=%d", fdb->tran); - wp += sprintf(wp, " walfd=%d", fdb->walfd); - wp += sprintf(wp, " walend=%" PRIuMAX "", (unsigned long long)fdb->walend); - wp += sprintf(wp, " dbgfd=%d", fdb->dbgfd); - wp += sprintf(wp, " cnt_writerec=%" PRIdMAX "", (long long)fdb->cnt_writerec); - wp += sprintf(wp, " cnt_readrec=%" PRIdMAX "", (long long)fdb->cnt_readrec); - wp += sprintf(wp, " cnt_truncfile=%" PRIdMAX "", (long long)fdb->cnt_truncfile); - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); +void tcfdbprintmeta(TCFDB *fdb) { + assert(fdb); + HANDLE dbgfd = INVALIDHANDLE(fdb->dbgfd) ? GET_STDOUT_HANDLE() : fdb->dbgfd; + char buf[FDBIOBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "META:"); + wp += sprintf(wp, " mmtx=%p", (void *) fdb->mmtx); + wp += sprintf(wp, " amtx=%p", (void *) fdb->amtx); + wp += sprintf(wp, " rmtxs=%p", (void *) fdb->rmtxs); + wp += sprintf(wp, " tmtx=%p", (void *) fdb->tmtx); + wp += sprintf(wp, " wmtx=%p", (void *) fdb->wmtx); + wp += sprintf(wp, " smtx=%p", (void *) fdb->smtx); + wp += sprintf(wp, " eckey=%p", (void *) fdb->eckey); + wp += sprintf(wp, " rpath=%s", fdb->rpath ? fdb->rpath : "-"); + wp += sprintf(wp, " type=%02X", fdb->type); + wp += sprintf(wp, " flags=%02X", fdb->flags); + wp += sprintf(wp, " width=%u", fdb->width); + wp += sprintf(wp, " limsiz=%" PRIuMAX "", (unsigned long long) fdb->limsiz); + wp += sprintf(wp, " wsiz=%u", fdb->wsiz); + wp += sprintf(wp, " rsiz=%u", fdb->rsiz); + wp += sprintf(wp, " limid=%" PRIuMAX "", (unsigned long long) fdb->limid); + wp += sprintf(wp, " path=%s", fdb->path ? fdb->path : "-"); + wp += sprintf(wp, " fd=%d", fdb->fd); + wp += sprintf(wp, " omode=%u", fdb->omode); + wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long) fdb->rnum); + wp += sprintf(wp, " fsiz=%" PRIuMAX "", (unsigned long long) fdb->fsiz); + wp += sprintf(wp, " min=%" PRIuMAX "", (unsigned long long) fdb->min); + wp += sprintf(wp, " max=%" PRIuMAX "", (unsigned long long) fdb->max); + wp += sprintf(wp, " iter=%" PRIuMAX "", (unsigned long long) fdb->iter); + wp += sprintf(wp, " map=%p", (void *) fdb->map); + wp += sprintf(wp, " ecode=%d", fdb->ecode); + wp += sprintf(wp, " fatal=%u", fdb->fatal); + wp += sprintf(wp, " inode=%" PRIuMAX "", (unsigned long long) fdb->inode); + wp += sprintf(wp, " mtime=%" PRIuMAX "", (unsigned long long) fdb->mtime); + wp += sprintf(wp, " tran=%d", fdb->tran); + wp += sprintf(wp, " walfd=%d", fdb->walfd); + wp += sprintf(wp, " walend=%" PRIuMAX "", (unsigned long long) fdb->walend); + wp += sprintf(wp, " dbgfd=%d", fdb->dbgfd); +#ifndef NDEBUG + wp += sprintf(wp, " cnt_writerec=%" PRIdMAX "", (long long) fdb->cnt_writerec); + wp += sprintf(wp, " cnt_readrec=%" PRIdMAX "", (long long) fdb->cnt_readrec); + wp += sprintf(wp, " cnt_truncfile=%" PRIdMAX "", (long long) fdb->cnt_truncfile); +#endif + *(wp++) = '\n'; + tcwrite(dbgfd, buf, wp - buf); } diff --git a/tcejdb/tcfdb.h b/tcejdb/tcfdb.h index 2747d04..a53383a 100644 --- a/tcejdb/tcfdb.h +++ b/tcejdb/tcfdb.h @@ -24,6 +24,7 @@ #define __TCFDB_CLINKAGEBEGIN #define __TCFDB_CLINKAGEEND #endif + __TCFDB_CLINKAGEBEGIN @@ -36,67 +37,70 @@ __TCFDB_CLINKAGEBEGIN *************************************************************************************************/ -typedef struct { /* type of structure for a fixed-length database */ - void *mmtx; /* mutex for method */ - void *amtx; /* mutex for attribute */ - void *rmtxs; /* mutexes for records */ - void *tmtx; /* mutex for transaction */ - void *wmtx; /* mutex for write ahead logging */ - void *eckey; /* key for thread specific error code */ - char *rpath; /* real path for locking */ - uint8_t type; /* database type */ - uint8_t flags; /* additional flags */ - uint32_t width; /* width of the value of each record */ - uint64_t limsiz; /* limit size of the file */ - int wsiz; /* size of the width region */ - int rsiz; /* size of each record */ - uint64_t limid; /* limit ID number */ - char *path; /* path of the database file */ - HANDLE fd; /* file descriptor of the database file */ - uint32_t omode; /* open mode */ - uint64_t rnum; /* number of the records */ - uint64_t fsiz; /* size of the database file */ - uint64_t min; /* minimum ID number */ - uint64_t max; /* maximum ID number */ - uint64_t iter; /* ID number of the iterator */ - char *map; /* pointer to the mapped memory */ - unsigned char *array; /* pointer to the array region */ - volatile int ecode; /* last happened error code */ - bool fatal; /* whether a fatal error occured */ - uint64_t inode; /* inode number */ - time_t mtime; /* modification time */ - bool tran; /* whether in the transaction */ - HANDLE walfd; /* file descriptor of write ahead logging */ - uint64_t walend; /* end offset of write ahead logging */ - HANDLE dbgfd; /* file descriptor for debugging */ - int64_t cnt_writerec; /* tesing counter for record write times */ - int64_t cnt_readrec; /* tesing counter for record read times */ - int64_t cnt_truncfile; /* tesing counter for file truncate times */ +typedef struct { /* type of structure for a fixed-length database */ + bool fatal; /* whether a fatal error occured */ + bool tran; /* whether in the transaction */ + uint8_t type; /* database type */ + uint8_t flags; /* additional flags */ + void *mmtx; /* mutex for method */ + void *smtx; /* rw lock for shared memory */ + void *amtx; /* mutex for attribute */ + void *rmtxs; /* mutexes for records */ + void *tmtx; /* mutex for transaction */ + void *wmtx; /* mutex for write ahead logging */ + void *eckey; /* key for thread specific error code */ + char *path; /* path of the database file */ + char *rpath; /* real path for locking */ + volatile char *map; /* pointer to the mapped memory */ + volatile int ecode; /* last happened error code */ + int wsiz; /* size of the width region */ + int rsiz; /* size of each record */ + uint32_t width; /* width of the value of each record */ + uint32_t omode; /* open mode */ + HANDLE fd; /* file descriptor of the database file */ + HANDLE walfd; /* file descriptor of write ahead logging */ + HANDLE dbgfd; /* file descriptor for debugging */ #ifdef _WIN32 - volatile HANDLE fileMapping; /* win32 file mappings for mmap */ + HANDLE w32hmap; /* win32 file mappings for mmap */ +#endif + time_t mtime; /* modification time */ + uint64_t limsiz; /* limit size of the file */ + uint64_t rnum; /* number of the records */ + uint64_t fsiz; /* size of the database file */ + uint64_t min; /* minimum ID number */ + uint64_t max; /* maximum ID number */ + uint64_t iter; /* ID number of the iterator */ + uint64_t inode; /* inode number */ + uint64_t walend; /* end offset of write ahead logging */ + uint64_t limid; /* limit ID number */ + +#ifndef NDEBUG + int64_t cnt_writerec; /* tesing counter for record write times */ + int64_t cnt_readrec; /* tesing counter for record read times */ + int64_t cnt_truncfile; /* tesing counter for file truncate times */ #endif } TCFDB; -enum { /* enumeration for additional flags */ - FDBFOPEN = 1 << 0, /* whether opened */ - FDBFFATAL = 1 << 1 /* whether with fatal error */ +enum { /* enumeration for additional flags */ + FDBFOPEN = 1 << 0, /* whether opened */ + FDBFFATAL = 1 << 1 /* whether with fatal error */ }; -enum { /* enumeration for open modes */ - FDBOREADER = 1 << 0, /* open as a reader */ - FDBOWRITER = 1 << 1, /* open as a writer */ - FDBOCREAT = 1 << 2, /* writer creating */ - FDBOTRUNC = 1 << 3, /* writer truncating */ - FDBONOLCK = 1 << 4, /* open without locking */ - FDBOLCKNB = 1 << 5, /* lock without blocking */ - FDBOTSYNC = 1 << 6 /* synchronize every transaction */ +enum { /* enumeration for open modes */ + FDBOREADER = 1 << 0, /* open as a reader */ + FDBOWRITER = 1 << 1, /* open as a writer */ + FDBOCREAT = 1 << 2, /* writer creating */ + FDBOTRUNC = 1 << 3, /* writer truncating */ + FDBONOLCK = 1 << 4, /* open without locking */ + FDBOLCKNB = 1 << 5, /* lock without blocking */ + FDBOTSYNC = 1 << 6 /* synchronize every transaction */ }; -enum { /* enumeration for ID constants */ - FDBIDMIN = -1, /* minimum number */ - FDBIDPREV = -2, /* less by one than the minimum */ - FDBIDMAX = -3, /* maximum number */ - FDBIDNEXT = -4 /* greater by one than the miximum */ +enum { /* enumeration for ID constants */ + FDBIDMIN = -1, /* minimum number */ + FDBIDPREV = -2, /* less by one than the minimum */ + FDBIDMAX = -3, /* maximum number */ + FDBIDNEXT = -4 /* greater by one than the miximum */ }; @@ -766,12 +770,25 @@ uint8_t tcfdbtype(TCFDB *fdb); The return value is the additional flags. */ uint8_t tcfdbflags(TCFDB *fdb); - -/* Get the pointer to the opaque field of a fixed-length database object. - `fdb' specifies the fixed-length database object. - The return value is the pointer to the opaque field whose size is 128 bytes. */ -char *tcfdbopaque(TCFDB *fdb); - +/** + * Get opaque data into specified buffer `dst` + * `bsiz` Max size to be read. + * Return -1 if error, otherwise number of bytes writen in dst. + */ +int tcfdbreadopaque(TCFDB *fdb, void *dst, int off, int bsiz); + +/** + * Write opaque data. + * Number of bytes specified bt `nb` + * can be truncated if it greater than max opaque data size. + * Return -1 if error, otherwise number of bytes read from src. + */ +int tcfdbwriteopaque(TCFDB *fdb, const void *src, int off, int nb); + +/** + * Copy opaque data between databases + */ +bool tcfdbcopyopaque(TCFDB *dst, TCFDB *src, int off, int nb); /* Store a record into a fixed-length database object with a duplication handler. `fdb' specifies the fixed-length database object connected as a writer. diff --git a/tcejdb/tcfmttest.c b/tcejdb/tcfmttest.c index 2202031..9ea2509 100644 --- a/tcejdb/tcfmttest.c +++ b/tcejdb/tcfmttest.c @@ -182,15 +182,18 @@ static void eprint(TCFDB *fdb, int line, const char *func){ /* print members of fixed-length database */ static void mprint(TCFDB *fdb){ - if(fdb->cnt_writerec < 0) return; iprintf("minimum ID number: %" PRIuMAX "\n", (unsigned long long)tcfdbmin(fdb)); iprintf("maximum ID number: %" PRIuMAX "\n", (unsigned long long)tcfdbmax(fdb)); iprintf("width of the value: %u\n", (unsigned int)tcfdbwidth(fdb)); iprintf("limit file size: %" PRIuMAX "\n", (unsigned long long)tcfdblimsiz(fdb)); iprintf("limit ID number: %" PRIuMAX "\n", (unsigned long long)tcfdblimid(fdb)); + +#ifndef NDEBUG + if(fdb->cnt_writerec < 0) return; iprintf("cnt_writerec: %" PRIdMAX "\n", (long long)fdb->cnt_writerec); iprintf("cnt_readrec: %" PRIdMAX "\n", (long long)fdb->cnt_readrec); iprintf("cnt_truncfile: %" PRIdMAX "\n", (long long)fdb->cnt_truncfile); +#endif } diff --git a/tcejdb/tcftest.c b/tcejdb/tcftest.c index b239b80..9fd0f5e 100644 --- a/tcejdb/tcftest.c +++ b/tcejdb/tcftest.c @@ -180,15 +180,17 @@ static void eprint(TCFDB *fdb, int line, const char *func){ /* print members of fixed-length database */ static void mprint(TCFDB *fdb){ - if(fdb->cnt_writerec < 0) return; iprintf("minimum ID number: %" PRIuMAX "\n", (unsigned long long)tcfdbmin(fdb)); iprintf("maximum ID number: %" PRIuMAX "\n", (unsigned long long)tcfdbmax(fdb)); iprintf("width of the value: %u\n", (unsigned int)tcfdbwidth(fdb)); iprintf("limit file size: %" PRIuMAX "\n", (unsigned long long)tcfdblimsiz(fdb)); iprintf("limit ID number: %" PRIuMAX "\n", (unsigned long long)tcfdblimid(fdb)); +#ifndef NDEBUG + if(fdb->cnt_writerec < 0) return; iprintf("cnt_writerec: %" PRIdMAX "\n", (long long)fdb->cnt_writerec); iprintf("cnt_readrec: %" PRIdMAX "\n", (long long)fdb->cnt_readrec); iprintf("cnt_truncfile: %" PRIdMAX "\n", (long long)fdb->cnt_truncfile); +#endif } diff --git a/tcejdb/tchdb.c b/tcejdb/tchdb.c index 070f386..db7024a 100644 --- a/tcejdb/tchdb.c +++ b/tcejdb/tchdb.c @@ -35,8 +35,8 @@ #define HDBFRECOFF 64 // offset of the region for the first record offset #define HDBOPAQUEOFF 128 // offset of the region for the opaque field #define HDBOPAQUESZ HDBHEADSIZ - HDBOPAQUEOFF //opaque data size -#define HDBB64(TC_hdb) ((uint64_t *) ((char *)((TC_hdb)->map) + HDBHEADSIZ)) -#define HDBB32(TC_hdb) ((uint32_t *) ((char *)((TC_hdb)->map) + HDBHEADSIZ)) +#define HDBB64(TC_hdb) ((uint64_t *) ((TC_hdb)->map + HDBHEADSIZ)) +#define HDBB32(TC_hdb) ((uint32_t *) ((TC_hdb)->map + HDBHEADSIZ)) #define HDBDEFBNUM 131071 // default bucket number #define HDBDEFAPOW 4 // default alignment power @@ -63,51 +63,50 @@ #define HDBCACHEOUT 128 // number of records in a process of cacheout #define HDBWALSUFFIX "wal" // suffix of write ahead logging file -typedef struct { // type of structure for a record - uint64_t off; // offset of the record - uint32_t rsiz; // size of the whole record - uint8_t magic; // magic number - uint8_t hash; // second hash value - uint64_t left; // offset of the left child record - uint64_t right; // offset of the right child record - uint32_t ksiz; // size of the key - uint32_t vsiz; // size of the value - uint16_t psiz; // size of the padding - const char *kbuf; // pointer to the key - const char *vbuf; // pointer to the value - uint64_t boff; // offset of the body - char *bbuf; // buffer of the body +typedef struct { // type of structure for a record + uint64_t off; // offset of the record + uint32_t rsiz; // size of the whole record + uint8_t magic; // magic number + uint8_t hash; // second hash value + uint64_t left; // offset of the left child record + uint64_t right; // offset of the right child record + uint32_t ksiz; // size of the key + uint32_t vsiz; // size of the value + uint16_t psiz; // size of the padding + const char *kbuf; // pointer to the key + const char *vbuf; // pointer to the value + uint64_t boff; // offset of the body + char *bbuf; // buffer of the body } TCHREC; -typedef struct { // type of structure for a free block - uint64_t off; // offset of the block - uint32_t rsiz; // size of the block +typedef struct { // type of structure for a free block + uint64_t off; // offset of the block + uint32_t rsiz; // size of the block } HDBFB; -enum { // enumeration for magic data - HDBMAGICREC = 0xc8, // for data block - HDBMAGICFB = 0xb0 // for free block +enum { // enumeration for magic data + HDBMAGICREC = 0xc8, // for data block + HDBMAGICFB = 0xb0 // for free block }; -enum { // enumeration for duplication behavior - HDBPDOVER, // overwrite an existing value - HDBPDKEEP, // keep the existing value - HDBPDCAT, // concatenate values - HDBPDADDINT, // add an integer - HDBPDADDDBL, // add a real number - HDBPDPROC // process by a callback function +enum { // enumeration for duplication behavior + HDBPDOVER, // overwrite an existing value + HDBPDKEEP, // keep the existing value + HDBPDCAT, // concatenate values + HDBPDADDINT, // add an integer + HDBPDADDDBL, // add a real number + HDBPDPROC // process by a callback function }; -typedef struct { // type of structure for a duplication callback - TCPDPROC proc; // function pointer - void *op; // opaque pointer +typedef struct { // type of structure for a duplication callback + TCPDPROC proc; // function pointer + void *op; // opaque pointer } HDBPDPROCOP; - enum { - HDBWRITENOWALL = 1, //do not write into wall in tchdbseekwrite - HDBWRITENOLOCK = 1 << 1, //do not use shared write lock in tchdbseekwrite & tchdbftruncate - HDBTRUNCSHRINKFILE = 1 << 2 //resize file on truncation + HDBWRITENOWALL = 1, //do not write into wall in tchdbseekwrite + HDBWRITENOLOCK = 1 << 1, //do not use shared write lock in tchdbseekwrite & tchdbftruncate + HDBTRALLOWSHRINK = 1 << 2 //resize file on truncation }; /* private macros */ @@ -127,12 +126,12 @@ enum { ((TC_hdb)->mmtx ? tchdblockdb(TC_hdb) : true) #define HDBUNLOCKDB(TC_hdb) \ ((TC_hdb)->mmtx ? tchdbunlockdb(TC_hdb) : true) - #define HDBLOCKSMEM(TC_hdb, TC_wr) \ - ((TC_hdb)->smtx ? tchdblocksmem((TC_hdb), (TC_wr)) : true) + ((TC_hdb)->smtx ? tchdblocksmem((TC_hdb), (TC_wr)) : ((TC_hdb)->map != NULL)) +#define HDBLOCKSMEM2(TC_hdb, TC_wr) \ + ((TC_hdb)->smtx ? tchdblocksmem2((TC_hdb), (TC_wr)) : true) #define HDBUNLOCKSMEM(TC_hdb) \ ((TC_hdb)->smtx ? tchdbunlocksmem(TC_hdb) : true) - #define HDBLOCKWAL(TC_hdb) \ ((TC_hdb)->mmtx ? tchdblockwal(TC_hdb) : true) #define HDBUNLOCKWAL(TC_hdb) \ @@ -180,20 +179,20 @@ static bool tchdbwalremove(TCHDB *hdb, const char *path); static bool tchdbopenimpl(TCHDB *hdb, const char *path, int omode); static bool tchdbcloseimpl(TCHDB *hdb); static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - const char *vbuf, int vsiz, int dmode); + const char *vbuf, int vsiz, int dmode); static void tchdbdrpappend(TCHDB *hdb, const char *kbuf, int ksiz, const char *vbuf, int vsiz, - uint8_t hash); + uint8_t hash); static bool tchdbputasyncimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, - uint8_t hash, const char *vbuf, int vsiz); + uint8_t hash, const char *vbuf, int vsiz); static bool tchdboutimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash); static char *tchdbgetimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - int *sp); + int *sp); static int tchdbgetintobuf(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - char *vbuf, int max); + char *vbuf, int max); static int tchdbgetintoxstrimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - TCXSTR *xstr); + TCXSTR *xstr); static char *tchdbgetnextimpl(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, - const char **vbp, int *vsp); + const char **vbp, int *vsp); static int tchdbvsizimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash); static bool tchdbiterinitimpl(TCHDB *hdb); static char *tchdbiternextimpl(TCHDB *hdb, int *sp); @@ -211,6 +210,7 @@ static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts); EJDB_INLINE bool tchdblockmethod(TCHDB *hdb, bool wr); EJDB_INLINE bool tchdbunlockmethod(TCHDB *hdb); EJDB_INLINE bool tchdblocksmem(TCHDB *hdb, bool wr); +EJDB_INLINE bool tchdblocksmem2(TCHDB *hdb, bool wr); EJDB_INLINE bool tchdbunlocksmem(TCHDB *hdb); EJDB_INLINE bool tchdblockrecord(TCHDB *hdb, uint8_t bidx, bool wr); EJDB_INLINE bool tchdbunlockrecord(TCHDB *hdb, uint8_t bidx); @@ -231,516 +231,494 @@ void tchdbprintrec(TCHDB *hdb, TCHREC *rec); * API *************************************************************************************************/ - /* Get the message string corresponding to an error code. */ -const char *tchdberrmsg(int ecode){ - return tcerrmsg(ecode); +const char *tchdberrmsg(int ecode) { + return tcerrmsg(ecode); } - /* Create a hash database object. */ -TCHDB *tchdbnew(void){ - TCHDB *hdb; - TCMALLOC(hdb, sizeof(*hdb)); - tchdbclear(hdb); - return hdb; +TCHDB *tchdbnew(void) { + TCHDB *hdb; + TCMALLOC(hdb, sizeof (*hdb)); + tchdbclear(hdb); + return hdb; } - /* Delete a hash database object. */ -void tchdbdel(TCHDB *hdb){ - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)) tchdbclose(hdb); - if(hdb->mmtx){ - pthread_mutex_destroy(hdb->wmtx); - pthread_mutex_destroy(hdb->dmtx); - for(int i = UINT8_MAX; i >= 0; i--){ - pthread_rwlock_destroy((pthread_rwlock_t *)hdb->rmtxs + i); - } - pthread_rwlock_destroy(hdb->mmtx); - pthread_rwlock_destroy(hdb->smtx); - TCFREE(hdb->wmtx); - TCFREE(hdb->dmtx); - TCFREE(hdb->smtx); - TCFREE(hdb->rmtxs); - TCFREE(hdb->mmtx); - } - if (hdb->eckey) { - pthread_key_delete(*(pthread_key_t *)hdb->eckey); - TCFREE(hdb->eckey); - } - TCFREE(hdb); +void tchdbdel(TCHDB *hdb) { + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) tchdbclose(hdb); + if (hdb->mmtx) { + pthread_mutex_destroy(hdb->wmtx); + pthread_mutex_destroy(hdb->dmtx); + for (int i = UINT8_MAX; i >= 0; i--) { + pthread_rwlock_destroy((pthread_rwlock_t *) hdb->rmtxs + i); + } + pthread_rwlock_destroy(hdb->mmtx); + pthread_rwlock_destroy(hdb->smtx); + TCFREE(hdb->wmtx); + TCFREE(hdb->dmtx); + TCFREE(hdb->smtx); + TCFREE(hdb->rmtxs); + TCFREE(hdb->mmtx); + } + if (hdb->eckey) { + pthread_key_delete(*(pthread_key_t *) hdb->eckey); + TCFREE(hdb->eckey); + } + TCFREE(hdb); } - /* Get the last happened error code of a hash database object. */ -int tchdbecode(TCHDB *hdb){ - assert(hdb); - return (hdb->eckey) ? (int)(intptr_t)pthread_getspecific(*(pthread_key_t *)hdb->eckey) : hdb->ecode; +int tchdbecode(TCHDB *hdb) { + assert(hdb); + return (hdb->eckey) ? (int) (intptr_t) pthread_getspecific(*(pthread_key_t *) hdb->eckey) : hdb->ecode; } - /* Set mutual exclusion control of a hash database object for threading. */ -bool tchdbsetmutex(TCHDB *hdb){ - assert(hdb); - if(hdb->mmtx || !INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - pthread_mutexattr_t rma; - pthread_mutexattr_init(&rma); - TCMALLOC(hdb->mmtx, sizeof(pthread_rwlock_t)); - TCMALLOC(hdb->smtx, sizeof(pthread_rwlock_t)); - TCMALLOC(hdb->rmtxs, (UINT8_MAX + 1) * sizeof(pthread_rwlock_t)); - TCMALLOC(hdb->dmtx, sizeof(pthread_mutex_t)); - TCMALLOC(hdb->wmtx, sizeof(pthread_mutex_t)); - bool err = false; - if(pthread_mutexattr_settype(&rma, PTHREAD_MUTEX_RECURSIVE) != 0) err = true; - if(pthread_rwlock_init(hdb->smtx, NULL) != 0) err = true; - if(pthread_rwlock_init(hdb->mmtx, NULL) != 0) err = true; - for(int i = 0; i <= UINT8_MAX; i++){ - if(pthread_rwlock_init((pthread_rwlock_t *)hdb->rmtxs + i, NULL) != 0) err = true; - } - if(pthread_mutex_init(hdb->dmtx, &rma) != 0) err = true; - if(pthread_mutex_init(hdb->wmtx, NULL) != 0) err = true; - if(err){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); +bool tchdbsetmutex(TCHDB *hdb) { + assert(hdb); + if (hdb->mmtx || !INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + pthread_mutexattr_t rma; + pthread_mutexattr_init(&rma); + TCMALLOC(hdb->mmtx, sizeof (pthread_rwlock_t)); + TCMALLOC(hdb->smtx, sizeof (pthread_rwlock_t)); + TCMALLOC(hdb->rmtxs, (UINT8_MAX + 1) * sizeof (pthread_rwlock_t)); + TCMALLOC(hdb->dmtx, sizeof (pthread_mutex_t)); + TCMALLOC(hdb->wmtx, sizeof (pthread_mutex_t)); + bool err = false; + if (pthread_mutexattr_settype(&rma, PTHREAD_MUTEX_RECURSIVE) != 0) err = true; + if (pthread_rwlock_init(hdb->smtx, NULL) != 0) err = true; + if (pthread_rwlock_init(hdb->mmtx, NULL) != 0) err = true; + for (int i = 0; i <= UINT8_MAX; i++) { + if (pthread_rwlock_init((pthread_rwlock_t *) hdb->rmtxs + i, NULL) != 0) err = true; + } + if (pthread_mutex_init(hdb->dmtx, &rma) != 0) err = true; + if (pthread_mutex_init(hdb->wmtx, NULL) != 0) err = true; + if (err) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + pthread_mutexattr_destroy(&rma); + TCFREE(hdb->wmtx); + TCFREE(hdb->dmtx); + TCFREE(hdb->rmtxs); + TCFREE(hdb->smtx); + TCFREE(hdb->mmtx); + hdb->wmtx = NULL; + hdb->dmtx = NULL; + hdb->rmtxs = NULL; + hdb->smtx = NULL; + hdb->mmtx = NULL; + return false; + } pthread_mutexattr_destroy(&rma); - TCFREE(hdb->wmtx); - TCFREE(hdb->dmtx); - TCFREE(hdb->rmtxs); - TCFREE(hdb->smtx); - TCFREE(hdb->mmtx); - hdb->wmtx = NULL; - hdb->dmtx = NULL; - hdb->rmtxs = NULL; - hdb->smtx = NULL; - hdb->mmtx = NULL; - return false; - } - pthread_mutexattr_destroy(&rma); - return true; + return true; } - /* Set the tuning parameters of a hash database object. */ -bool tchdbtune(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - hdb->bnum = (bnum > 0) ? tcgetprime(bnum) : HDBDEFBNUM; - hdb->apow = (apow >= 0) ? tclmin(apow, HDBMAXAPOW) : HDBDEFAPOW; - hdb->fpow = (fpow >= 0) ? tclmin(fpow, HDBMAXFPOW) : HDBDEFFPOW; - hdb->opts = opts; - if(!_tc_deflate) hdb->opts &= ~HDBTDEFLATE; - if(!_tc_bzcompress) hdb->opts &= ~HDBTBZIP; - return true; +bool tchdbtune(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + hdb->bnum = (bnum > 0) ? tcgetprime(bnum) : HDBDEFBNUM; + hdb->apow = (apow >= 0) ? tclmin(apow, HDBMAXAPOW) : HDBDEFAPOW; + hdb->fpow = (fpow >= 0) ? tclmin(fpow, HDBMAXFPOW) : HDBDEFFPOW; + hdb->opts = opts; + if (!_tc_deflate) hdb->opts &= ~HDBTDEFLATE; + if (!_tc_bzcompress) hdb->opts &= ~HDBTBZIP; + return true; } - /* Set the caching parameters of a hash database object. */ -bool tchdbsetcache(TCHDB *hdb, int32_t rcnum){ - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - hdb->rcnum = (rcnum > 0) ? tclmin(tclmax(rcnum, HDBCACHEOUT * 2), INT_MAX / 4) : 0; - return true; +bool tchdbsetcache(TCHDB *hdb, int32_t rcnum) { + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + hdb->rcnum = (rcnum > 0) ? tclmin(tclmax(rcnum, HDBCACHEOUT * 2), INT_MAX / 4) : 0; + return true; } - /* Set the size of the extra mapped memory of a hash database object. */ -bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz){ +bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz) { #ifdef _WIN32 - fprintf(stderr, "\ntchdbsetxmsiz does not takes effect on windows platform\n"); - return true; + fprintf(stderr, "\ntchdbsetxmsiz does not takes effect on windows platform\n"); + return true; #else - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - hdb->xmsiz = (xmsiz > 0) ? tcpagealign(xmsiz) : 0; - return true; + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + hdb->xmsiz = (xmsiz > 0) ? tcpagealign(xmsiz) : 0; + return true; #endif } - /* Set the unit step number of auto defragmentation of a hash database object. */ -bool tchdbsetdfunit(TCHDB *hdb, int32_t dfunit){ - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - hdb->dfunit = (dfunit > 0) ? dfunit : 0; - return true; +bool tchdbsetdfunit(TCHDB *hdb, int32_t dfunit) { + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; + } + hdb->dfunit = (dfunit > 0) ? dfunit : 0; + return true; } - /* Open a database file and connect a hash database object. */ -bool tchdbopen(TCHDB *hdb, const char *path, int omode){ - assert(hdb && path); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if (!hdb->eckey) { - TCMALLOC(hdb->eckey, sizeof(pthread_key_t)); - if(pthread_key_create(hdb->eckey, NULL)) { - TCFREE(hdb->eckey); - hdb->eckey = NULL; - HDBUNLOCKMETHOD(hdb); - return false; - } - } - char *rpath = tcrealpath(path); - if(!rpath){ - tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!tcpathlock(rpath)){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - TCFREE(rpath); +bool tchdbopen(TCHDB *hdb, const char *path, int omode) { + assert(hdb && path); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!hdb->eckey) { + TCMALLOC(hdb->eckey, sizeof (pthread_key_t)); + if (pthread_key_create(hdb->eckey, NULL)) { + TCFREE(hdb->eckey); + hdb->eckey = NULL; + HDBUNLOCKMETHOD(hdb); + return false; + } + } + char *rpath = tcrealpath(path); + if (!rpath) { + tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!tcpathlock(rpath)) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + TCFREE(rpath); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbopenimpl(hdb, path, omode); + if (rv) { + hdb->rpath = rpath; + } else { + tcpathunlock(rpath); + TCFREE(rpath); + } HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbopenimpl(hdb, path, omode); - if(rv){ - hdb->rpath = rpath; - } else { - tcpathunlock(rpath); - TCFREE(rpath); - } - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Close a database object. */ -bool tchdbclose(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbclose(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbcloseimpl(hdb); + tcpathunlock(hdb->rpath); + TCFREE(hdb->rpath); + hdb->rpath = NULL; HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbcloseimpl(hdb); - tcpathunlock(hdb->rpath); - TCFREE(hdb->rpath); - hdb->rpath = NULL; - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Store a record into a hash database object. */ -bool tchdbput(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->zmode){ - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(vbuf, vsiz, &vsiz); - } else { - zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); +bool tchdbput(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return false; + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->zmode) { + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(vbuf, vsiz, &vsiz); + } else { + zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv; } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); - TCFREE(zbuf); + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDOVER); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDOVER); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv; } - /* Store a string record into a hash database object. */ -bool tchdbput2(TCHDB *hdb, const char *kstr, const char *vstr){ - assert(hdb && kstr && vstr); - return tchdbput(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tchdbput2(TCHDB *hdb, const char *kstr, const char *vstr) { + assert(hdb && kstr && vstr); + return tchdbput(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Store a new record into a hash database object. */ -bool tchdbputkeep(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->zmode){ - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(vbuf, vsiz, &vsiz); - } else { - zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); +bool tchdbputkeep(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return false; } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return false; + if (hdb->zmode) { + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(vbuf, vsiz, &vsiz); + } else { + zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDKEEP); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv; } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDKEEP); - TCFREE(zbuf); + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDKEEP); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDKEEP); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv; } - /* Store a new string record into a hash database object. */ -bool tchdbputkeep2(TCHDB *hdb, const char *kstr, const char *vstr){ - return tchdbputkeep(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tchdbputkeep2(TCHDB *hdb, const char *kstr, const char *vstr) { + return tchdbputkeep(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Concatenate a value at the end of the existing record in a hash database object. */ -bool tchdbputcat(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->zmode){ - char *zbuf; - int osiz; - char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); - if(obuf){ - TCREALLOC(obuf, obuf, osiz + vsiz + 1); - memcpy(obuf + osiz, vbuf, vsiz); - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(obuf, osiz + vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(obuf, osiz + vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(obuf, osiz + vsiz, &vsiz); - } else { - zbuf = hdb->enc(obuf, osiz + vsiz, &vsiz, hdb->encop); - } - TCFREE(obuf); - } else { - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(vbuf, vsiz, &vsiz); - } else { - zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); - } - } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); - TCFREE(zbuf); +bool tchdbputcat(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->zmode) { + char *zbuf; + int osiz; + char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); + if (obuf) { + TCREALLOC(obuf, obuf, osiz + vsiz + 1); + memcpy(obuf + osiz, vbuf, vsiz); + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(obuf, osiz + vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(obuf, osiz + vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(obuf, osiz + vsiz, &vsiz); + } else { + zbuf = hdb->enc(obuf, osiz + vsiz, &vsiz, hdb->encop); + } + TCFREE(obuf); + } else { + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(vbuf, vsiz, &vsiz); + } else { + zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); + } + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDCAT); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDCAT); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv; } - /* Concatenate a string value at the end of the existing record in a hash database object. */ -bool tchdbputcat2(TCHDB *hdb, const char *kstr, const char *vstr){ - assert(hdb && kstr && vstr); - return tchdbputcat(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tchdbputcat2(TCHDB *hdb, const char *kstr, const char *vstr) { + assert(hdb && kstr && vstr); + return tchdbputcat(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Store a record into a hash database object in asynchronous fashion. */ -bool tchdbputasync(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(!HDBLOCKMETHOD(hdb, true)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - hdb->async = true; - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->zmode){ - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(vbuf, vsiz, &vsiz); - } else { - zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); +bool tchdbputasync(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (!HDBLOCKMETHOD(hdb, true)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + hdb->async = true; + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; + if (hdb->zmode) { + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(vbuf, vsiz, &vsiz); + } else { + zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbputasyncimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz); + TCFREE(zbuf); + HDBUNLOCKMETHOD(hdb); + return rv; } - bool rv = tchdbputasyncimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz); - TCFREE(zbuf); + bool rv = tchdbputasyncimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz); HDBUNLOCKMETHOD(hdb); return rv; - } - bool rv = tchdbputasyncimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz); - HDBUNLOCKMETHOD(hdb); - return rv; } - /* Store a string record into a hash database object in asynchronous fashion. */ -bool tchdbputasync2(TCHDB *hdb, const char *kstr, const char *vstr){ - assert(hdb && kstr && vstr); - return tchdbputasync(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); +bool tchdbputasync2(TCHDB *hdb, const char *kstr, const char *vstr) { + assert(hdb && kstr && vstr); + return tchdbputasync(hdb, kstr, strlen(kstr), vstr, strlen(vstr)); } - /* Remove a record of a hash database object. */ -bool tchdbout(TCHDB *hdb, const void *kbuf, int ksiz){ - assert(hdb && kbuf && ksiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ +bool tchdbout(TCHDB *hdb, const void *kbuf, int ksiz) { + assert(hdb && kbuf && ksiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdboutimpl(hdb, kbuf, ksiz, bidx, hash); + HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdboutimpl(hdb, kbuf, ksiz, bidx, hash); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv; } - /* Remove a string record of a hash database object. */ -bool tchdbout2(TCHDB *hdb, const char *kstr){ - assert(hdb && kstr); - return tchdbout(hdb, kstr, strlen(kstr)); +bool tchdbout2(TCHDB *hdb, const char *kstr) { + assert(hdb && kstr); + return tchdbout(hdb, kstr, strlen(kstr)); } - /* Retrieve a record in a hash database object. */ -void *tchdbget(TCHDB *hdb, const void *kbuf, int ksiz, int *sp){ - assert(hdb && kbuf && ksiz >= 0 && sp); - if(!HDBLOCKMETHOD(hdb, false)) return NULL; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return NULL; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return NULL; - } - if(!HDBLOCKRECORD(hdb, bidx, false)){ +void *tchdbget(TCHDB *hdb, const void *kbuf, int ksiz, int *sp) { + assert(hdb && kbuf && ksiz >= 0 && sp); + if (!HDBLOCKMETHOD(hdb, false)) return NULL; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return NULL; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return NULL; + } + if (!HDBLOCKRECORD(hdb, bidx, false)) { + HDBUNLOCKMETHOD(hdb); + return NULL; + } + char *rv = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, sp); + HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - return NULL; - } - char *rv = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, sp); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } int tchdbgetintoxstr(TCHDB *hdb, const void *kbuf, int ksiz, TCXSTR *xstr) { @@ -769,595 +747,579 @@ int tchdbgetintoxstr(TCHDB *hdb, const void *kbuf, int ksiz, TCXSTR *xstr) { } /* Retrieve a string record in a hash database object. */ -char *tchdbget2(TCHDB *hdb, const char *kstr){ - assert(hdb && kstr); - int vsiz; - return tchdbget(hdb, kstr, strlen(kstr), &vsiz); +char *tchdbget2(TCHDB *hdb, const char *kstr) { + assert(hdb && kstr); + int vsiz; + return tchdbget(hdb, kstr, strlen(kstr), &vsiz); } - /* Retrieve a record in a hash database object and write the value into a buffer. */ -int tchdbget3(TCHDB *hdb, const void *kbuf, int ksiz, void *vbuf, int max){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && max >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return -1; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return -1; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return -1; - } - if(!HDBLOCKRECORD(hdb, bidx, false)){ - HDBUNLOCKMETHOD(hdb); - return -1; - } - int rv = tchdbgetintobuf(hdb, kbuf, ksiz, bidx, hash, vbuf, max); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return rv; -} - - -/* Get the size of the value of a record in a hash database object. */ -int tchdbvsiz(TCHDB *hdb, const void *kbuf, int ksiz){ - assert(hdb && kbuf && ksiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return -1; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return -1; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return -1; - } - if(!HDBLOCKRECORD(hdb, bidx, false)){ +int tchdbget3(TCHDB *hdb, const void *kbuf, int ksiz, void *vbuf, int max) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && max >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return -1; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return -1; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return -1; + } + if (!HDBLOCKRECORD(hdb, bidx, false)) { + HDBUNLOCKMETHOD(hdb); + return -1; + } + int rv = tchdbgetintobuf(hdb, kbuf, ksiz, bidx, hash, vbuf, max); + HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - return -1; - } - int rv = tchdbvsizimpl(hdb, kbuf, ksiz, bidx, hash); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } +/* Get the size of the value of a record in a hash database object. */ +int tchdbvsiz(TCHDB *hdb, const void *kbuf, int ksiz) { + assert(hdb && kbuf && ksiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return -1; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return -1; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return -1; + } + if (!HDBLOCKRECORD(hdb, bidx, false)) { + HDBUNLOCKMETHOD(hdb); + return -1; + } + int rv = tchdbvsizimpl(hdb, kbuf, ksiz, bidx, hash); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return rv; +} /* Get the size of the value of a string record in a hash database object. */ -int tchdbvsiz2(TCHDB *hdb, const char *kstr){ - assert(hdb && kstr); - return tchdbvsiz(hdb, kstr, strlen(kstr)); +int tchdbvsiz2(TCHDB *hdb, const char *kstr) { + assert(hdb && kstr); + return tchdbvsiz(hdb, kstr, strlen(kstr)); } - /* Initialize the iterator of a hash database object. */ -bool tchdbiterinit(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbiterinit(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbiterinitimpl(hdb); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbiterinitimpl(hdb); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } /* Initialize the iterator of a hash database object. */ -bool tchdbiterinit4(TCHDB *hdb, uint64_t *iter){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbiterinit4(TCHDB *hdb, uint64_t *iter) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + *iter = hdb->frec; HDBUNLOCKMETHOD(hdb); - return false; - } - *iter = hdb->frec; - HDBUNLOCKMETHOD(hdb); - return true; + return true; } /* Get the next key of the iterator of a hash database object. */ -void *tchdbiternext(TCHDB *hdb, int *sp){ - assert(hdb && sp); - if(!HDBLOCKMETHOD(hdb, true)) return NULL; - if(INVALIDHANDLE(hdb->fd) || hdb->iter < 1){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return NULL; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +void *tchdbiternext(TCHDB *hdb, int *sp) { + assert(hdb && sp); + if (!HDBLOCKMETHOD(hdb, true)) return NULL; + if (INVALIDHANDLE(hdb->fd) || hdb->iter < 1) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return NULL; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return NULL; + } + char *rv = tchdbiternextimpl(hdb, sp); HDBUNLOCKMETHOD(hdb); - return NULL; - } - char *rv = tchdbiternextimpl(hdb, sp); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Get the next key string of the iterator of a hash database object. */ -char *tchdbiternext2(TCHDB *hdb){ - assert(hdb); - int vsiz; - return tchdbiternext(hdb, &vsiz); +char *tchdbiternext2(TCHDB *hdb) { + assert(hdb); + int vsiz; + return tchdbiternext(hdb, &vsiz); } - /* Get the next extensible objects of the iterator of a hash database object. */ -bool tchdbiternext3(TCHDB *hdb, TCXSTR *kxstr, TCXSTR *vxstr){ - assert(hdb && kxstr && vxstr); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd) || hdb->iter < 1){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbiternext3(TCHDB *hdb, TCXSTR *kxstr, TCXSTR *vxstr) { + assert(hdb && kxstr && vxstr); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd) || hdb->iter < 1) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbiternextintoxstr(hdb, kxstr, vxstr); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbiternextintoxstr(hdb, kxstr, vxstr); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Get the next extensible objects of the iterator of a hash database object. */ -bool tchdbiternext4(TCHDB *hdb, uint64_t *iter, TCXSTR *kxstr, TCXSTR *vxstr){ - assert(hdb && kxstr && vxstr && iter); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd) || *iter < 1){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbiternext4(TCHDB *hdb, uint64_t *iter, TCXSTR *kxstr, TCXSTR *vxstr) { + assert(hdb && kxstr && vxstr && iter); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd) || *iter < 1) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbiternextintoxstr2(hdb, iter, kxstr, vxstr); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbiternextintoxstr2(hdb, iter, kxstr, vxstr); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Get forward matching keys in a hash database object. */ -TCLIST *tchdbfwmkeys(TCHDB *hdb, const void *pbuf, int psiz, int max){ - assert(hdb && pbuf && psiz >= 0); - TCLIST* keys = tclistnew(); - if(!HDBLOCKMETHOD(hdb, true)) return keys; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return keys; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +TCLIST *tchdbfwmkeys(TCHDB *hdb, const void *pbuf, int psiz, int max) { + assert(hdb && pbuf && psiz >= 0); + TCLIST* keys = tclistnew(); + if (!HDBLOCKMETHOD(hdb, true)) return keys; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return keys; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return keys; + } + if (max < 0) max = INT_MAX; + uint64_t iter = hdb->iter; + tchdbiterinitimpl(hdb); + char *kbuf; + int ksiz; + while (TCLISTNUM(keys) < max && (kbuf = tchdbiternextimpl(hdb, &ksiz)) != NULL) { + if (ksiz >= psiz && !memcmp(kbuf, pbuf, psiz)) { + tclistpushmalloc(keys, kbuf, ksiz); + } else { + TCFREE(kbuf); + } + } + hdb->iter = iter; HDBUNLOCKMETHOD(hdb); return keys; - } - if(max < 0) max = INT_MAX; - uint64_t iter = hdb->iter; - tchdbiterinitimpl(hdb); - char *kbuf; - int ksiz; - while(TCLISTNUM(keys) < max && (kbuf = tchdbiternextimpl(hdb, &ksiz)) != NULL){ - if(ksiz >= psiz && !memcmp(kbuf, pbuf, psiz)){ - tclistpushmalloc(keys, kbuf, ksiz); - } else { - TCFREE(kbuf); - } - } - hdb->iter = iter; - HDBUNLOCKMETHOD(hdb); - return keys; } - /* Get forward matching string keys in a hash database object. */ -TCLIST *tchdbfwmkeys2(TCHDB *hdb, const char *pstr, int max){ - assert(hdb && pstr); - return tchdbfwmkeys(hdb, pstr, strlen(pstr), max); +TCLIST *tchdbfwmkeys2(TCHDB *hdb, const char *pstr, int max) { + assert(hdb && pstr); + return tchdbfwmkeys(hdb, pstr, strlen(pstr), max); } - /* Add an integer to a record in a hash database object. */ -int tchdbaddint(TCHDB *hdb, const void *kbuf, int ksiz, int num){ - assert(hdb && kbuf && ksiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return INT_MIN; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return INT_MIN; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return INT_MIN; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return INT_MIN; - } - if(hdb->zmode){ - char *zbuf; - int osiz; - char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); - if(obuf){ - if(osiz != sizeof(num)){ - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - TCFREE(obuf); - HDBUNLOCKRECORD(hdb, bidx); +int tchdbaddint(TCHDB *hdb, const void *kbuf, int ksiz, int num) { + assert(hdb && kbuf && ksiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return INT_MIN; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); HDBUNLOCKMETHOD(hdb); return INT_MIN; - } - num += *(int *)obuf; - TCFREE(obuf); - } - int zsiz; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate((char *)&num, sizeof(num), &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress((char *)&num, sizeof(num), &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode((char *)&num, sizeof(num), &zsiz); - } else { - zbuf = hdb->enc((char *)&num, sizeof(num), &zsiz, hdb->encop); } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return INT_MIN; + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return INT_MIN; } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, zsiz, HDBPDOVER); - TCFREE(zbuf); + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return INT_MIN; + } + if (hdb->zmode) { + char *zbuf; + int osiz; + char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); + if (obuf) { + if (osiz != sizeof (num)) { + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + TCFREE(obuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return INT_MIN; + } + num += *(int *) obuf; + TCFREE(obuf); + } + int zsiz; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate((char *) &num, sizeof (num), &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress((char *) &num, sizeof (num), &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode((char *) &num, sizeof (num), &zsiz); + } else { + zbuf = hdb->enc((char *) &num, sizeof (num), &zsiz, hdb->encop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return INT_MIN; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, zsiz, HDBPDOVER); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv ? num : INT_MIN; + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, (char *) &num, sizeof (num), HDBPDADDINT); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv ? num : INT_MIN; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, (char *)&num, sizeof(num), HDBPDADDINT); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv ? num : INT_MIN; } - /* Add a real number to a record in a hash database object. */ -double tchdbadddouble(TCHDB *hdb, const void *kbuf, int ksiz, double num){ - assert(hdb && kbuf && ksiz >= 0); - if(!HDBLOCKMETHOD(hdb, false)) return nan(""); - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return nan(""); - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return nan(""); - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return nan(""); - } - if(hdb->zmode){ - char *zbuf; - int osiz; - char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); - if(obuf){ - if(osiz != sizeof(num)){ - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - TCFREE(obuf); - HDBUNLOCKRECORD(hdb, bidx); +double tchdbadddouble(TCHDB *hdb, const void *kbuf, int ksiz, double num) { + assert(hdb && kbuf && ksiz >= 0); + if (!HDBLOCKMETHOD(hdb, false)) return nan(""); + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); HDBUNLOCKMETHOD(hdb); return nan(""); - } - num += *(double *)obuf; - TCFREE(obuf); - } - int zsiz; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate((char *)&num, sizeof(num), &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress((char *)&num, sizeof(num), &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode((char *)&num, sizeof(num), &zsiz); - } else { - zbuf = hdb->enc((char *)&num, sizeof(num), &zsiz, hdb->encop); } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return nan(""); + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return nan(""); + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return nan(""); + } + if (hdb->zmode) { + char *zbuf; + int osiz; + char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); + if (obuf) { + if (osiz != sizeof (num)) { + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + TCFREE(obuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return nan(""); + } + num += *(double *) obuf; + TCFREE(obuf); + } + int zsiz; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate((char *) &num, sizeof (num), &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress((char *) &num, sizeof (num), &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode((char *) &num, sizeof (num), &zsiz); + } else { + zbuf = hdb->enc((char *) &num, sizeof (num), &zsiz, hdb->encop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return nan(""); + } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, zsiz, HDBPDOVER); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv ? num : nan(""); } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, zsiz, HDBPDOVER); - TCFREE(zbuf); + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, (char *) &num, sizeof (num), HDBPDADDDBL); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv ? num : nan(""); - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, (char *)&num, sizeof(num), HDBPDADDDBL); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv ? num : nan(""); } - /* Synchronize updated contents of a hash database object with the file and the device. */ -bool tchdbsync(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbsync(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbmemsync(hdb, true); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbmemsync(hdb, true); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Optimize the file of a hash database object. */ -bool tchdboptimize(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdboptimize(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + HDBTHREADYIELD(hdb); + bool rv = tchdboptimizeimpl(hdb, bnum, apow, fpow, opts); HDBUNLOCKMETHOD(hdb); - return false; - } - HDBTHREADYIELD(hdb); - bool rv = tchdboptimizeimpl(hdb, bnum, apow, fpow, opts); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Remove all records of a hash database object. */ -bool tchdbvanish(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbvanish(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + HDBTHREADYIELD(hdb); + bool rv = tchdbvanishimpl(hdb); HDBUNLOCKMETHOD(hdb); - return false; - } - HDBTHREADYIELD(hdb); - bool rv = tchdbvanishimpl(hdb); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Copy the database file of a hash database object. */ -bool tchdbcopy(TCHDB *hdb, const char *path){ - assert(hdb && path); - if(!HDBLOCKMETHOD(hdb, false)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKALLRECORDS(hdb, false)){ +bool tchdbcopy(TCHDB *hdb, const char *path) { + assert(hdb && path); + if (!HDBLOCKMETHOD(hdb, false)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKALLRECORDS(hdb, false)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + HDBTHREADYIELD(hdb); + bool rv = tchdbcopyimpl(hdb, path); + HDBUNLOCKALLRECORDS(hdb); HDBUNLOCKMETHOD(hdb); - return false; - } - HDBTHREADYIELD(hdb); - bool rv = tchdbcopyimpl(hdb, path); - HDBUNLOCKALLRECORDS(hdb); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Begin the transaction of a hash database object. */ -bool tchdbtranbegin(TCHDB *hdb){ - assert(hdb); - for(double wsec = 1.0 / sysconf_SC_CLK_TCK; true; wsec *= 2){ - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!hdb->tran) break; - HDBUNLOCKMETHOD(hdb); - if(wsec > 1.0) wsec = 1.0; - tcsleep(wsec); - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!tchdbmemsync(hdb, (hdb->omode & HDBOTSYNC))){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->walfd)){ - char *tpath = tcsprintf("%s%c%s", hdb->path, MYEXTCHR, HDBWALSUFFIX); +bool tchdbtranbegin(TCHDB *hdb) { + assert(hdb); + for (double wsec = 1.0 / sysconf_SC_CLK_TCK; true; wsec *= 2) { + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!hdb->tran) break; + HDBUNLOCKMETHOD(hdb); + if (wsec > 1.0) wsec = 1.0; + tcsleep(wsec); + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!tchdbmemsync(hdb, (hdb->omode & HDBOTSYNC))) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->walfd)) { + char *tpath = tcsprintf("%s%c%s", hdb->path, MYEXTCHR, HDBWALSUFFIX); #ifndef _WIN32 - HANDLE walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, HDBFILEMODE); + HANDLE walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, HDBFILEMODE); #else - HANDLE walfd = CreateFile(tpath, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE walfd = CreateFile(tpath, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); #endif - TCFREE(tpath); - if(INVALIDHANDLE(walfd)){ - tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - hdb->walfd = walfd; - } - tchdbsetflag(hdb, HDBFOPEN, false); - if(!tchdbwalinit(hdb)){ + TCFREE(tpath); + if (INVALIDHANDLE(walfd)) { + tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + hdb->walfd = walfd; + } + tchdbsetflag(hdb, HDBFOPEN, false); + if (!tchdbwalinit(hdb)) { + tchdbsetflag(hdb, HDBFOPEN, true); + HDBUNLOCKMETHOD(hdb); + return false; + } tchdbsetflag(hdb, HDBFOPEN, true); + hdb->tran = true; HDBUNLOCKMETHOD(hdb); - return false; - } - tchdbsetflag(hdb, HDBFOPEN, true); - hdb->tran = true; - HDBUNLOCKMETHOD(hdb); - return true; + return true; } - /* Commit the transaction of a hash database object. */ -bool tchdbtrancommit(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (!hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbtrancommit(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (!hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool err = false; + if (hdb->async && !tchdbflushdrp(hdb)) err = true; + if (!tchdbmemsync(hdb, (hdb->omode & HDBOTSYNC))) err = true; + if (HDBLOCKWAL(hdb)) { + if (!err && !tcftruncate(hdb->walfd, 0)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + HDBUNLOCKWAL(hdb); + } else { + err = true; + } + hdb->tran = false; HDBUNLOCKMETHOD(hdb); - return false; - } - bool err = false; - if(hdb->async && !tchdbflushdrp(hdb)) err = true; - if(!tchdbmemsync(hdb, (hdb->omode & HDBOTSYNC))) err = true; - if(!err && !tcftruncate(hdb->walfd, 0)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - err = true; - } - hdb->tran = false; - HDBUNLOCKMETHOD(hdb); - return !err; + return !err; } - /* Abort the transaction of a hash database object. */ -bool tchdbtranabort(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (!hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbtranabort(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (!hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + bool err = false; + if (hdb->async && !tchdbflushdrp(hdb)) err = true; + if (!tchdbmemsync(hdb, false)) err = true; + if (!tchdbwalrestore(hdb, hdb->path)) err = true; + hdb->dfcur = hdb->frec; + hdb->iter = 0; + hdb->fbpnum = 0; + if (hdb->recc) tcmdbvanish(hdb->recc); + hdb->tran = false; HDBUNLOCKMETHOD(hdb); - return false; - } - bool err = false; - if(hdb->async && !tchdbflushdrp(hdb)) err = true; - if(!tchdbmemsync(hdb, false)) err = true; - if(!tchdbwalrestore(hdb, hdb->path)) err = true; - hdb->dfcur = hdb->frec; - hdb->iter = 0; - hdb->fbpnum = 0; - if(hdb->recc) tcmdbvanish(hdb->recc); - hdb->tran = false; - HDBUNLOCKMETHOD(hdb); - return !err; + return !err; } - /* Get the file path of a hash database object. */ -const char *tchdbpath(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, false)) return NULL; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +const char *tchdbpath(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, false)) return NULL; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return NULL; + } + const char *rv = hdb->path; HDBUNLOCKMETHOD(hdb); - return NULL; - } - const char *rv = hdb->path; - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Get the number of records of a hash database object. */ -uint64_t tchdbrnum(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, false)) return 0; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tchdbrnum(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, false)) return 0; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return 0; + } + uint64_t rv = hdb->rnum; HDBUNLOCKMETHOD(hdb); - return 0; - } - uint64_t rv = hdb->rnum; - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Get the size of the database file of a hash database object. */ -uint64_t tchdbfsiz(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, false)) return 0; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +uint64_t tchdbfsiz(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, false)) return 0; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return 0; + } + uint64_t rv = hdb->fsiz; HDBUNLOCKMETHOD(hdb); - return 0; - } - uint64_t rv = hdb->fsiz; - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } @@ -1366,17 +1328,16 @@ uint64_t tchdbfsiz(TCHDB *hdb){ * features for experts *************************************************************************************************/ - /* Set the error code of a hash database object. */ -void tchdbsetecode(TCHDB *hdb, int ecode, const char *filename, int line, const char *func){ - assert(hdb && filename && line >= 1 && func); - if(!hdb->fatal) { - if (hdb->eckey) { - pthread_setspecific(*(pthread_key_t *)hdb->eckey, (void *)(intptr_t)ecode); - } - hdb->ecode = ecode; - } - switch (ecode) { //Fatal errors +void tchdbsetecode(TCHDB *hdb, int ecode, const char *filename, int line, const char *func) { + assert(hdb && filename && line >= 1 && func); + if (!hdb->fatal) { + if (hdb->eckey) { + pthread_setspecific(*(pthread_key_t *) hdb->eckey, (void *) (intptr_t) ecode); + } + hdb->ecode = ecode; + } + switch (ecode) { //Fatal errors case TCETHREAD: case TCENOFILE: case TCENOPERM: @@ -1404,224 +1365,209 @@ void tchdbsetecode(TCHDB *hdb, int ecode, const char *filename, int line, const case TCESUCCESS: case TCENOREC: case TCEKEEP: - return; - break; + return; + break; default: break; - } + } #ifdef _WIN32 - DWORD winerrno = GetLastError(); + DWORD winerrno = GetLastError(); #endif - int stderrno = errno; - if(!INVALIDHANDLE(hdb->dbgfd) || hdb->fatal) { - HANDLE dbgfd = INVALIDHANDLE(hdb->dbgfd) ? GET_STDERR_HANDLE() : (hdb->dbgfd); - char obuf[HDBIOBUFSIZ]; + int stderrno = errno; + if (!INVALIDHANDLE(hdb->dbgfd) || hdb->fatal) { + HANDLE dbgfd = INVALIDHANDLE(hdb->dbgfd) ? GET_STDERR_HANDLE() : (hdb->dbgfd); + char obuf[HDBIOBUFSIZ]; #ifdef _WIN32 - LPTSTR errorText = NULL; - if (winerrno > 0) { - DWORD ret = FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, winerrno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &errorText, 0, NULL); - if (!ret) { - if (errorText) LocalFree(errorText); - errorText = NULL; + LPTSTR errorText = NULL; + if (winerrno > 0) { + DWORD ret = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, winerrno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & errorText, 0, NULL); + if (!ret) { + if (errorText) LocalFree(errorText); + errorText = NULL; + } } - } - int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s:%d:%s\n", - filename, line, - func, (hdb->path ? hdb->path : "-"), - ecode, tchdberrmsg(ecode), - winerrno, (errorText ? errorText : "-"), - stderrno, (stderrno > 0 ? strerror(stderrno) : "-")); - if (errorText) LocalFree(errorText); + int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s:%d:%s\n", + filename, line, + func, (hdb->path ? hdb->path : "-"), + ecode, tchdberrmsg(ecode), + winerrno, (errorText ? errorText : "-"), + stderrno, (stderrno > 0 ? strerror(stderrno) : "-")); + if (errorText) LocalFree(errorText); #else - int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s\n", - filename, line, - func, (hdb->path ? hdb->path : "-"), - ecode, tchdberrmsg(ecode), - stderrno, strerror(stderrno)); + int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s\n", + filename, line, + func, (hdb->path ? hdb->path : "-"), + ecode, tchdberrmsg(ecode), + stderrno, strerror(stderrno)); #endif - tcwrite(dbgfd, obuf, osiz); - } + tcwrite(dbgfd, obuf, osiz); + } } /* Set the type of a hash database object. */ -void tchdbsettype(TCHDB *hdb, uint8_t type){ - assert(hdb); - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return; - } - hdb->type = type; +void tchdbsettype(TCHDB *hdb, uint8_t type) { + assert(hdb); + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return; + } + hdb->type = type; } - /* Set the file descriptor for debugging output. */ -void tchdbsetdbgfd(TCHDB *hdb, HANDLE fd){ - assert(hdb); - hdb->dbgfd = fd; +void tchdbsetdbgfd(TCHDB *hdb, HANDLE fd) { + assert(hdb); + hdb->dbgfd = fd; } - /* Get the file descriptor for debugging output. */ -HANDLE tchdbdbgfd(TCHDB *hdb){ - assert(hdb); - return hdb->dbgfd; +HANDLE tchdbdbgfd(TCHDB *hdb) { + assert(hdb); + return hdb->dbgfd; } - /* Check whether mutual exclusion control is set to a hash database object. */ -bool tchdbhasmutex(TCHDB *hdb){ - assert(hdb); - return hdb->mmtx != NULL; +bool tchdbhasmutex(TCHDB *hdb) { + assert(hdb); + return hdb->mmtx != NULL; } - /* Synchronize updating contents on memory of a hash database object. */ -bool tchdbmemsync(TCHDB *hdb, bool phys){ - assert(hdb); - bool err = false; - char hbuf[HDBHEADSIZ]; - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return false; - } - if (!HDBLOCKSMEM(hdb, true)) return false; - tchdbdumpmeta(hdb, hbuf); - memcpy((void *) hdb->map, hbuf, HDBOPAQUEOFF); - HDBUNLOCKSMEM(hdb); - - if (phys) { - if (!HDBLOCKSMEM(hdb, false)) return false; -#ifdef _WIN32 - if(!FlushViewOfFile((PCVOID) hdb->map, 0)){ - tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; +bool tchdbmemsync(TCHDB *hdb, bool phys) { + assert(hdb); + bool err = false; + char hbuf[HDBHEADSIZ]; + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return false; } + if (!HDBLOCKSMEM(hdb, true)) return false; + tchdbdumpmeta(hdb, hbuf); + memcpy((void *) hdb->map, hbuf, HDBOPAQUEOFF); + HDBUNLOCKSMEM(hdb); + if (phys) { + if (!HDBLOCKSMEM(hdb, false)) return false; +#ifdef _WIN32 + if (!hdb->map || !FlushViewOfFile((PCVOID) hdb->map, 0)) { + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + } #elif !defined __GNU__ - size_t xmsiz = (hdb->xmsiz > hdb->msiz) ? hdb->xmsiz : hdb->msiz; - if(msync(hdb->map, xmsiz, MS_SYNC)){ - tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; - } + size_t xmsiz = (hdb->xmsiz > hdb->msiz) ? hdb->xmsiz : hdb->msiz; + if (!hdb->map || msync(hdb->map, xmsiz, MS_SYNC)) { + tchmdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + } #endif - HDBUNLOCKSMEM(hdb); - if(fsync(hdb->fd)){ - tchdbsetecode(hdb, TCESYNC, __FILE__, __LINE__, __func__); - err = true; + HDBUNLOCKSMEM(hdb); + if (fsync(hdb->fd)) { + tchdbsetecode(hdb, TCESYNC, __FILE__, __LINE__, __func__); + err = true; + } } - } - return !err; + return !err; } - /* Get the number of elements of the bucket array of a hash database object. */ -uint64_t tchdbbnum(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->bnum; +uint64_t tchdbbnum(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->bnum; } - /* Get the record alignment a hash database object. */ -uint32_t tchdbalign(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->align; +uint32_t tchdbalign(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->align; } - /* Get the maximum number of the free block pool of a a hash database object. */ -uint32_t tchdbfbpmax(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->fbpmax; +uint32_t tchdbfbpmax(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->fbpmax; } - /* Get the size of the extra mapped memory of a hash database object. */ -uint64_t tchdbxmsiz(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->xmsiz; +uint64_t tchdbxmsiz(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->xmsiz; } - /* Get the inode number of the database file of a hash database object. */ -uint64_t tchdbinode(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->inode; +uint64_t tchdbinode(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->inode; } - /* Get the modification time of the database file of a hash database object. */ -time_t tchdbmtime(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->mtime; +time_t tchdbmtime(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->mtime; } - /* Get the connection mode of a hash database object. */ -int tchdbomode(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->omode; +int tchdbomode(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->omode; } - /* Get the database type of a hash database object. */ -uint8_t tchdbtype(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->type; +uint8_t tchdbtype(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->type; } - /* Get the additional flags of a hash database object. */ -uint8_t tchdbflags(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->flags; +uint8_t tchdbflags(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->flags; } - /* Get the options of a hash database object. */ -uint8_t tchdbopts(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - return hdb->opts; +uint8_t tchdbopts(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + return hdb->opts; } bool tchdbcopyopaque(TCHDB *dst, TCHDB *src, int off, int rsz) { @@ -1632,8 +1578,8 @@ bool tchdbcopyopaque(TCHDB *dst, TCHDB *src, int off, int rsz) { char odata[HDBOPAQUESZ]; rsz = tchdbreadopaque(src, odata, off, rsz); if (rsz == -1) { - tchdbsetecode(dst, tchdbecode(src), __FILE__, __LINE__, __func__); - return false; + tchdbsetecode(dst, tchdbecode(src), __FILE__, __LINE__, __func__); + return false; } return (tchdbwriteopaque(dst, odata, off, rsz) == rsz); } @@ -1653,378 +1599,364 @@ int tchdbreadopaque(TCHDB *hdb, void *dst, int off, int bsiz) { return -1; } if (!HDBLOCKSMEM(hdb, false)) return -1; - assert(hdb->map); memcpy((void *) dst, (void *) (hdb->map + HDBOPAQUEOFF + off), bsiz); HDBUNLOCKSMEM(hdb); return bsiz; } int tchdbwriteopaque(TCHDB *hdb, const void *src, int off, int nb) { - assert(hdb && src); - if (nb == -1) { + assert(hdb && src); + if (nb == -1) { nb = HDBOPAQUESZ; - } - if (off > HDBOPAQUESZ) { + } + if (off > HDBOPAQUESZ) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return -1; + } + nb = MIN(nb, HDBOPAQUESZ - off); + if (nb <= 0) { tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); return -1; - } - nb = MIN(nb, HDBOPAQUESZ - off); - if (nb <= 0) { - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return -1; - } - if (!HDBLOCKSMEM(hdb, true)) return -1; - memcpy((void *) (hdb->map + HDBOPAQUEOFF + off), src, nb); - HDBUNLOCKSMEM(hdb); - return nb; + } + if (!HDBLOCKSMEM(hdb, true)) return -1; + memcpy((void *) (hdb->map + HDBOPAQUEOFF + off), src, nb); + HDBUNLOCKSMEM(hdb); + return nb; } /* Get the number of used elements of the bucket array of a hash database object. */ -uint64_t tchdbbnumused(TCHDB *hdb){ - assert(hdb); - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - return 0; - } - if (!HDBLOCKSMEM(hdb, false)) return false; - uint64_t unum = 0; - if(hdb->ba64){ - uint64_t *buckets = HDBB64(hdb); - for(int i = 0; i < hdb->bnum; i++){ - if(buckets[i]) unum++; - } - } else { - uint32_t *buckets = HDBB32(hdb); - for(int i = 0; i < hdb->bnum; i++){ - if(buckets[i]) unum++; - } - } - HDBUNLOCKSMEM(hdb); - return unum; +uint64_t tchdbbnumused(TCHDB *hdb) { + assert(hdb); + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + return 0; + } + if (!HDBLOCKSMEM(hdb, false)) return false; + uint64_t unum = 0; + if (hdb->ba64) { + uint64_t *buckets = HDBB64(hdb); + for (int i = 0; i < hdb->bnum; i++) { + if (buckets[i]) unum++; + } + } else { + uint32_t *buckets = HDBB32(hdb); + for (int i = 0; i < hdb->bnum; i++) { + if (buckets[i]) unum++; + } + } + HDBUNLOCKSMEM(hdb); + return unum; } - /* Set the custom codec functions of a hash database object. */ -bool tchdbsetcodecfunc(TCHDB *hdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop){ - assert(hdb && enc && dec); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(!INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbsetcodecfunc(TCHDB *hdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop) { + assert(hdb && enc && dec); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (!INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + hdb->enc = enc; + hdb->encop = encop; + hdb->dec = dec; + hdb->decop = decop; HDBUNLOCKMETHOD(hdb); - return false; - } - hdb->enc = enc; - hdb->encop = encop; - hdb->dec = dec; - hdb->decop = decop; - HDBUNLOCKMETHOD(hdb); - return true; + return true; } - /* Get the unit step number of auto defragmentation of a hash database object. */ -uint32_t tchdbdfunit(TCHDB *hdb){ - assert(hdb); - return hdb->dfunit; +uint32_t tchdbdfunit(TCHDB *hdb) { + assert(hdb); + return hdb->dfunit; } - /* Perform dynamic defragmentation of a hash database object. */ -bool tchdbdefrag(TCHDB *hdb, int64_t step){ - assert(hdb); - if(step > 0){ - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbdefragimpl(hdb, step); - HDBUNLOCKMETHOD(hdb); - return rv; - } - if(!HDBLOCKMETHOD(hdb, false)) return false; - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - bool err = false; - if(HDBLOCKALLRECORDS(hdb, true)){ - hdb->dfcur = hdb->frec; - HDBUNLOCKALLRECORDS(hdb); - } else { - err = true; - } - bool stop = false; - while(!err && !stop){ - if(HDBLOCKALLRECORDS(hdb, true)){ - uint64_t cur = hdb->dfcur; - if(!tchdbdefragimpl(hdb, UINT8_MAX)) err = true; - if(hdb->dfcur <= cur) stop = true; - HDBUNLOCKALLRECORDS(hdb); - HDBTHREADYIELD(hdb); +bool tchdbdefrag(TCHDB *hdb, int64_t step) { + assert(hdb); + if (step > 0) { + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbdefragimpl(hdb, step); + HDBUNLOCKMETHOD(hdb); + return rv; + } + if (!HDBLOCKMETHOD(hdb, false)) return false; + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool err = false; + if (HDBLOCKALLRECORDS(hdb, true)) { + hdb->dfcur = hdb->frec; + HDBUNLOCKALLRECORDS(hdb); } else { - err = true; + err = true; + } + bool stop = false; + while (!err && !stop) { + if (HDBLOCKALLRECORDS(hdb, true)) { + uint64_t cur = hdb->dfcur; + if (!tchdbdefragimpl(hdb, UINT8_MAX)) err = true; + if (hdb->dfcur <= cur) stop = true; + HDBUNLOCKALLRECORDS(hdb); + HDBTHREADYIELD(hdb); + } else { + err = true; + } } - } - HDBUNLOCKMETHOD(hdb); - return !err; + HDBUNLOCKMETHOD(hdb); + return !err; } - /* Clear the cache of a hash tree database object. */ -bool tchdbcacheclear(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbcacheclear(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + HDBTHREADYIELD(hdb); + if (hdb->recc) tcmdbvanish(hdb->recc); HDBUNLOCKMETHOD(hdb); - return false; - } - HDBTHREADYIELD(hdb); - if(hdb->recc) tcmdbvanish(hdb->recc); - HDBUNLOCKMETHOD(hdb); - return true; + return true; } - /* Store a record into a hash database object with a duplication handler. */ bool tchdbputproc(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - TCPDPROC proc, void *op){ - assert(hdb && kbuf && ksiz >= 0 && proc); - if(!HDBLOCKMETHOD(hdb, false)) return false; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKRECORD(hdb, bidx, true)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->zmode){ - char *zbuf; - int osiz; - char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); - if(obuf){ - int nsiz; - char *nbuf = proc(obuf, osiz, &nsiz, op); - if(nbuf == (void *)-1){ - bool rv = tchdboutimpl(hdb, kbuf, ksiz, bidx, hash); - TCFREE(obuf); - HDBUNLOCKRECORD(hdb, bidx); + TCPDPROC proc, void *op) { + assert(hdb && kbuf && ksiz >= 0 && proc); + if (!HDBLOCKMETHOD(hdb, false)) return false; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); HDBUNLOCKMETHOD(hdb); - return rv; - } else if(nbuf){ - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(nbuf, nsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(nbuf, nsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(nbuf, nsiz, &vsiz); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKRECORD(hdb, bidx, true)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->zmode) { + char *zbuf; + int osiz; + char *obuf = tchdbgetimpl(hdb, kbuf, ksiz, bidx, hash, &osiz); + if (obuf) { + int nsiz; + char *nbuf = proc(obuf, osiz, &nsiz, op); + if (nbuf == (void *) - 1) { + bool rv = tchdboutimpl(hdb, kbuf, ksiz, bidx, hash); + TCFREE(obuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return rv; + } else if (nbuf) { + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(nbuf, nsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(nbuf, nsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(nbuf, nsiz, &vsiz); + } else { + zbuf = hdb->enc(nbuf, nsiz, &vsiz, hdb->encop); + } + TCFREE(nbuf); + } else { + zbuf = NULL; + } + TCFREE(obuf); + } else if (vbuf) { + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsencode(vbuf, vsiz, &vsiz); + } else { + zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); + } } else { - zbuf = hdb->enc(nbuf, nsiz, &vsiz, hdb->encop); + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!zbuf) { + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + return false; } - TCFREE(nbuf); - } else { - zbuf = NULL; - } - TCFREE(obuf); - } else if(vbuf){ - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_deflate(vbuf, vsiz, &vsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzcompress(vbuf, vsiz, &vsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsencode(vbuf, vsiz, &vsiz); - } else { - zbuf = hdb->enc(vbuf, vsiz, &vsiz, hdb->encop); - } + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); + TCFREE(zbuf); + HDBUNLOCKRECORD(hdb, bidx); + HDBUNLOCKMETHOD(hdb); + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + return rv; + } + HDBPDPROCOP procop; + procop.proc = proc; + procop.op = op; + HDBPDPROCOP *procptr = &procop; + tcgeneric_t stack[(TCNUMBUFSIZ * 2) / sizeof (tcgeneric_t) + 1]; + char *rbuf; + if (ksiz <= sizeof (stack) - sizeof (procptr)) { + rbuf = (char *) stack; } else { - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!zbuf){ - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, zbuf, vsiz, HDBPDOVER); - TCFREE(zbuf); + TCMALLOC(rbuf, ksiz + sizeof (procptr)); + } + char *wp = rbuf; + memcpy(wp, &procptr, sizeof (procptr)); + wp += sizeof (procptr); + memcpy(wp, kbuf, ksiz); + kbuf = rbuf + sizeof (procptr); + bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDPROC); + if (rbuf != (char *) stack) TCFREE(rbuf); HDBUNLOCKRECORD(hdb, bidx); HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; + if (hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && + !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; return rv; - } - HDBPDPROCOP procop; - procop.proc = proc; - procop.op = op; - HDBPDPROCOP *procptr = &procop; - tcgeneric_t stack[(TCNUMBUFSIZ*2)/sizeof(tcgeneric_t)+1]; - char *rbuf; - if(ksiz <= sizeof(stack) - sizeof(procptr)){ - rbuf = (char *)stack; - } else { - TCMALLOC(rbuf, ksiz + sizeof(procptr)); - } - char *wp = rbuf; - memcpy(wp, &procptr, sizeof(procptr)); - wp += sizeof(procptr); - memcpy(wp, kbuf, ksiz); - kbuf = rbuf + sizeof(procptr); - bool rv = tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDPROC); - if(rbuf != (char *)stack) TCFREE(rbuf); - HDBUNLOCKRECORD(hdb, bidx); - HDBUNLOCKMETHOD(hdb); - if(hdb->dfunit > 0 && hdb->dfcnt > hdb->dfunit && - !tchdbdefrag(hdb, hdb->dfunit * HDBDFRSRAT + 1)) rv = false; - return rv; } - /* Get the custom codec functions of a hash database object. */ -void tchdbcodecfunc(TCHDB *hdb, TCCODEC *ep, void **eop, TCCODEC *dp, void **dop){ - assert(hdb && ep && eop && dp && dop); - *ep = hdb->enc; - *eop = hdb->encop; - *dp = hdb->dec; - *dop = hdb->decop; +void tchdbcodecfunc(TCHDB *hdb, TCCODEC *ep, void **eop, TCCODEC *dp, void **dop) { + assert(hdb && ep && eop && dp && dop); + *ep = hdb->enc; + *eop = hdb->encop; + *dp = hdb->dec; + *dop = hdb->decop; } - /* Retrieve the next record of a record in a hash database object. */ -void *tchdbgetnext(TCHDB *hdb, const void *kbuf, int ksiz, int *sp){ - assert(hdb && sp); - if(!HDBLOCKMETHOD(hdb, true)) return NULL; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return NULL; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +void *tchdbgetnext(TCHDB *hdb, const void *kbuf, int ksiz, int *sp) { + assert(hdb && sp); + if (!HDBLOCKMETHOD(hdb, true)) return NULL; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return NULL; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return NULL; + } + char *rv = tchdbgetnextimpl(hdb, kbuf, ksiz, sp, NULL, NULL); HDBUNLOCKMETHOD(hdb); - return NULL; - } - char *rv = tchdbgetnextimpl(hdb, kbuf, ksiz, sp, NULL, NULL); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Retrieve the next record of a string record in a hash database object. */ -char *tchdbgetnext2(TCHDB *hdb, const char *kstr){ - assert(hdb); - int vsiz; - return tchdbgetnext(hdb, kstr, strlen(kstr), &vsiz); +char *tchdbgetnext2(TCHDB *hdb, const char *kstr) { + assert(hdb); + int vsiz; + return tchdbgetnext(hdb, kstr, strlen(kstr), &vsiz); } - /* Retrieve the key and the value of the next record of a record in a hash database object. */ -char *tchdbgetnext3(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, const char **vbp, int *vsp){ - assert(hdb && sp && vbp && vsp); - if(!HDBLOCKMETHOD(hdb, true)) return NULL; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return NULL; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +char *tchdbgetnext3(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, const char **vbp, int *vsp) { + assert(hdb && sp && vbp && vsp); + if (!HDBLOCKMETHOD(hdb, true)) return NULL; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return NULL; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return NULL; + } + char *rv = tchdbgetnextimpl(hdb, kbuf, ksiz, sp, vbp, vsp); HDBUNLOCKMETHOD(hdb); - return NULL; - } - char *rv = tchdbgetnextimpl(hdb, kbuf, ksiz, sp, vbp, vsp); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Move the iterator to the record corresponding a key of a hash database object. */ -bool tchdbiterinit2(TCHDB *hdb, const void *kbuf, int ksiz){ - assert(hdb && kbuf && ksiz >= 0); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ +bool tchdbiterinit2(TCHDB *hdb, const void *kbuf, int ksiz) { + assert(hdb && kbuf && ksiz >= 0); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + bool rv = tchdbiterjumpimpl(hdb, kbuf, ksiz); HDBUNLOCKMETHOD(hdb); - return false; - } - bool rv = tchdbiterjumpimpl(hdb, kbuf, ksiz); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Move the iterator to the record corresponding a key string of a hash database object. */ -bool tchdbiterinit3(TCHDB *hdb, const char *kstr){ - assert(hdb && kstr); - return tchdbiterinit2(hdb, kstr, strlen(kstr)); +bool tchdbiterinit3(TCHDB *hdb, const char *kstr) { + assert(hdb && kstr); + return tchdbiterinit2(hdb, kstr, strlen(kstr)); } - /* Process each record atomically of a hash database object. */ -bool tchdbforeach(TCHDB *hdb, TCITER iter, void *op){ - assert(hdb && iter); - if(!HDBLOCKMETHOD(hdb, false)) return false; - if(INVALIDHANDLE(hdb->fd)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(hdb->async && !tchdbflushdrp(hdb)){ - HDBUNLOCKMETHOD(hdb); - return false; - } - if(!HDBLOCKALLRECORDS(hdb, false)){ +bool tchdbforeach(TCHDB *hdb, TCITER iter, void *op) { + assert(hdb && iter); + if (!HDBLOCKMETHOD(hdb, false)) return false; + if (INVALIDHANDLE(hdb->fd)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (hdb->async && !tchdbflushdrp(hdb)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + if (!HDBLOCKALLRECORDS(hdb, false)) { + HDBUNLOCKMETHOD(hdb); + return false; + } + HDBTHREADYIELD(hdb); + bool rv = tchdbforeachimpl(hdb, iter, op); + HDBUNLOCKALLRECORDS(hdb); HDBUNLOCKMETHOD(hdb); - return false; - } - HDBTHREADYIELD(hdb); - bool rv = tchdbforeachimpl(hdb, iter, op); - HDBUNLOCKALLRECORDS(hdb); - HDBUNLOCKMETHOD(hdb); - return rv; + return rv; } - /* Void the transaction of a hash database object. */ -bool tchdbtranvoid(TCHDB *hdb){ - assert(hdb); - if(!HDBLOCKMETHOD(hdb, true)) return false; - if (!hdb->tran) { - tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); - HDBUNLOCKMETHOD(hdb); - return false; - } - if(INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); +bool tchdbtranvoid(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKMETHOD(hdb, true)) return false; + if (!hdb->tran) { + tchdbsetecode(hdb, TCETR, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + if (INVALIDHANDLE(hdb->fd) || !(hdb->omode & HDBOWRITER) || hdb->fatal) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + HDBUNLOCKMETHOD(hdb); + return false; + } + hdb->tran = false; HDBUNLOCKMETHOD(hdb); - return false; - } - hdb->tran = false; - HDBUNLOCKMETHOD(hdb); - return true; + return true; } @@ -2036,1099 +1968,1084 @@ bool tchdbtranvoid(TCHDB *hdb){ /* Get a natural prime number not less than a floor number. `num' specified the floor number. The return value is a prime number not less than the floor number. */ -static uint64_t tcgetprime(uint64_t num){ - uint64_t primes[] = { - 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 43, 47, 53, 59, 61, 71, 79, 83, - 89, 103, 109, 113, 127, 139, 157, 173, 191, 199, 223, 239, 251, 283, 317, 349, - 383, 409, 443, 479, 509, 571, 631, 701, 761, 829, 887, 953, 1021, 1151, 1279, - 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]; -} - -static bool tchdbseekwrite(TCHDB *hdb, off_t off, const void *buf, size_t size){ +static uint64_t tcgetprime(uint64_t num) { + uint64_t primes[] = { + 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 43, 47, 53, 59, 61, 71, 79, 83, + 89, 103, 109, 113, 127, 139, 157, 173, 191, 199, 223, 239, 251, 283, 317, 349, + 383, 409, 443, 479, 509, 571, 631, 701, 761, 829, 887, 953, 1021, 1151, 1279, + 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]; +} + +static bool tchdbseekwrite(TCHDB *hdb, off_t off, const void *buf, size_t size) { return tchdbseekwrite2(hdb, off, buf, size, 0); } - /* Seek and write data into 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 tchdbseekwrite2(TCHDB *hdb, off_t off, const void *buf, size_t size, int opts){ - assert(hdb && off >= 0 && buf && size >= 0); - if(hdb->tran && !(opts & HDBWRITENOWALL) && !tchdbwalwrite(hdb, off, size)) return false; - off_t end = off + size; - if(end >= hdb->xfsiz){ - if(!tchdbftruncate2(hdb, end, opts)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - return false; - } - } - if(end <= hdb->xmsiz){ - if (opts & HDBWRITENOLOCK) { - memcpy((void *) (hdb->map + off), buf, size); - } else { - if (!HDBLOCKSMEM(hdb, true)) return false; - memcpy((void *) (hdb->map + off), buf, size); - HDBUNLOCKSMEM(hdb); +static bool tchdbseekwrite2(TCHDB *hdb, off_t off, const void *buf, size_t size, int opts) { + assert(hdb && off >= 0 && buf && size >= 0); + if (hdb->tran && !(opts & HDBWRITENOWALL) && !tchdbwalwrite(hdb, off, size)) return false; + off_t end = off + size; + if (end >= hdb->xfsiz) { + if (!tchdbftruncate2(hdb, end, opts)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + return false; + } } - return true; - } - if(!TCUBCACHE && off < hdb->xmsiz){ - int head = hdb->xmsiz - off; - if (opts & HDBWRITENOLOCK) { - memcpy((void *) (hdb->map + off), buf, head); - } else { - if (!HDBLOCKSMEM(hdb, true)) return false; - memcpy((void *) (hdb->map + off), buf, head); - HDBUNLOCKSMEM(hdb); + if (end <= hdb->xmsiz && end <= hdb->xfsiz) { + if (opts & HDBWRITENOLOCK) { + if (hdb->map == NULL) { + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + return false; + } + memcpy((void *) (hdb->map + off), buf, size); + return true; + } else { + if (!HDBLOCKSMEM(hdb, false)) return false; + if (end <= hdb->xmsiz && end <= hdb->xfsiz) { + memcpy((void *) (hdb->map + off), buf, size); + HDBUNLOCKSMEM(hdb); + return true; + } + HDBUNLOCKSMEM(hdb); + } } - 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, tcfilerrno2tcerr(TCEWRITE), __FILE__, __LINE__, __func__); - return false; - } - } else { - if(size > 0){ - tchdbsetecode(hdb, tcfilerrno2tcerr(TCEWRITE), __FILE__, __LINE__, __func__); - return false; - } + if (!TCUBCACHE && off < hdb->xmsiz && off < hdb->xfsiz) { + int head = hdb->xmsiz - off; + if (opts & HDBWRITENOLOCK) { + if (hdb->map == NULL) { + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + return false; + } + memcpy((void *) (hdb->map + off), buf, head); + off += head; + buf = (char *) buf + head; + size -= head; + } else { + if (!HDBLOCKSMEM(hdb, false)) return false; + if (off < hdb->xmsiz && off < hdb->xfsiz) { + memcpy((void *) (hdb->map + off), buf, head); + off += head; + buf = (char *) buf + head; + size -= head; + } + HDBUNLOCKSMEM(hdb); + } + } + 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, tcfilerrno2tcerr(TCEWRITE), __FILE__, __LINE__, __func__); + return false; + } + } else { + if (size > 0) { + tchdbsetecode(hdb, tcfilerrno2tcerr(TCEWRITE), __FILE__, __LINE__, __func__); + return false; + } + } } - } - return true; + 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){ - if (!HDBLOCKSMEM(hdb, false)) return false; - memcpy(buf, (void *) (hdb->map + off), size); - HDBUNLOCKSMEM(hdb); - return true; - } - if(!TCUBCACHE && off < hdb->xmsiz){ - int head = hdb->xmsiz - off; - if (!HDBLOCKSMEM(hdb, false)) return false; - memcpy(buf, (void *) (hdb->map + off), head); - HDBUNLOCKSMEM(hdb); - 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; - } +static bool tchdbseekread(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->xmsiz && end <= hdb->xfsiz) { + if (!HDBLOCKSMEM(hdb, false)) return false; + if (end <= hdb->xmsiz && end <= hdb->xfsiz) { + memcpy(buf, (void *) (hdb->map + off), size); + HDBUNLOCKSMEM(hdb); + return true; + } + HDBUNLOCKSMEM(hdb); + } + if (!TCUBCACHE && off < hdb->xmsiz && off < hdb->xfsiz) { + int head = hdb->xmsiz - off; + if (!HDBLOCKSMEM(hdb, false)) return false; + if (off < hdb->xmsiz && off < hdb->xfsiz) { + memcpy(buf, (void *) (hdb->map + off), head); + off += head; + buf = (char *) buf + head; + size -= head; + } + HDBUNLOCKSMEM(hdb); + } + 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; + 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){ - if (!HDBLOCKSMEM(hdb, false)) return false; - memcpy(buf, (void *) (hdb->map + off), size); - HDBUNLOCKSMEM(hdb); - return true; - } - if(!TCUBCACHE && off < hdb->xmsiz){ - int head = hdb->xmsiz - off; - if (!HDBLOCKSMEM(hdb, false)) return false; - memcpy(buf, (void *)(hdb->map + off), head); - HDBUNLOCKSMEM(hdb); - 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; +static bool tchdbseekreadtry(TCHDB *hdb, off_t off, void *buf, size_t size) { + return (off + size > hdb->fsiz) ? false : tchdbseekread(hdb, off, buf, size); } - /* 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)); +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); +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->smtx = NULL; - hdb->rmtxs = NULL; - hdb->dmtx = NULL; - hdb->wmtx = NULL; - hdb->eckey = NULL; - hdb->rpath = NULL; - hdb->type = TCDBTHASH; - hdb->flags = 0; - hdb->bnum = HDBDEFBNUM; - hdb->apow = HDBDEFAPOW; - hdb->fpow = HDBDEFFPOW; - hdb->opts = 0; - hdb->path = NULL; - hdb->fd = INVALID_HANDLE_VALUE; - hdb->omode = 0; - hdb->rnum = 0; - hdb->fsiz = 0; - hdb->frec = 0; - hdb->dfcur = 0; - hdb->iter = 0; - hdb->map = NULL; - hdb->msiz = 0; - hdb->xmsiz = HDBDEFXMSIZ; - hdb->xfsiz = 0; - hdb->ba64 = false; - 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->dfunit = 0; - hdb->dfcnt = 0; - hdb->tran = false; - hdb->walfd = INVALID_HANDLE_VALUE; - hdb->walend = 0; - hdb->dbgfd = INVALID_HANDLE_VALUE; - 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; - hdb->cnt_defrag = -1; - hdb->cnt_shiftrec = -1; - hdb->cnt_trunc = -1; +static void tchdbclear(TCHDB *hdb) { + assert(hdb); + hdb->mmtx = NULL; + hdb->smtx = NULL; + hdb->rmtxs = NULL; + hdb->dmtx = NULL; + hdb->wmtx = NULL; + hdb->eckey = NULL; + hdb->rpath = NULL; + hdb->type = TCDBTHASH; + hdb->flags = 0; + hdb->bnum = HDBDEFBNUM; + hdb->apow = HDBDEFAPOW; + hdb->fpow = HDBDEFFPOW; + hdb->opts = 0; + hdb->path = NULL; + hdb->fd = INVALID_HANDLE_VALUE; + hdb->omode = 0; + hdb->rnum = 0; + hdb->fsiz = 0; + hdb->frec = 0; + hdb->dfcur = 0; + hdb->iter = 0; + hdb->map = NULL; + hdb->msiz = 0; + hdb->xmsiz = HDBDEFXMSIZ; + hdb->xfsiz = 0; + hdb->ba64 = false; + 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->dfunit = 0; + hdb->dfcnt = 0; + hdb->tran = false; + hdb->walfd = INVALID_HANDLE_VALUE; + hdb->walend = 0; + hdb->dbgfd = INVALID_HANDLE_VALUE; + +#ifndef NDEBUG + 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; + hdb->cnt_defrag = -1; + hdb->cnt_shiftrec = -1; + hdb->cnt_trunc = -1; +#endif + #ifdef _WIN32 - hdb->w32hmap = INVALID_HANDLE_VALUE; + hdb->w32hmap = INVALID_HANDLE_VALUE; #endif - 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); - TCDODEBUG(hdb->cnt_defrag = 0); - TCDODEBUG(hdb->cnt_shiftrec = 0); - TCDODEBUG(hdb->cnt_trunc = 0); + 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); + TCDODEBUG(hdb->cnt_defrag = 0); + TCDODEBUG(hdb->cnt_shiftrec = 0); + TCDODEBUG(hdb->cnt_trunc = 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; +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); - if (!HDBLOCKSMEM(hdb, true)) return; - char *fp = (char *)hdb->map + HDBFLAGSOFF; - if(sign){ - *fp |= (uint8_t)flag; - } else { - *fp &= ~(uint8_t)flag; - } - hdb->flags = *fp; - HDBUNLOCKSMEM(hdb); +static void tchdbsetflag(TCHDB *hdb, int flag, bool sign) { + assert(hdb); + if (!HDBLOCKSMEM(hdb, true)) return; + char *fp = (char *) hdb->map + HDBFLAGSOFF; + if (sign) { + *fp |= (uint8_t) flag; + } else { + *fp &= ~(uint8_t) flag; + } + hdb->flags = *fp; + HDBUNLOCKSMEM(hdb); } - /* 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; +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 (!HDBLOCKSMEM(hdb, false)) return -1; - off_t ret; - if(hdb->ba64){ - uint64_t llnum = HDBB64(hdb)[bidx]; - ret = TCITOHLL(llnum) << hdb->apow; - } else { - uint32_t lnum = HDBB32(hdb)[bidx]; - ret = (off_t)TCITOHL(lnum) << hdb->apow; - } - HDBUNLOCKSMEM(hdb); - return ret; +static off_t tchdbgetbucket(TCHDB *hdb, uint64_t bidx) { + assert(hdb && bidx >= 0); + if (!HDBLOCKSMEM(hdb, false)) return -1; + off_t ret; + if (hdb->ba64) { + uint64_t llnum = HDBB64(hdb)[bidx]; + ret = TCITOHLL(llnum) << hdb->apow; + } else { + uint32_t lnum = HDBB32(hdb)[bidx]; + ret = (off_t) TCITOHL(lnum) << hdb->apow; + } + HDBUNLOCKSMEM(hdb); + return ret; } - /* 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)); - bool l = HDBLOCKSMEM(hdb, true); - uint64_t *ba = HDBB64(hdb); - ba[bidx] = TCHTOILL(llnum); - if (l) HDBUNLOCKSMEM(hdb); - } else { - uint32_t lnum = off >> hdb->apow; - if(hdb->tran) tchdbwalwrite(hdb, HDBHEADSIZ + bidx * sizeof(lnum), sizeof(lnum)); - bool l = HDBLOCKSMEM(hdb, true); - uint32_t *ba = HDBB32(hdb); - ba[bidx] = TCHTOIL(lnum); - if (l) HDBUNLOCKSMEM(hdb); - } -} - - -/* Load the free block pool from the file. +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)); + bool l = HDBLOCKSMEM(hdb, false); + + uint64_t *ba = HDBB64(hdb); + ba[bidx] = TCHTOILL(llnum); + + if (l) HDBUNLOCKSMEM(hdb); + } else { + uint32_t lnum = off >> hdb->apow; + if (hdb->tran) tchdbwalwrite(hdb, HDBHEADSIZ + bidx * sizeof (lnum), sizeof (lnum)); + bool l = HDBLOCKSMEM(hdb, false); + + uint32_t *ba = HDBB32(hdb); + ba[bidx] = TCHTOIL(lnum); + + if (l) HDBUNLOCKSMEM(hdb); + } +} + +/* Save the free block pool into 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)){ +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 false; - } - TCFREE(buf); - return true; + return true; } - /* Save the free block pool into the file. The return value is true if successful, else, it is false. */ -static bool tchdbloadfbp(TCHDB *hdb){ - int bsiz = hdb->frec - hdb->msiz; - char *buf; - TCMALLOC(buf, bsiz); - if(!tchdbseekread(hdb, hdb->msiz, buf, bsiz)){ +static bool tchdbloadfbp(TCHDB *hdb) { + int bsiz = hdb->frec - hdb->msiz; + char *buf; + TCMALLOC(buf, bsiz); + if (!tchdbseekread(hdb, hdb->msiz, buf, bsiz)) { + TCFREE(buf); + return false; + } + const char *rp = buf; + HDBFB *cur = hdb->fbpool; + HDBFB *end = cur + hdb->fbpmax * HDBFBPALWRAT; + uint64_t base = 0; + while (cur < end && *rp != '\0') { + int step; + uint64_t llnum; + TCREADVNUMBUF64(rp, llnum, step); + base += llnum << hdb->apow; + cur->off = base; + rp += step; + uint32_t lnum; + TCREADVNUMBUF(rp, lnum, step); + cur->rsiz = lnum << hdb->apow; + rp += step; + cur++; + } + hdb->fbpnum = cur - (HDBFB *) hdb->fbpool; TCFREE(buf); - return false; - } - const char *rp = buf; - HDBFB *cur = hdb->fbpool; - HDBFB *end = cur + hdb->fbpmax * HDBFBPALWRAT; - uint64_t base = 0; - while(cur < end && *rp != '\0'){ - int step; - uint64_t llnum; - TCREADVNUMBUF64(rp, llnum, step); - base += llnum << hdb->apow; - cur->off = base; - rp += step; - uint32_t lnum; - TCREADVNUMBUF(rp, lnum, step); - cur->rsiz = lnum << hdb->apow; - rp += step; - cur++; - } - hdb->fbpnum = cur - (HDBFB *)hdb->fbpool; - TCFREE(buf); - tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); - return true; + tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); + return true; } - /* Sort the free block pool by offset. `fbpool' specifies the free block pool. `fbpnum' specifies the number of blocks. */ -static void tcfbpsortbyoff(HDBFB *fbpool, int fbpnum){ - assert(fbpool && fbpnum >= 0); - fbpnum--; - int bottom = fbpnum / 2 + 1; - int top = fbpnum; - while(bottom > 0){ - bottom--; - int mybot = bottom; - int i = mybot * 2; - while(i <= top){ - if(i < top && fbpool[i+1].off > fbpool[i].off) i++; - if(fbpool[mybot].off >= fbpool[i].off) break; - HDBFB swap = fbpool[mybot]; - fbpool[mybot] = fbpool[i]; - fbpool[i] = swap; - mybot = i; - i = mybot * 2; - } - } - while(top > 0){ - HDBFB swap = fbpool[0]; - fbpool[0] = fbpool[top]; - fbpool[top] = swap; - top--; - int mybot = bottom; - int i = mybot * 2; - while(i <= top){ - if(i < top && fbpool[i+1].off > fbpool[i].off) i++; - if(fbpool[mybot].off >= fbpool[i].off) break; - swap = fbpool[mybot]; - fbpool[mybot] = fbpool[i]; - fbpool[i] = swap; - mybot = i; - i = mybot * 2; - } - } +static void tcfbpsortbyoff(HDBFB *fbpool, int fbpnum) { + assert(fbpool && fbpnum >= 0); + fbpnum--; + int bottom = fbpnum / 2 + 1; + int top = fbpnum; + while (bottom > 0) { + bottom--; + int mybot = bottom; + int i = mybot * 2; + while (i <= top) { + if (i < top && fbpool[i + 1].off > fbpool[i].off) i++; + if (fbpool[mybot].off >= fbpool[i].off) break; + HDBFB swap = fbpool[mybot]; + fbpool[mybot] = fbpool[i]; + fbpool[i] = swap; + mybot = i; + i = mybot * 2; + } + } + while (top > 0) { + HDBFB swap = fbpool[0]; + fbpool[0] = fbpool[top]; + fbpool[top] = swap; + top--; + int mybot = bottom; + int i = mybot * 2; + while (i <= top) { + if (i < top && fbpool[i + 1].off > fbpool[i].off) i++; + if (fbpool[mybot].off >= fbpool[i].off) break; + swap = fbpool[mybot]; + fbpool[mybot] = fbpool[i]; + fbpool[i] = swap; + mybot = i; + i = mybot * 2; + } + } } - /* Sort the free block pool by record size. `fbpool' specifies the free block pool. `fbpnum' specifies the number of blocks. */ -static void tcfbpsortbyrsiz(HDBFB *fbpool, int fbpnum){ - assert(fbpool && fbpnum >= 0); - fbpnum--; - int bottom = fbpnum / 2 + 1; - int top = fbpnum; - while(bottom > 0){ - bottom--; - int mybot = bottom; - int i = mybot * 2; - while(i <= top){ - if(i < top && fbpool[i+1].rsiz > fbpool[i].rsiz) i++; - if(fbpool[mybot].rsiz >= fbpool[i].rsiz) break; - HDBFB swap = fbpool[mybot]; - fbpool[mybot] = fbpool[i]; - fbpool[i] = swap; - mybot = i; - i = mybot * 2; - } - } - while(top > 0){ - HDBFB swap = fbpool[0]; - fbpool[0] = fbpool[top]; - fbpool[top] = swap; - top--; - int mybot = bottom; - int i = mybot * 2; - while(i <= top){ - if(i < top && fbpool[i+1].rsiz > fbpool[i].rsiz) i++; - if(fbpool[mybot].rsiz >= fbpool[i].rsiz) break; - swap = fbpool[mybot]; - fbpool[mybot] = fbpool[i]; - fbpool[i] = swap; - mybot = i; - i = mybot * 2; - } - } +static void tcfbpsortbyrsiz(HDBFB *fbpool, int fbpnum) { + assert(fbpool && fbpnum >= 0); + fbpnum--; + int bottom = fbpnum / 2 + 1; + int top = fbpnum; + while (bottom > 0) { + bottom--; + int mybot = bottom; + int i = mybot * 2; + while (i <= top) { + if (i < top && fbpool[i + 1].rsiz > fbpool[i].rsiz) i++; + if (fbpool[mybot].rsiz >= fbpool[i].rsiz) break; + HDBFB swap = fbpool[mybot]; + fbpool[mybot] = fbpool[i]; + fbpool[i] = swap; + mybot = i; + i = mybot * 2; + } + } + while (top > 0) { + HDBFB swap = fbpool[0]; + fbpool[0] = fbpool[top]; + fbpool[top] = swap; + top--; + int mybot = bottom; + int i = mybot * 2; + while (i <= top) { + if (i < top && fbpool[i + 1].rsiz > fbpool[i].rsiz) i++; + if (fbpool[mybot].rsiz >= fbpool[i].rsiz) break; + swap = fbpool[mybot]; + fbpool[mybot] = fbpool[i]; + fbpool[i] = swap; + mybot = i; + i = mybot * 2; + } + } } - /* Merge successive records in the free block pool. `hdb' specifies the hash database object. */ -static void tchdbfbpmerge(TCHDB *hdb){ - assert(hdb); - TCDODEBUG(hdb->cnt_mergefbp++); - tcfbpsortbyoff(hdb->fbpool, hdb->fbpnum); - HDBFB *wp = hdb->fbpool; - HDBFB *cur = wp; - HDBFB *end = wp + hdb->fbpnum - 1; - while(cur < end){ - if(cur->off > 0){ - HDBFB *next = cur + 1; - if(cur->off + cur->rsiz == next->off && cur->rsiz + next->rsiz <= HDBFBMAXSIZ){ - if(hdb->dfcur == next->off) hdb->dfcur += next->rsiz; - if(hdb->iter == next->off) hdb->iter += next->rsiz; - cur->rsiz += next->rsiz; - next->off = 0; - } - *(wp++) = *cur; - } - cur++; - } - if(end->off > 0) *(wp++) = *end; - hdb->fbpnum = wp - (HDBFB *)hdb->fbpool; - hdb->fbpmis = hdb->fbpnum * -1; +static void tchdbfbpmerge(TCHDB *hdb) { + assert(hdb); + TCDODEBUG(hdb->cnt_mergefbp++); + tcfbpsortbyoff(hdb->fbpool, hdb->fbpnum); + HDBFB *wp = hdb->fbpool; + HDBFB *cur = wp; + HDBFB *end = wp + hdb->fbpnum - 1; + while (cur < end) { + if (cur->off > 0) { + HDBFB *next = cur + 1; + if (cur->off + cur->rsiz == next->off && cur->rsiz + next->rsiz <= HDBFBMAXSIZ) { + if (hdb->dfcur == next->off) hdb->dfcur += next->rsiz; + if (hdb->iter == next->off) hdb->iter += next->rsiz; + cur->rsiz += next->rsiz; + next->off = 0; + } + *(wp++) = *cur; + } + cur++; + } + if (end->off > 0) *(wp++) = *end; + hdb->fbpnum = wp - (HDBFB *) hdb->fbpool; + hdb->fbpmis = hdb->fbpnum * -1; } - /* Insert a block into the free block pool. `hdb' specifies the hash database object. `off' specifies the offset of the block. `rsiz' specifies the size of the block. */ -static void tchdbfbpinsert(TCHDB *hdb, uint64_t off, uint32_t rsiz){ - assert(hdb && off > 0 && rsiz > 0); - TCDODEBUG(hdb->cnt_insertfbp++); - hdb->dfcnt++; - if(hdb->fpow < 1) return; - HDBFB *pv = hdb->fbpool; - if(hdb->fbpnum >= hdb->fbpmax * HDBFBPALWRAT){ - tchdbfbpmerge(hdb); - tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); - int diff = hdb->fbpnum - hdb->fbpmax; - if(diff > 0){ - TCDODEBUG(hdb->cnt_reducefbp++); - memmove(pv, pv + diff, (hdb->fbpnum - diff) * sizeof(*pv)); - hdb->fbpnum -= diff; +static void tchdbfbpinsert(TCHDB *hdb, uint64_t off, uint32_t rsiz) { + assert(hdb && off > 0 && rsiz > 0); + TCDODEBUG(hdb->cnt_insertfbp++); + hdb->dfcnt++; + if (hdb->fpow < 1) return; + HDBFB *pv = hdb->fbpool; + if (hdb->fbpnum >= hdb->fbpmax * HDBFBPALWRAT) { + tchdbfbpmerge(hdb); + tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); + int diff = hdb->fbpnum - hdb->fbpmax; + if (diff > 0) { + TCDODEBUG(hdb->cnt_reducefbp++); + memmove(pv, pv + diff, (hdb->fbpnum - diff) * sizeof (*pv)); + hdb->fbpnum -= diff; + } + hdb->fbpmis = 0; + } + int num = hdb->fbpnum; + int left = 0; + int right = num; + int i = (left + right) / 2; + int cand = -1; + while (right >= left && i < num) { + int rv = (int) rsiz - (int) pv[i].rsiz; + if (rv == 0) { + cand = i; + break; + } else if (rv <= 0) { + cand = i; + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; } - hdb->fbpmis = 0; - } - int num = hdb->fbpnum; - int left = 0; - int right = num; - int i = (left + right) / 2; - int cand = -1; - while(right >= left && i < num){ - int rv = (int)rsiz - (int)pv[i].rsiz; - if(rv == 0){ - cand = i; - break; - } else if(rv <= 0){ - cand = i; - right = i - 1; + if (cand >= 0) { + pv += cand; + memmove(pv + 1, pv, sizeof (*pv) * (num - cand)); } else { - left = i + 1; + pv += num; } - i = (left + right) / 2; - } - if(cand >= 0){ - pv += cand; - memmove(pv + 1, pv, sizeof(*pv) * (num - cand)); - } else { - pv += num; - } - pv->off = off; - pv->rsiz = rsiz; - hdb->fbpnum++; + pv->off = off; + pv->rsiz = rsiz; + hdb->fbpnum++; } - /* Search the free block pool for the minimum region. `hdb' specifies the hash database object. `rec' specifies the record object to be stored. The return value is true if successful, else, it is false. */ -static bool tchdbfbpsearch(TCHDB *hdb, TCHREC *rec){ - assert(hdb && rec); - TCDODEBUG(hdb->cnt_searchfbp++); - if(hdb->fbpnum < 1){ +static bool tchdbfbpsearch(TCHDB *hdb, TCHREC *rec) { + assert(hdb && rec); + TCDODEBUG(hdb->cnt_searchfbp++); + if (hdb->fbpnum < 1) { + rec->off = hdb->fsiz; + rec->rsiz = 0; + return true; + } + uint32_t rsiz = rec->rsiz; + HDBFB *pv = hdb->fbpool; + int num = hdb->fbpnum; + int left = 0; + int right = num; + int i = (left + right) / 2; + int cand = -1; + while (right >= left && i < num) { + int rv = (int) rsiz - (int) pv[i].rsiz; + if (rv == 0) { + cand = i; + break; + } else if (rv <= 0) { + cand = i; + right = i - 1; + } else { + left = i + 1; + } + i = (left + right) / 2; + } + if (cand >= 0) { + pv += cand; + if (pv->rsiz > rsiz * 2) { + uint32_t psiz = tchdbpadsize(hdb, pv->off + rsiz); + uint64_t noff = pv->off + rsiz + psiz; + if (pv->rsiz >= (noff - pv->off) * 2) { + TCDODEBUG(hdb->cnt_dividefbp++); + rec->off = pv->off; + rec->rsiz = noff - pv->off; + pv->off = noff; + pv->rsiz -= rec->rsiz; + return tchdbwritefb(hdb, pv->off, pv->rsiz); + } + } + rec->off = pv->off; + rec->rsiz = pv->rsiz; + memmove(pv, pv + 1, sizeof (*pv) * (num - cand - 1)); + hdb->fbpnum--; + return true; + } rec->off = hdb->fsiz; rec->rsiz = 0; + hdb->fbpmis++; + if (hdb->fbpmis >= HDBFBPMGFREQ) { + tchdbfbpmerge(hdb); + tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); + } return true; - } - uint32_t rsiz = rec->rsiz; - HDBFB *pv = hdb->fbpool; - int num = hdb->fbpnum; - int left = 0; - int right = num; - int i = (left + right) / 2; - int cand = -1; - while(right >= left && i < num){ - int rv = (int)rsiz - (int)pv[i].rsiz; - if(rv == 0){ - cand = i; - break; - } else if(rv <= 0){ - cand = i; - right = i - 1; - } else { - left = i + 1; - } - i = (left + right) / 2; - } - if(cand >= 0){ - pv += cand; - if(pv->rsiz > rsiz * 2){ - uint32_t psiz = tchdbpadsize(hdb, pv->off + rsiz); - uint64_t noff = pv->off + rsiz + psiz; - if(pv->rsiz >= (noff - pv->off) * 2){ - TCDODEBUG(hdb->cnt_dividefbp++); - rec->off = pv->off; - rec->rsiz = noff - pv->off; - pv->off = noff; - pv->rsiz -= rec->rsiz; - return tchdbwritefb(hdb, pv->off, pv->rsiz); - } - } - rec->off = pv->off; - rec->rsiz = pv->rsiz; - memmove(pv, pv + 1, sizeof(*pv) * (num - cand - 1)); - hdb->fbpnum--; - return true; - } - rec->off = hdb->fsiz; - rec->rsiz = 0; - hdb->fbpmis++; - if(hdb->fbpmis >= HDBFBPMGFREQ){ - tchdbfbpmerge(hdb); - tcfbpsortbyrsiz(hdb->fbpool, hdb->fbpnum); - } - return true; } - /* Splice the trailing free block `hdb' specifies the hash database object. `rec' specifies the record object to be stored. `nsiz' specifies the needed size. The return value is whether splicing succeeded or not. */ -static bool tchdbfbpsplice(TCHDB *hdb, TCHREC *rec, uint32_t nsiz){ - assert(hdb && rec && nsiz > 0); - if(hdb->mmtx){ - if(hdb->fbpnum < 1) return false; +static bool tchdbfbpsplice(TCHDB *hdb, TCHREC *rec, uint32_t nsiz) { + assert(hdb && rec && nsiz > 0); + if (hdb->mmtx) { + if (hdb->fbpnum < 1) return false; + uint64_t off = rec->off + rec->rsiz; + uint32_t rsiz = rec->rsiz; + uint8_t magic; + if (tchdbseekreadtry(hdb, off, &magic, sizeof (magic)) && magic != HDBMAGICFB) return false; + HDBFB *pv = hdb->fbpool; + HDBFB *ep = pv + hdb->fbpnum; + while (pv < ep) { + if (pv->off == off && rsiz + pv->rsiz >= nsiz) { + if (hdb->dfcur == pv->off) hdb->dfcur += pv->rsiz; + if (hdb->iter == pv->off) hdb->iter += pv->rsiz; + rec->rsiz += pv->rsiz; + memmove(pv, pv + 1, sizeof (*pv) * ((ep - pv) - 1)); + hdb->fbpnum--; + return true; + } + pv++; + } + return false; + } uint64_t off = rec->off + rec->rsiz; - uint32_t rsiz = rec->rsiz; - uint8_t magic; - if(tchdbseekreadtry(hdb, off, &magic, sizeof(magic)) && magic != HDBMAGICFB) return false; - HDBFB *pv = hdb->fbpool; - HDBFB *ep = pv + hdb->fbpnum; - while(pv < ep){ - if(pv->off == off && rsiz + pv->rsiz >= nsiz){ - if(hdb->dfcur == pv->off) hdb->dfcur += pv->rsiz; - if(hdb->iter == pv->off) hdb->iter += pv->rsiz; - rec->rsiz += pv->rsiz; - memmove(pv, pv + 1, sizeof(*pv) * ((ep - pv) - 1)); - hdb->fbpnum--; - return true; - } - pv++; + TCHREC nrec; + char nbuf[HDBIOBUFSIZ]; + while (off < hdb->fsiz) { + nrec.off = off; + if (!tchdbreadrec(hdb, &nrec, nbuf)) return false; + if (nrec.magic != HDBMAGICFB) break; + if (hdb->dfcur == off) hdb->dfcur += nrec.rsiz; + if (hdb->iter == off) hdb->iter += nrec.rsiz; + off += nrec.rsiz; + } + uint32_t jsiz = off - rec->off; + if (jsiz < nsiz) return false; + rec->rsiz = jsiz; + uint64_t base = rec->off; + HDBFB *wp = hdb->fbpool; + HDBFB *cur = wp; + HDBFB *end = wp + hdb->fbpnum; + while (cur < end) { + if (cur->off < base || cur->off > off) *(wp++) = *cur; + cur++; + } + hdb->fbpnum = wp - (HDBFB *) hdb->fbpool; + if (jsiz > nsiz * 2) { + uint32_t psiz = tchdbpadsize(hdb, rec->off + nsiz); + uint64_t noff = rec->off + nsiz + psiz; + if (jsiz >= (noff - rec->off) * 2) { + TCDODEBUG(hdb->cnt_dividefbp++); + nsiz = off - noff; + if (!tchdbwritefb(hdb, noff, nsiz)) return false; + rec->rsiz = noff - rec->off; + tchdbfbpinsert(hdb, noff, nsiz); + } } - return false; - } - uint64_t off = rec->off + rec->rsiz; - TCHREC nrec; - char nbuf[HDBIOBUFSIZ]; - while(off < hdb->fsiz){ - nrec.off = off; - if(!tchdbreadrec(hdb, &nrec, nbuf)) return false; - if(nrec.magic != HDBMAGICFB) break; - if(hdb->dfcur == off) hdb->dfcur += nrec.rsiz; - if(hdb->iter == off) hdb->iter += nrec.rsiz; - off += nrec.rsiz; - } - uint32_t jsiz = off - rec->off; - if(jsiz < nsiz) return false; - rec->rsiz = jsiz; - uint64_t base = rec->off; - HDBFB *wp = hdb->fbpool; - HDBFB *cur = wp; - HDBFB *end = wp + hdb->fbpnum; - while(cur < end){ - if(cur->off < base || cur->off > off) *(wp++) = *cur; - cur++; - } - hdb->fbpnum = wp - (HDBFB *)hdb->fbpool; - if(jsiz > nsiz * 2){ - uint32_t psiz = tchdbpadsize(hdb, rec->off + nsiz); - uint64_t noff = rec->off + nsiz + psiz; - if(jsiz >= (noff - rec->off) * 2){ - TCDODEBUG(hdb->cnt_dividefbp++); - nsiz = off - noff; - if(!tchdbwritefb(hdb, noff, nsiz)) return false; - rec->rsiz = noff - rec->off; - tchdbfbpinsert(hdb, noff, nsiz); - } - } - return true; + return true; } - /* Remove blocks of a region from the free block pool. `hdb' specifies the hash database object. `base' specifies the base offset of the region. `next' specifies the offset of the next region. `off' specifies the offset of the block. `rsiz' specifies the size of the block. */ -static void tchdbfbptrim(TCHDB *hdb, uint64_t base, uint64_t next, uint64_t off, uint32_t rsiz){ - assert(hdb && base > 0 && next > 0); - if(hdb->fpow < 1) return; - if(hdb->fbpnum < 1){ - if(off > 0){ - HDBFB *fbpool = hdb->fbpool; - fbpool->off = off; - fbpool->rsiz = rsiz; - hdb->fbpnum = 1; - } - return; - } - HDBFB *wp = hdb->fbpool; - HDBFB *cur = wp; - HDBFB *end = wp + hdb->fbpnum; - if(hdb->fbpnum >= hdb->fbpmax * HDBFBPALWRAT) cur++; - while(cur < end){ - if(cur->rsiz >= rsiz && off > 0){ - TCDODEBUG(hdb->cnt_insertfbp++); - wp->off = off; - wp->rsiz = rsiz; - wp++; - off = 0; - } else if(cur->off < base || cur->off >= next){ - *(wp++) = *cur; - } - cur++; - } - if(off > 0){ - TCDODEBUG(hdb->cnt_insertfbp++); - wp->off = off; - wp->rsiz = rsiz; - wp++; - off = 0; - } - hdb->fbpnum = wp - (HDBFB *)hdb->fbpool; +static void tchdbfbptrim(TCHDB *hdb, uint64_t base, uint64_t next, uint64_t off, uint32_t rsiz) { + assert(hdb && base > 0 && next > 0); + if (hdb->fpow < 1) return; + if (hdb->fbpnum < 1) { + if (off > 0) { + HDBFB *fbpool = hdb->fbpool; + fbpool->off = off; + fbpool->rsiz = rsiz; + hdb->fbpnum = 1; + } + return; + } + HDBFB *wp = hdb->fbpool; + HDBFB *cur = wp; + HDBFB *end = wp + hdb->fbpnum; + if (hdb->fbpnum >= hdb->fbpmax * HDBFBPALWRAT) cur++; + while (cur < end) { + if (cur->rsiz >= rsiz && off > 0) { + TCDODEBUG(hdb->cnt_insertfbp++); + wp->off = off; + wp->rsiz = rsiz; + wp++; + off = 0; + } else if (cur->off < base || cur->off >= next) { + *(wp++) = *cur; + } + cur++; + } + if (off > 0) { + TCDODEBUG(hdb->cnt_insertfbp++); + wp->off = off; + wp->rsiz = rsiz; + wp++; + off = 0; + } + hdb->fbpnum = wp - (HDBFB *) hdb->fbpool; } - /* Write a free block into the file. `hdb' specifies the hash database object. `off' specifies the offset of the block. `rsiz' specifies the size of the block. The return value is true if successful, else, it is false. */ -static bool tchdbwritefb(TCHDB *hdb, uint64_t off, uint32_t rsiz){ - assert(hdb && off > 0 && rsiz > 0); - char rbuf[HDBMAXHSIZ]; - char *wp = rbuf; - *(uint8_t *)(wp++) = HDBMAGICFB; - uint32_t lnum = TCHTOIL(rsiz); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - return tchdbseekwrite(hdb, off, rbuf, wp - rbuf); +static bool tchdbwritefb(TCHDB *hdb, uint64_t off, uint32_t rsiz) { + assert(hdb && off > 0 && rsiz > 0); + char rbuf[HDBMAXHSIZ]; + char *wp = rbuf; + *(uint8_t *) (wp++) = HDBMAGICFB; + uint32_t lnum = TCHTOIL(rsiz); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + return tchdbseekwrite(hdb, off, rbuf, wp - rbuf); } - /* Write a record into the file. `hdb' specifies the hash database object. `rec' specifies the record object. `bidx' specifies the index of the bucket. `entoff' specifies the offset of the tree entry. The return value is true if successful, else, it is false. */ -static bool tchdbwriterec(TCHDB *hdb, TCHREC *rec, uint64_t bidx, off_t entoff){ - assert(hdb && rec); - TCDODEBUG(hdb->cnt_writerec++); - char stack[HDBIOBUFSIZ]; - int bsiz = (rec->rsiz > 0) ? rec->rsiz : HDBMAXHSIZ + rec->ksiz + rec->vsiz + hdb->align; - char *rbuf; - if(bsiz <= HDBIOBUFSIZ){ - rbuf = stack; - } else { - TCMALLOC(rbuf, bsiz); - } - char *wp = rbuf; - *(uint8_t *)(wp++) = HDBMAGICREC; - *(uint8_t *)(wp++) = rec->hash; - if(hdb->ba64){ - uint64_t llnum; - llnum = rec->left >> hdb->apow; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - llnum = rec->right >> hdb->apow; - llnum = TCHTOILL(llnum); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - } else { - uint32_t lnum; - lnum = rec->left >> hdb->apow; - lnum = TCHTOIL(lnum); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - lnum = rec->right >> hdb->apow; - lnum = TCHTOIL(lnum); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - } - uint16_t snum; - char *pwp = wp; - wp += sizeof(snum); - int step; - TCSETVNUMBUF(step, wp, rec->ksiz); - wp += step; - TCSETVNUMBUF(step, wp, rec->vsiz); - wp += step; - int32_t hsiz = wp - rbuf; - int32_t rsiz = hsiz + rec->ksiz + rec->vsiz; - int32_t finc = 0; - if(rec->rsiz < 1){ - uint16_t psiz = tchdbpadsize(hdb, hdb->fsiz + rsiz); - rec->rsiz = rsiz + psiz; - rec->psiz = psiz; - finc = rec->rsiz; - } else if(rsiz > rec->rsiz){ - if(rbuf != stack) TCFREE(rbuf); - if(!HDBLOCKDB(hdb)) return false; - if(tchdbfbpsplice(hdb, rec, rsiz)){ - TCDODEBUG(hdb->cnt_splicefbp++); - bool rv = tchdbwriterec(hdb, rec, bidx, entoff); - HDBUNLOCKDB(hdb); - return rv; - } - TCDODEBUG(hdb->cnt_moverec++); - if(!tchdbwritefb(hdb, rec->off, rec->rsiz)){ - HDBUNLOCKDB(hdb); - return false; +static bool tchdbwriterec(TCHDB *hdb, TCHREC *rec, uint64_t bidx, off_t entoff) { + assert(hdb && rec); + TCDODEBUG(hdb->cnt_writerec++); + char stack[HDBIOBUFSIZ]; + int bsiz = (rec->rsiz > 0) ? rec->rsiz : HDBMAXHSIZ + rec->ksiz + rec->vsiz + hdb->align; + char *rbuf; + if (bsiz <= HDBIOBUFSIZ) { + rbuf = stack; + } else { + TCMALLOC(rbuf, bsiz); + } + char *wp = rbuf; + *(uint8_t *) (wp++) = HDBMAGICREC; + *(uint8_t *) (wp++) = rec->hash; + if (hdb->ba64) { + uint64_t llnum; + llnum = rec->left >> hdb->apow; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + llnum = rec->right >> hdb->apow; + llnum = TCHTOILL(llnum); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + } else { + uint32_t lnum; + lnum = rec->left >> hdb->apow; + lnum = TCHTOIL(lnum); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + lnum = rec->right >> hdb->apow; + lnum = TCHTOIL(lnum); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + } + uint16_t snum; + char *pwp = wp; + wp += sizeof (snum); + int step; + TCSETVNUMBUF(step, wp, rec->ksiz); + wp += step; + TCSETVNUMBUF(step, wp, rec->vsiz); + wp += step; + int32_t hsiz = wp - rbuf; + int32_t rsiz = hsiz + rec->ksiz + rec->vsiz; + int32_t finc = 0; + if (rec->rsiz < 1) { + uint16_t psiz = tchdbpadsize(hdb, hdb->fsiz + rsiz); + rec->rsiz = rsiz + psiz; + rec->psiz = psiz; + finc = rec->rsiz; + } else if (rsiz > rec->rsiz) { + if (rbuf != stack) TCFREE(rbuf); + if (!HDBLOCKDB(hdb)) return false; + if (tchdbfbpsplice(hdb, rec, rsiz)) { + TCDODEBUG(hdb->cnt_splicefbp++); + bool rv = tchdbwriterec(hdb, rec, bidx, entoff); + HDBUNLOCKDB(hdb); + return rv; + } + TCDODEBUG(hdb->cnt_moverec++); + if (!tchdbwritefb(hdb, rec->off, rec->rsiz)) { + HDBUNLOCKDB(hdb); + return false; + } + tchdbfbpinsert(hdb, rec->off, rec->rsiz); + rec->rsiz = rsiz; + if (!tchdbfbpsearch(hdb, rec)) { + HDBUNLOCKDB(hdb); + return false; + } + bool rv = tchdbwriterec(hdb, rec, bidx, entoff); + HDBUNLOCKDB(hdb); + return rv; + } else { + TCDODEBUG(hdb->cnt_reuserec++); + uint32_t psiz = rec->rsiz - rsiz; + if (psiz > UINT16_MAX) { + TCDODEBUG(hdb->cnt_dividefbp++); + psiz = tchdbpadsize(hdb, rec->off + rsiz); + uint64_t noff = rec->off + rsiz + psiz; + uint32_t nsiz = rec->rsiz - rsiz - psiz; + rec->rsiz = noff - rec->off; + rec->psiz = psiz; + if (!tchdbwritefb(hdb, noff, nsiz)) { + if (rbuf != stack) TCFREE(rbuf); + return false; + } + if (!HDBLOCKDB(hdb)) { + if (rbuf != stack) TCFREE(rbuf); + return false; + } + tchdbfbpinsert(hdb, noff, nsiz); + HDBUNLOCKDB(hdb); + } + rec->psiz = psiz; + } + snum = rec->psiz; + snum = TCHTOIS(snum); + memcpy(pwp, &snum, sizeof (snum)); + rsiz = rec->rsiz; + rsiz -= hsiz; + memcpy(wp, rec->kbuf, rec->ksiz); + wp += rec->ksiz; + rsiz -= rec->ksiz; + memcpy(wp, rec->vbuf, rec->vsiz); + wp += rec->vsiz; + rsiz -= rec->vsiz; + memset(wp, 0, rsiz); + if (!tchdbseekwrite(hdb, rec->off, rbuf, rec->rsiz)) { + if (rbuf != stack) TCFREE(rbuf); + return false; } - tchdbfbpinsert(hdb, rec->off, rec->rsiz); - rec->rsiz = rsiz; - if(!tchdbfbpsearch(hdb, rec)){ - HDBUNLOCKDB(hdb); - return false; + if (finc != 0) { + hdb->fsiz += finc; + uint64_t llnum = hdb->fsiz; + llnum = TCHTOILL(llnum); + if (!HDBLOCKSMEM(hdb, false)) return false; + memcpy((void *) (hdb->map + HDBFSIZOFF), &llnum, sizeof (llnum)); + HDBUNLOCKSMEM(hdb); } - bool rv = tchdbwriterec(hdb, rec, bidx, entoff); - HDBUNLOCKDB(hdb); - return rv; - } else { - TCDODEBUG(hdb->cnt_reuserec++); - uint32_t psiz = rec->rsiz - rsiz; - if(psiz > UINT16_MAX){ - TCDODEBUG(hdb->cnt_dividefbp++); - psiz = tchdbpadsize(hdb, rec->off + rsiz); - uint64_t noff = rec->off + rsiz + psiz; - uint32_t nsiz = rec->rsiz - rsiz - psiz; - rec->rsiz = noff - rec->off; - rec->psiz = psiz; - if(!tchdbwritefb(hdb, noff, nsiz)){ - if(rbuf != stack) TCFREE(rbuf); - return false; - } - if(!HDBLOCKDB(hdb)){ - if(rbuf != stack) TCFREE(rbuf); - return false; - } - tchdbfbpinsert(hdb, noff, nsiz); - HDBUNLOCKDB(hdb); - } - rec->psiz = psiz; - } - snum = rec->psiz; - snum = TCHTOIS(snum); - memcpy(pwp, &snum, sizeof(snum)); - rsiz = rec->rsiz; - rsiz -= hsiz; - memcpy(wp, rec->kbuf, rec->ksiz); - wp += rec->ksiz; - rsiz -= rec->ksiz; - memcpy(wp, rec->vbuf, rec->vsiz); - wp += rec->vsiz; - rsiz -= rec->vsiz; - memset(wp, 0, rsiz); - if(!tchdbseekwrite(hdb, rec->off, rbuf, rec->rsiz)){ - if(rbuf != stack) TCFREE(rbuf); - return false; - } - if(finc != 0){ - hdb->fsiz += finc; - uint64_t llnum = hdb->fsiz; - llnum = TCHTOILL(llnum); - if (!HDBLOCKSMEM(hdb, true)) return false; - memcpy((void *)(hdb->map + HDBFSIZOFF), &llnum, sizeof(llnum)); - HDBUNLOCKSMEM(hdb); - } - if(rbuf != stack) TCFREE(rbuf); - if(entoff > 0){ - if(hdb->ba64){ - uint64_t llnum = rec->off >> hdb->apow; - llnum = TCHTOILL(llnum); - if(!tchdbseekwrite(hdb, entoff, &llnum, sizeof(uint64_t))) return false; + if (rbuf != stack) TCFREE(rbuf); + if (entoff > 0) { + if (hdb->ba64) { + uint64_t llnum = rec->off >> hdb->apow; + llnum = TCHTOILL(llnum); + if (!tchdbseekwrite(hdb, entoff, &llnum, sizeof (uint64_t))) return false; + } else { + uint32_t lnum = rec->off >> hdb->apow; + lnum = TCHTOIL(lnum); + if (!tchdbseekwrite(hdb, entoff, &lnum, sizeof (uint32_t))) return false; + } } else { - uint32_t lnum = rec->off >> hdb->apow; - lnum = TCHTOIL(lnum); - if(!tchdbseekwrite(hdb, entoff, &lnum, sizeof(uint32_t))) return false; + tchdbsetbucket(hdb, bidx, rec->off); } - } else { - tchdbsetbucket(hdb, bidx, rec->off); - } - return true; + return true; } - /* Read a record from the file. `hdb' specifies the hash database object. `rec' specifies the record object. `rbuf' specifies the buffer for reading. The return value is true if successful, else, it is false. */ -static bool tchdbreadrec(TCHDB *hdb, TCHREC *rec, char *rbuf){ - assert(hdb && rec && rbuf); - TCDODEBUG(hdb->cnt_readrec++); - int rsiz = hdb->runit; - if(!tchdbseekreadtry(hdb, rec->off, rbuf, rsiz)){ - if(!HDBLOCKDB(hdb)) return false; - rsiz = hdb->fsiz - rec->off; - if(rsiz > hdb->runit){ - rsiz = hdb->runit; - } else if(rsiz < (int)(sizeof(uint8_t) + sizeof(uint32_t))){ - tchdbsetecode(hdb, TCERHEAD, __FILE__, __LINE__, __func__); - HDBUNLOCKDB(hdb); - return false; - } - if(!tchdbseekread(hdb, rec->off, rbuf, rsiz)){ - HDBUNLOCKDB(hdb); - return false; +static bool tchdbreadrec(TCHDB *hdb, TCHREC *rec, char *rbuf) { + assert(hdb && rec && rbuf); + TCDODEBUG(hdb->cnt_readrec++); + int rsiz = hdb->runit; + if (!tchdbseekreadtry(hdb, rec->off, rbuf, rsiz)) { + if (!HDBLOCKDB(hdb)) return false; + rsiz = hdb->fsiz - rec->off; + if (rsiz > hdb->runit) { + rsiz = hdb->runit; + } else if (rsiz < (int) (sizeof (uint8_t) + sizeof (uint32_t))) { + tchdbsetecode(hdb, TCERHEAD, __FILE__, __LINE__, __func__); + HDBUNLOCKDB(hdb); + return false; + } + if (!tchdbseekread(hdb, rec->off, rbuf, rsiz)) { + HDBUNLOCKDB(hdb); + return false; + } + HDBUNLOCKDB(hdb); + } + const char *rp = rbuf; + rec->magic = *(uint8_t *) (rp++); + if (rec->magic == HDBMAGICFB) { + uint32_t lnum; + memcpy(&lnum, rp, sizeof (lnum)); + rec->rsiz = TCITOHL(lnum); + return true; + } else if (rec->magic != HDBMAGICREC) { + tchdbsetecode(hdb, TCERHEAD, __FILE__, __LINE__, __func__); + return false; } - HDBUNLOCKDB(hdb); - } - const char *rp = rbuf; - rec->magic = *(uint8_t *)(rp++); - if(rec->magic == HDBMAGICFB){ + rec->hash = *(uint8_t *) (rp++); + if (hdb->ba64) { + uint64_t llnum; + memcpy(&llnum, rp, sizeof (llnum)); + rec->left = TCITOHLL(llnum) << hdb->apow; + rp += sizeof (llnum); + memcpy(&llnum, rp, sizeof (llnum)); + rec->right = TCITOHLL(llnum) << hdb->apow; + rp += sizeof (llnum); + } else { + uint32_t lnum; + memcpy(&lnum, rp, sizeof (lnum)); + rec->left = (uint64_t) TCITOHL(lnum) << hdb->apow; + rp += sizeof (lnum); + memcpy(&lnum, rp, sizeof (lnum)); + rec->right = (uint64_t) TCITOHL(lnum) << hdb->apow; + rp += sizeof (lnum); + } + uint16_t snum; + memcpy(&snum, rp, sizeof (snum)); + rec->psiz = TCITOHS(snum); + rp += sizeof (snum); uint32_t lnum; - memcpy(&lnum, rp, sizeof(lnum)); - rec->rsiz = TCITOHL(lnum); + int step; + TCREADVNUMBUF(rp, lnum, step); + rec->ksiz = lnum; + rp += step; + TCREADVNUMBUF(rp, lnum, step); + rec->vsiz = lnum; + rp += step; + int32_t hsiz = rp - rbuf; + rec->rsiz = hsiz + rec->ksiz + rec->vsiz + rec->psiz; + rec->kbuf = NULL; + rec->vbuf = NULL; + rec->boff = rec->off + hsiz; + rec->bbuf = NULL; + rsiz -= hsiz; + if (rsiz >= rec->ksiz) { + rec->kbuf = rp; + rsiz -= rec->ksiz; + rp += rec->ksiz; + if (rsiz >= rec->vsiz) rec->vbuf = rp; + } return true; - } else if(rec->magic != HDBMAGICREC){ - tchdbsetecode(hdb, TCERHEAD, __FILE__, __LINE__, __func__); - return false; - } - rec->hash = *(uint8_t *)(rp++); - if(hdb->ba64){ - uint64_t llnum; - memcpy(&llnum, rp, sizeof(llnum)); - rec->left = TCITOHLL(llnum) << hdb->apow; - rp += sizeof(llnum); - memcpy(&llnum, rp, sizeof(llnum)); - rec->right = TCITOHLL(llnum) << hdb->apow; - rp += sizeof(llnum); - } else { - uint32_t lnum; - memcpy(&lnum, rp, sizeof(lnum)); - rec->left = (uint64_t)TCITOHL(lnum) << hdb->apow; - rp += sizeof(lnum); - memcpy(&lnum, rp, sizeof(lnum)); - rec->right = (uint64_t)TCITOHL(lnum) << hdb->apow; - rp += sizeof(lnum); - } - uint16_t snum; - memcpy(&snum, rp, sizeof(snum)); - rec->psiz = TCITOHS(snum); - rp += sizeof(snum); - uint32_t lnum; - int step; - TCREADVNUMBUF(rp, lnum, step); - rec->ksiz = lnum; - rp += step; - TCREADVNUMBUF(rp, lnum, step); - rec->vsiz = lnum; - rp += step; - int32_t hsiz = rp - rbuf; - rec->rsiz = hsiz + rec->ksiz + rec->vsiz + rec->psiz; - rec->kbuf = NULL; - rec->vbuf = NULL; - rec->boff = rec->off + hsiz; - rec->bbuf = NULL; - rsiz -= hsiz; - if(rsiz >= rec->ksiz){ - rec->kbuf = rp; - rsiz -= rec->ksiz; - rp += rec->ksiz; - if(rsiz >= rec->vsiz) rec->vbuf = rp; - } - return true; } - /* Read the body of a record from the file. `hdb' specifies the hash database object. `rec' specifies the record object. The return value is true if successful, else, it is false. */ -static bool tchdbreadrecbody(TCHDB *hdb, TCHREC *rec){ - assert(hdb && rec); - int32_t bsiz = rec->ksiz + rec->vsiz; - TCMALLOC(rec->bbuf, bsiz + 1); - if(!tchdbseekread(hdb, rec->boff, rec->bbuf, bsiz)) return false; - rec->kbuf = rec->bbuf; - rec->vbuf = rec->bbuf + rec->ksiz; - return true; +static bool tchdbreadrecbody(TCHDB *hdb, TCHREC *rec) { + assert(hdb && rec); + int32_t bsiz = rec->ksiz + rec->vsiz; + TCMALLOC(rec->bbuf, bsiz + 1); + if (!tchdbseekread(hdb, rec->boff, rec->bbuf, bsiz)) return false; + rec->kbuf = rec->bbuf; + rec->vbuf = rec->bbuf + rec->ksiz; + return true; } - /* Remove a record from the file. `hdb' specifies the hash database object. `rec' specifies the record object. @@ -3136,328 +3053,324 @@ static bool tchdbreadrecbody(TCHDB *hdb, TCHREC *rec){ `bidx' specifies the index of the bucket. `entoff' specifies the offset of the tree entry. The return value is true if successful, else, it is false. */ -static bool tchdbremoverec(TCHDB *hdb, TCHREC *rec, char *rbuf, uint64_t bidx, off_t entoff){ - assert(hdb && rec); - bool err = false; - if(!tchdbwritefb(hdb, rec->off, rec->rsiz)) return false; - if(!HDBLOCKDB(hdb)) return false; - tchdbfbpinsert(hdb, rec->off, rec->rsiz); - HDBUNLOCKDB(hdb); - uint64_t child; - if(rec->left > 0 && rec->right < 1){ - child = rec->left; - } else if(rec->left < 1 && rec->right > 0){ - child = rec->right; - } else if(rec->left < 1){ - child = 0; - } else { - child = rec->left; - uint64_t right = rec->right; - rec->right = child; - while(rec->right > 0){ - rec->off = rec->right; - if(!tchdbreadrec(hdb, rec, rbuf)) return false; - } - if(hdb->ba64){ - off_t toff = rec->off + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t)); - uint64_t llnum = right >> hdb->apow; - llnum = TCHTOILL(llnum); - if(!tchdbseekwrite(hdb, toff, &llnum, sizeof(uint64_t))) return false; +static bool tchdbremoverec(TCHDB *hdb, TCHREC *rec, char *rbuf, uint64_t bidx, off_t entoff) { + assert(hdb && rec); + bool err = false; + if (!tchdbwritefb(hdb, rec->off, rec->rsiz)) return false; + if (!HDBLOCKDB(hdb)) return false; + tchdbfbpinsert(hdb, rec->off, rec->rsiz); + HDBUNLOCKDB(hdb); + uint64_t child; + if (rec->left > 0 && rec->right < 1) { + child = rec->left; + } else if (rec->left < 1 && rec->right > 0) { + child = rec->right; + } else if (rec->left < 1) { + child = 0; + } else { + child = rec->left; + uint64_t right = rec->right; + rec->right = child; + while (rec->right > 0) { + rec->off = rec->right; + if (!tchdbreadrec(hdb, rec, rbuf)) return false; + } + if (hdb->ba64) { + off_t toff = rec->off + (sizeof (uint8_t) + sizeof (uint8_t) + sizeof (uint64_t)); + uint64_t llnum = right >> hdb->apow; + llnum = TCHTOILL(llnum); + if (!tchdbseekwrite(hdb, toff, &llnum, sizeof (uint64_t))) return false; + } else { + off_t toff = rec->off + (sizeof (uint8_t) + sizeof (uint8_t) + sizeof (uint32_t)); + uint32_t lnum = right >> hdb->apow; + lnum = TCHTOIL(lnum); + if (!tchdbseekwrite(hdb, toff, &lnum, sizeof (uint32_t))) return false; + } + } + if (entoff > 0) { + if (hdb->ba64) { + uint64_t llnum = child >> hdb->apow; + llnum = TCHTOILL(llnum); + if (!tchdbseekwrite(hdb, entoff, &llnum, sizeof (uint64_t))) return false; + } else { + uint32_t lnum = child >> hdb->apow; + lnum = TCHTOIL(lnum); + if (!tchdbseekwrite(hdb, entoff, &lnum, sizeof (uint32_t))) return false; + } } else { - off_t toff = rec->off + (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t)); - uint32_t lnum = right >> hdb->apow; - lnum = TCHTOIL(lnum); - if(!tchdbseekwrite(hdb, toff, &lnum, sizeof(uint32_t))) return false; - } - } - if(entoff > 0){ - if(hdb->ba64){ - uint64_t llnum = child >> hdb->apow; - llnum = TCHTOILL(llnum); - if(!tchdbseekwrite(hdb, entoff, &llnum, sizeof(uint64_t))) return false; + tchdbsetbucket(hdb, bidx, child); + } + if (!HDBLOCKDB(hdb)) return false; + hdb->rnum--; + uint64_t llnum = hdb->rnum; + llnum = TCHTOILL(llnum); + if (HDBLOCKSMEM(hdb, false)) { + memcpy((void *) (hdb->map + HDBRNUMOFF), &llnum, sizeof (llnum)); + HDBUNLOCKSMEM(hdb); } else { - uint32_t lnum = child >> hdb->apow; - lnum = TCHTOIL(lnum); - if(!tchdbseekwrite(hdb, entoff, &lnum, sizeof(uint32_t))) return false; - } - } else { - tchdbsetbucket(hdb, bidx, child); - } - if(!HDBLOCKDB(hdb)) return false; - hdb->rnum--; - uint64_t llnum = hdb->rnum; - llnum = TCHTOILL(llnum); - if (HDBLOCKSMEM(hdb, true)) { - memcpy((void *)(hdb->map + HDBRNUMOFF), &llnum, sizeof(llnum)); - HDBUNLOCKSMEM(hdb); - } else { - err = true; - } - HDBUNLOCKDB(hdb); - return !err; + err = true; + } + HDBUNLOCKDB(hdb); + return !err; } - /* Remove a record from the file. `hdb' specifies the hash database object. `rec' specifies the record object. `rbuf' specifies the buffer for reading. `destoff' specifies the offset of the destination. The return value is true if successful, else, it is false. */ -static bool tchdbshiftrec(TCHDB *hdb, TCHREC *rec, char *rbuf, off_t destoff){ - assert(hdb && rec && rbuf && destoff >= 0); - TCDODEBUG(hdb->cnt_shiftrec++); - if(!rec->vbuf && !tchdbreadrecbody(hdb, rec)) { - return false; - } - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, rec->kbuf, rec->ksiz, &hash); - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return false; - if(rec->off == off){ - bool err = false; - rec->off = destoff; - if(!tchdbwriterec(hdb, rec, bidx, 0)) err = true; - TCFREE(rec->bbuf); - rec->kbuf = NULL; - rec->vbuf = NULL; - rec->bbuf = NULL; - return !err; - } - TCHREC trec; - char tbuf[HDBIOBUFSIZ]; - char *bbuf = rec->bbuf; - const char *kbuf = rec->kbuf; - int ksiz = rec->ksiz; - const char *vbuf = rec->vbuf; - int vsiz = rec->vsiz; - rec->kbuf = NULL; - rec->vbuf = NULL; - rec->bbuf = NULL; - off_t entoff = 0; - while(off > 0){ - trec.off = off; - if(!tchdbreadrec(hdb, &trec, tbuf)){ - TCFREE(bbuf); - return false; - } - if(hash > trec.hash){ - off = trec.left; - entoff = trec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(hash < trec.hash){ - off = trec.right; - entoff = trec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - if(!trec.kbuf && !tchdbreadrecbody(hdb, &trec)){ - TCFREE(bbuf); +static bool tchdbshiftrec(TCHDB *hdb, TCHREC *rec, char *rbuf, off_t destoff) { + assert(hdb && rec && rbuf && destoff >= 0); + TCDODEBUG(hdb->cnt_shiftrec++); + if (!rec->vbuf && !tchdbreadrecbody(hdb, rec)) { return false; - } - int kcmp = tcreckeycmp(kbuf, ksiz, trec.kbuf, trec.ksiz); - if(kcmp > 0){ - off = trec.left; - TCFREE(trec.bbuf); - trec.kbuf = NULL; - trec.bbuf = NULL; - entoff = trec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(kcmp < 0){ - off = trec.right; - TCFREE(trec.bbuf); - trec.kbuf = NULL; - trec.bbuf = NULL; - entoff = trec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - TCFREE(trec.bbuf); - trec.bbuf = NULL; + } + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, rec->kbuf, rec->ksiz, &hash); + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return false; + if (rec->off == off) { bool err = false; rec->off = destoff; - rec->kbuf = kbuf; - rec->ksiz = ksiz; - rec->vbuf = vbuf; - rec->vsiz = vsiz; - if(!tchdbwriterec(hdb, rec, bidx, entoff)) err = true; - TCFREE(bbuf); + if (!tchdbwriterec(hdb, rec, bidx, 0)) err = true; + TCFREE(rec->bbuf); + rec->kbuf = NULL; + rec->vbuf = NULL; + rec->bbuf = NULL; return !err; - } } - } - TCFREE(bbuf); - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; + TCHREC trec; + char tbuf[HDBIOBUFSIZ]; + char *bbuf = rec->bbuf; + const char *kbuf = rec->kbuf; + int ksiz = rec->ksiz; + const char *vbuf = rec->vbuf; + int vsiz = rec->vsiz; + rec->kbuf = NULL; + rec->vbuf = NULL; + rec->bbuf = NULL; + off_t entoff = 0; + while (off > 0) { + trec.off = off; + if (!tchdbreadrec(hdb, &trec, tbuf)) { + TCFREE(bbuf); + return false; + } + if (hash > trec.hash) { + off = trec.left; + entoff = trec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (hash < trec.hash) { + off = trec.right; + entoff = trec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + if (!trec.kbuf && !tchdbreadrecbody(hdb, &trec)) { + TCFREE(bbuf); + return false; + } + int kcmp = tcreckeycmp(kbuf, ksiz, trec.kbuf, trec.ksiz); + if (kcmp > 0) { + off = trec.left; + TCFREE(trec.bbuf); + trec.kbuf = NULL; + trec.bbuf = NULL; + entoff = trec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (kcmp < 0) { + off = trec.right; + TCFREE(trec.bbuf); + trec.kbuf = NULL; + trec.bbuf = NULL; + entoff = trec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + TCFREE(trec.bbuf); + trec.bbuf = NULL; + bool err = false; + rec->off = destoff; + rec->kbuf = kbuf; + rec->ksiz = ksiz; + rec->vbuf = vbuf; + rec->vsiz = vsiz; + if (!tchdbwriterec(hdb, rec, bidx, entoff)) err = true; + TCFREE(bbuf); + return !err; + } + } + } + TCFREE(bbuf); + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; } - /* Compare keys of two records. `abuf' specifies the pointer to the region of the former. `asiz' specifies the size of the region. `bbuf' specifies the pointer to the region of the latter. `bsiz' specifies the size of the region. The return value is 0 if two equals, positive if the formar is big, else, negative. */ -static int tcreckeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz){ - assert(abuf && asiz >= 0 && bbuf && bsiz >= 0); - if(asiz > bsiz) return 1; - if(asiz < bsiz) return -1; - return memcmp(abuf, bbuf, asiz); +static int tcreckeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz) { + assert(abuf && asiz >= 0 && bbuf && bsiz >= 0); + if (asiz > bsiz) return 1; + if (asiz < bsiz) return -1; + return memcmp(abuf, bbuf, asiz); } - /* Flush the delayed record pool. `hdb' specifies the hash database object. The return value is true if successful, else, it is false. */ -static bool tchdbflushdrp(TCHDB *hdb){ - assert(hdb); - bool err = false; - if(!HDBLOCKDB(hdb)) return false; - if(!hdb->drpool){ - HDBUNLOCKDB(hdb); - return true; - } - TCDODEBUG(hdb->cnt_flushdrp++); - if(!tchdbseekwrite(hdb, hdb->drpoff, TCXSTRPTR(hdb->drpool), TCXSTRSIZE(hdb->drpool))){ +static bool tchdbflushdrp(TCHDB *hdb) { + assert(hdb); + bool err = false; + if (!HDBLOCKDB(hdb)) return false; + if (!hdb->drpool) { + HDBUNLOCKDB(hdb); + return true; + } + TCDODEBUG(hdb->cnt_flushdrp++); + if (!tchdbseekwrite(hdb, hdb->drpoff, TCXSTRPTR(hdb->drpool), TCXSTRSIZE(hdb->drpool))) { + HDBUNLOCKDB(hdb); + return false; + } + const char *rp = TCXSTRPTR(hdb->drpdef); + int size = TCXSTRSIZE(hdb->drpdef); + while (size > 0) { + int ksiz, vsiz; + memcpy(&ksiz, rp, sizeof (int)); + rp += sizeof (int); + memcpy(&vsiz, rp, sizeof (int)); + rp += sizeof (int); + const char *kbuf = rp; + rp += ksiz; + const char *vbuf = rp; + rp += vsiz; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + if (!tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDOVER)) { + tcxstrdel(hdb->drpdef); + tcxstrdel(hdb->drpool); + hdb->drpool = NULL; + hdb->drpdef = NULL; + hdb->drpoff = 0; + HDBUNLOCKDB(hdb); + return false; + } + size -= sizeof (int) * 2 + ksiz + vsiz; + } + tcxstrdel(hdb->drpdef); + tcxstrdel(hdb->drpool); + hdb->drpool = NULL; + hdb->drpdef = NULL; + hdb->drpoff = 0; + if (HDBLOCKSMEM(hdb, false)) { + + uint64_t llnum; + llnum = hdb->rnum; + llnum = TCHTOILL(llnum); + memcpy((void *) (hdb->map + HDBRNUMOFF), &llnum, sizeof (llnum)); + llnum = hdb->fsiz; + llnum = TCHTOILL(llnum); + memcpy((void *) (hdb->map + HDBFSIZOFF), &llnum, sizeof (llnum)); + + HDBUNLOCKSMEM(hdb); + } else { + err = true; + } HDBUNLOCKDB(hdb); - return false; - } - const char *rp = TCXSTRPTR(hdb->drpdef); - int size = TCXSTRSIZE(hdb->drpdef); - while(size > 0){ - int ksiz, vsiz; - memcpy(&ksiz, rp, sizeof(int)); - rp += sizeof(int); - memcpy(&vsiz, rp, sizeof(int)); - rp += sizeof(int); - const char *kbuf = rp; - rp += ksiz; - const char *vbuf = rp; - rp += vsiz; - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - if(!tchdbputimpl(hdb, kbuf, ksiz, bidx, hash, vbuf, vsiz, HDBPDOVER)){ - tcxstrdel(hdb->drpdef); - tcxstrdel(hdb->drpool); - hdb->drpool = NULL; - hdb->drpdef = NULL; - hdb->drpoff = 0; - HDBUNLOCKDB(hdb); - return false; - } - size -= sizeof(int) * 2 + ksiz + vsiz; - } - tcxstrdel(hdb->drpdef); - tcxstrdel(hdb->drpool); - hdb->drpool = NULL; - hdb->drpdef = NULL; - hdb->drpoff = 0; - if (HDBLOCKSMEM(hdb, true)) { - uint64_t llnum; - llnum = hdb->rnum; - llnum = TCHTOILL(llnum); - memcpy((void *)(hdb->map + HDBRNUMOFF), &llnum, sizeof(llnum)); - llnum = hdb->fsiz; - llnum = TCHTOILL(llnum); - memcpy((void *)(hdb->map + HDBFSIZOFF), &llnum, sizeof(llnum)); - HDBUNLOCKSMEM(hdb); - } else { - err = true; - } - HDBUNLOCKDB(hdb); - return !err; + return !err; } - /* Adjust the caches for leaves and nodes. `hdb' specifies the hash tree database object. */ -static void tchdbcacheadjust(TCHDB *hdb){ - assert(hdb); - TCDODEBUG(hdb->cnt_adjrecc++); - tcmdbcutfront(hdb->recc, HDBCACHEOUT); +static void tchdbcacheadjust(TCHDB *hdb) { + assert(hdb); + TCDODEBUG(hdb->cnt_adjrecc++); + tcmdbcutfront(hdb->recc, HDBCACHEOUT); } - /* Initialize the write ahead logging file. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -static bool tchdbwalinit(TCHDB *hdb){ - assert(hdb); - if (!HDBLOCKWAL(hdb)) return false; - if(!tcfseek(hdb->walfd, 0, TCFSTART)){ - tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); - HDBUNLOCKWAL(hdb); - return false; - } - if(!tcftruncate(hdb->walfd, 0)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - HDBUNLOCKWAL(hdb); - return false; - } - uint64_t llnum = hdb->fsiz; - llnum = TCHTOILL(llnum); - if(!tcwrite(hdb->walfd, &llnum, sizeof(llnum))){ - tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); +static bool tchdbwalinit(TCHDB *hdb) { + assert(hdb); + if (!HDBLOCKWAL(hdb)) return false; + if (!tcfseek(hdb->walfd, 0, TCFSTART)) { + tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); + HDBUNLOCKWAL(hdb); + return false; + } + if (!tcftruncate(hdb->walfd, 0)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + HDBUNLOCKWAL(hdb); + return false; + } + uint64_t llnum = hdb->fsiz; + llnum = TCHTOILL(llnum); + if (!tcwrite(hdb->walfd, &llnum, sizeof (llnum))) { + tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); + HDBUNLOCKWAL(hdb); + return false; + } + hdb->walend = hdb->fsiz; HDBUNLOCKWAL(hdb); - return false; - } - hdb->walend = hdb->fsiz; - HDBUNLOCKWAL(hdb); - if(!tchdbwalwrite(hdb, 0, HDBHEADSIZ)) return false; - return true; + if (!tchdbwalwrite(hdb, 0, HDBHEADSIZ)) return false; + return true; } - /* Write an event into the write ahead logging file. `hdb' specifies the hash database object. `off' specifies the offset of the region to be updated. `size' specifies the size of the region. If successful, the return value is true, else, it is false. */ -static bool tchdbwalwrite(TCHDB *hdb, uint64_t off, int64_t size){ - assert(hdb && off >= 0 && size >= 0); - if(off + size > hdb->walend) size = hdb->walend - off; - if(size < 1) return true; - char stack[HDBIOBUFSIZ]; - char *buf; - if(size + sizeof(off) + sizeof(size) <= HDBIOBUFSIZ){ - buf = stack; - } else { - TCMALLOC(buf, size + sizeof(off) + sizeof(size)); - } - char *wp = buf; - uint64_t llnum = TCHTOILL(off); - memcpy(wp, &llnum, sizeof(llnum)); - wp += sizeof(llnum); - uint32_t lnum = TCHTOIL(size); - memcpy(wp, &lnum, sizeof(lnum)); - wp += sizeof(lnum); - if(!tchdbseekread(hdb, off, wp, size)){ - if(buf != stack) TCFREE(buf); - return false; - } - wp += size; - if(!HDBLOCKWAL(hdb)) { - if(buf != stack) TCFREE(buf); - return false; - } - if(!tcwrite(hdb->walfd, buf, wp - buf)){ - tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); - if(buf != stack) TCFREE(buf); - HDBUNLOCKWAL(hdb); - return false; - } - if(buf != stack) TCFREE(buf); - if((hdb->omode & HDBOTSYNC) && fsync(hdb->walfd)){ - tchdbsetecode(hdb, TCESYNC, __FILE__, __LINE__, __func__); +static bool tchdbwalwrite(TCHDB *hdb, uint64_t off, int64_t size) { + assert(hdb && off >= 0 && size >= 0); + if (off + size > hdb->walend) size = hdb->walend - off; + if (size < 1) return true; + char stack[HDBIOBUFSIZ]; + char *buf; + if (size + sizeof (off) + sizeof (size) <= HDBIOBUFSIZ) { + buf = stack; + } else { + TCMALLOC(buf, size + sizeof (off) + sizeof (size)); + } + char *wp = buf; + uint64_t llnum = TCHTOILL(off); + memcpy(wp, &llnum, sizeof (llnum)); + wp += sizeof (llnum); + uint32_t lnum = TCHTOIL(size); + memcpy(wp, &lnum, sizeof (lnum)); + wp += sizeof (lnum); + if (!tchdbseekread(hdb, off, wp, size)) { + if (buf != stack) TCFREE(buf); + return false; + } + wp += size; + if (!HDBLOCKWAL(hdb)) { + if (buf != stack) TCFREE(buf); + return false; + } + if (!tcwrite(hdb->walfd, buf, wp - buf)) { + tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); + if (buf != stack) TCFREE(buf); + HDBUNLOCKWAL(hdb); + return false; + } + if (buf != stack) TCFREE(buf); + if ((hdb->omode & HDBOTSYNC) && fsync(hdb->walfd)) { + tchdbsetecode(hdb, TCESYNC, __FILE__, __LINE__, __func__); + HDBUNLOCKWAL(hdb); + return false; + } HDBUNLOCKWAL(hdb); - return false; - } - HDBUNLOCKWAL(hdb); - return true; + return true; } - /* Restore the database from the write ahead logging file. `hdb' specifies the hash database object. `path' specifies the path of the database file. If successful, the return value is true, else, it is false. */ static bool tchdbwalrestore(TCHDB *hdb, const char *path) { + assert(hdb && path); bool err = false; uint64_t walsiz = 0; HANDLE walfd; @@ -3467,12 +3380,11 @@ static bool tchdbwalrestore(TCHDB *hdb, const char *path) { walfd = open(tpath, O_RDONLY, HDBFILEMODE); #else walfd = CreateFile(tpath, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); #endif TCFREE(tpath); if (INVALIDHANDLE(walfd)) { - tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); HDBUNLOCKWAL(hdb); err = true; goto finish; @@ -3527,6 +3439,12 @@ static bool tchdbwalrestore(TCHDB *hdb, const char *path) { if (buf != stack) TCFREE(buf); waloff += sizeof (off) + sizeof (size) + size; } + if (!CLOSEFH(walfd)) { + tchdbsetecode(hdb, TCECLOSE, __FILE__, __LINE__, __func__); + err = true; + } else { + walfd = INVALID_HANDLE_VALUE; + } HDBUNLOCKWAL(hdb); if (HDBLOCKSMEM(hdb, true)) { @@ -3565,312 +3483,311 @@ finish: return !err; } - /* Remove the write ahead logging file. `hdb' specifies the hash database object. `path' specifies the path of the database file. If successful, the return value is true, else, it is false. */ -static bool tchdbwalremove(TCHDB *hdb, const char *path){ - assert(hdb && path); - if (!HDBLOCKWAL(hdb)) return false; - char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, HDBWALSUFFIX); - bool err = false; - if(!tcunlinkfile(tpath) && errno != ENOENT){ - tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - HDBUNLOCKWAL(hdb); - TCFREE(tpath); - return !err; +static bool tchdbwalremove(TCHDB *hdb, const char *path) { + assert(hdb && path); + if (!HDBLOCKWAL(hdb)) return false; + char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, HDBWALSUFFIX); + bool err = false; + if (!tcunlinkfile(tpath) && errno != ENOENT) { + tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + HDBUNLOCKWAL(hdb); + TCFREE(tpath); + return !err; } - /* Open a database file and connect a hash database object. `hdb' specifies the hash database object. `path' specifies the path of the database file. `omode' specifies the connection mode. If successful, the return value is true, else, it is false. */ -static bool tchdbopenimpl(TCHDB *hdb, const char *path, int omode){ - assert(hdb && path); - HANDLE fd; +static bool tchdbopenimpl(TCHDB *hdb, const char *path, int omode) { + assert(hdb && path); + HANDLE fd; #ifndef _WIN32 - int mode = O_RDONLY; - if(omode & HDBOWRITER){ - mode = O_RDWR; - if(omode & HDBOCREAT) mode |= O_CREAT; - } - fd = open(path, mode, HDBFILEMODE); + int mode = O_RDONLY; + if (omode & HDBOWRITER) { + mode = O_RDWR; + if (omode & HDBOCREAT) mode |= O_CREAT; + } + fd = open(path, mode, HDBFILEMODE); #else - DWORD mode, cmode; - mode = GENERIC_READ; - cmode = OPEN_EXISTING; - if (omode & HDBOWRITER) { - mode |= GENERIC_WRITE; - } - if (omode & (HDBOTRUNC | HDBOCREAT)) { - cmode = CREATE_ALWAYS; - } else if (omode & HDBOTRUNC) { - cmode = TRUNCATE_EXISTING; - } else if (omode & HDBOCREAT) { - cmode = CREATE_NEW; - } - fd = CreateFile(path, mode, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, cmode, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD mode, cmode; + mode = GENERIC_READ; + cmode = OPEN_EXISTING; + if (omode & HDBOWRITER) { + mode |= GENERIC_WRITE; + if (omode & (HDBOTRUNC | HDBOCREAT)) { + cmode = CREATE_ALWAYS; + } else if (omode & HDBOTRUNC) { + cmode = TRUNCATE_EXISTING; + } else if (omode & HDBOCREAT) { + cmode = CREATE_NEW; + } + } + fd = CreateFile(path, mode, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, cmode, FILE_ATTRIBUTE_NORMAL, NULL); #endif - if(INVALIDHANDLE(fd)){ - tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); - return false; - } - if(!(omode & HDBONOLCK)){ - if(!tclock(fd, omode & HDBOWRITER, omode & HDBOLCKNB)){ - tchdbsetecode(hdb, TCELOCK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - } - hdb->omode = omode; - hdb->fd = fd; - if((omode & HDBOWRITER) && (omode & HDBOTRUNC)){ - if(!tchdbftruncate2(hdb, 0, HDBTRUNCSHRINKFILE)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tchdbwalremove(hdb, path)){ - CLOSEFH(fd); - return false; - } - } - struct stat sbuf; - if(fstat(fd, &sbuf) || !S_ISREG(sbuf.st_mode)){ - tchdbsetecode(hdb, TCESTAT, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - char hbuf[HDBHEADSIZ]; - if((omode & HDBOWRITER) && (sbuf.st_size < 1 || (omode & HDBOTRUNC))){ - hdb->flags = 0; - hdb->rnum = 0; - uint32_t fbpmax = 1 << hdb->fpow; - uint32_t fbpsiz = HDBFBPBSIZ + fbpmax * HDBFBPESIZ; - int besiz = (hdb->opts & HDBTLARGE) ? sizeof(int64_t) : sizeof(int32_t); - hdb->align = 1 << hdb->apow; - hdb->fsiz = HDBHEADSIZ + besiz * hdb->bnum + fbpsiz; - hdb->fsiz += tchdbpadsize(hdb, hdb->fsiz); - hdb->frec = hdb->fsiz; - tchdbdumpmeta(hdb, hbuf); - bool err = false; - if(!tcwrite(fd, hbuf, HDBHEADSIZ)) err = true; - char pbuf[HDBIOBUFSIZ]; - memset(pbuf, 0, HDBIOBUFSIZ); - uint64_t psiz = hdb->fsiz - HDBHEADSIZ; - while(psiz > 0){ - if(psiz > HDBIOBUFSIZ){ - if(!tcwrite(fd, pbuf, HDBIOBUFSIZ)) err = true; - psiz -= HDBIOBUFSIZ; - } else { - if(!tcwrite(fd, pbuf, psiz)) err = true; - psiz = 0; - } - } - if(err){ - tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - sbuf.st_size = hdb->fsiz; - } - if(!tcfseek(fd, 0, TCFSTART)){ - tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tcread(fd, hbuf, HDBHEADSIZ)){ - tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - int type = hdb->type; - tchdbloadmeta(hdb, hbuf); - if((hdb->flags & HDBFOPEN) && tchdbwalrestore(hdb, path)){ - if(!tcfseek(fd, 0, TCFSTART)){ - tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - if(!tcread(fd, hbuf, HDBHEADSIZ)){ - tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; + if (INVALIDHANDLE(fd)) { + tchdbsetecode(hdb, tcfilerrno2tcerr(TCEOPEN), __FILE__, __LINE__, __func__); + return false; + } + hdb->omode = omode; + hdb->fd = fd; + + + if (!(omode & HDBONOLCK)) { + if (!tclock(fd, omode & HDBOWRITER, omode & HDBOLCKNB)) { + tchdbsetecode(hdb, TCELOCK, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + } + if ((omode & HDBOWRITER) && (omode & HDBOTRUNC)) { + if (!tchdbftruncate2(hdb, 0, HDBTRALLOWSHRINK)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + if (!tchdbwalremove(hdb, path)) { + CLOSEFH2(hdb->fd); + return false; + } + } + struct stat sbuf; + if (fstat(fd, &sbuf) || !S_ISREG(sbuf.st_mode)) { + tchdbsetecode(hdb, TCESTAT, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + char hbuf[HDBHEADSIZ]; + if ((omode & HDBOWRITER) && (sbuf.st_size < 1 || (omode & HDBOTRUNC))) { + hdb->flags = 0; + hdb->rnum = 0; + uint32_t fbpmax = 1 << hdb->fpow; + uint32_t fbpsiz = HDBFBPBSIZ + fbpmax * HDBFBPESIZ; + int besiz = (hdb->opts & HDBTLARGE) ? sizeof (int64_t) : sizeof (int32_t); + hdb->align = 1 << hdb->apow; + hdb->fsiz = HDBHEADSIZ + besiz * hdb->bnum + fbpsiz; + hdb->fsiz += tchdbpadsize(hdb, hdb->fsiz); + hdb->frec = hdb->fsiz; + tchdbdumpmeta(hdb, hbuf); + bool err = false; + if (!tcwrite(fd, hbuf, HDBHEADSIZ)) err = true; + char pbuf[HDBIOBUFSIZ]; + memset(pbuf, 0, HDBIOBUFSIZ); + uint64_t psiz = hdb->fsiz - HDBHEADSIZ; + while (psiz > 0) { + if (psiz > HDBIOBUFSIZ) { + if (!tcwrite(fd, pbuf, HDBIOBUFSIZ)) err = true; + psiz -= HDBIOBUFSIZ; + } else { + if (!tcwrite(fd, pbuf, psiz)) err = true; + psiz = 0; + } + } + if (err) { + tchdbsetecode(hdb, TCEWRITE, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + sbuf.st_size = hdb->fsiz; + } + if (!tcfseek(fd, 0, TCFSTART)) { + tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + if (!tcread(fd, hbuf, HDBHEADSIZ)) { + tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; } + int type = hdb->type; tchdbloadmeta(hdb, hbuf); - if(!tchdbwalremove(hdb, path)){ - CLOSEFH(fd); - return false; - } - } - int besiz = (hdb->opts & HDBTLARGE) ? sizeof(int64_t) : sizeof(int32_t); - size_t msiz = HDBHEADSIZ + hdb->bnum * besiz; - if(!(omode & HDBONOLCK)){ - if(memcmp(hbuf, HDBMAGICDATA, strlen(HDBMAGICDATA)) || hdb->type != type || - hdb->frec < msiz + HDBFBPBSIZ || hdb->frec > hdb->fsiz || sbuf.st_size < hdb->fsiz){ - tchdbsetecode(hdb, TCEMETA, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - } - if(((hdb->opts & HDBTDEFLATE) && !_tc_deflate) || - ((hdb->opts & HDBTBZIP) && !_tc_bzcompress) || - ((hdb->opts & HDBTEXCODEC) && !hdb->enc)){ - tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } + if ((hdb->flags & HDBFOPEN) && tchdbwalrestore(hdb, path)) { + if (!tcfseek(fd, 0, TCFSTART)) { + tchdbsetecode(hdb, TCESEEK, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + if (!tcread(fd, hbuf, HDBHEADSIZ)) { + tchdbsetecode(hdb, TCEREAD, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + tchdbloadmeta(hdb, hbuf); + if (!tchdbwalremove(hdb, path)) { + CLOSEFH2(hdb->fd); + return false; + } + } + int besiz = (hdb->opts & HDBTLARGE) ? sizeof (int64_t) : sizeof (int32_t); + size_t msiz = HDBHEADSIZ + hdb->bnum * besiz; + if (!(omode & HDBONOLCK)) { + if (memcmp(hbuf, HDBMAGICDATA, strlen(HDBMAGICDATA)) || hdb->type != type || + hdb->frec < msiz + HDBFBPBSIZ || hdb->frec > hdb->fsiz || sbuf.st_size < hdb->fsiz) { + tchdbsetecode(hdb, TCEMETA, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } + } + if (((hdb->opts & HDBTDEFLATE) && !_tc_deflate) || + ((hdb->opts & HDBTBZIP) && !_tc_bzcompress) || + ((hdb->opts & HDBTEXCODEC) && !hdb->enc)) { + tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } #ifndef _WIN32 - size_t xmsiz = (hdb->xmsiz > msiz) ? hdb->xmsiz : msiz; - if(!(omode & HDBOWRITER) && xmsiz > hdb->fsiz) xmsiz = hdb->fsiz; - void *map = mmap(0, xmsiz, PROT_READ | ((omode & HDBOWRITER) ? PROT_WRITE : 0), - MAP_SHARED, fd, 0); - if(map == MAP_FAILED){ - tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } - hdb->map = map; - hdb->xfsiz = sbuf.st_size; + size_t xmsiz = (hdb->xmsiz > msiz) ? hdb->xmsiz : msiz; + if (!(omode & HDBOWRITER) && xmsiz > hdb->fsiz) xmsiz = hdb->fsiz; + void *map = mmap(0, xmsiz, PROT_READ | ((omode & HDBOWRITER) ? PROT_WRITE : 0), + MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + hdb->fd = INVALID_HANDLE_VALUE; + return false; + } + hdb->map = map; + hdb->xfsiz = sbuf.st_size; #else - if(!tchdbftruncate(hdb, sbuf.st_size)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - CLOSEFH(fd); - return false; - } + if (!tchdbftruncate(hdb, sbuf.st_size)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + CLOSEFH2(hdb->fd); + return false; + } #endif - hdb->fbpmax = 1 << hdb->fpow; - if(omode & HDBOWRITER){ - TCMALLOC(hdb->fbpool, hdb->fbpmax * HDBFBPALWRAT * sizeof(HDBFB)); - } else { - hdb->fbpool = NULL; - } - hdb->fbpnum = 0; - hdb->fbpmis = 0; - hdb->async = false; - hdb->drpool = NULL; - hdb->drpdef = NULL; - hdb->drpoff = 0; - hdb->recc = (hdb->rcnum > 0) ? tcmdbnew2(hdb->rcnum * 2 + 1) : NULL; - hdb->path = tcstrdup(path); - hdb->dfcur = hdb->frec; - hdb->iter = 0; - hdb->ba64 = (hdb->opts & HDBTLARGE); - hdb->msiz = msiz; - hdb->align = 1 << hdb->apow; - hdb->runit = tclmin(tclmax(hdb->align, HDBMINRUNIT), HDBIOBUFSIZ); - hdb->zmode = (hdb->opts & HDBTDEFLATE) || (hdb->opts & HDBTBZIP) || - (hdb->opts & HDBTTCBS) || (hdb->opts & HDBTEXCODEC); - hdb->ecode = TCESUCCESS; - hdb->fatal = false; - hdb->inode = (uint64_t)sbuf.st_ino; - hdb->mtime = sbuf.st_mtime; - hdb->dfcnt = 0; - hdb->tran = false; - hdb->walfd = INVALID_HANDLE_VALUE; - hdb->walend = 0; - if(hdb->omode & HDBOWRITER){ - bool err = false; - if(!(hdb->flags & HDBFOPEN) && !tchdbloadfbp(hdb)) err = true; - memset(hbuf, 0, 2); - if(!tchdbseekwrite(hdb, hdb->msiz, hbuf, 2)) err = true; - if(err){ - TCFREE(hdb->path); - TCFREE(hdb->fbpool); - bool l = HDBLOCKSMEM(hdb, true); + hdb->fbpmax = 1 << hdb->fpow; + if (omode & HDBOWRITER) { + TCMALLOC(hdb->fbpool, hdb->fbpmax * HDBFBPALWRAT * sizeof (HDBFB)); + } else { + hdb->fbpool = NULL; + } + hdb->fbpnum = 0; + hdb->fbpmis = 0; + hdb->async = false; + hdb->drpool = NULL; + hdb->drpdef = NULL; + hdb->drpoff = 0; + hdb->recc = (hdb->rcnum > 0) ? tcmdbnew2(hdb->rcnum * 2 + 1) : NULL; + hdb->path = tcstrdup(path); + hdb->dfcur = hdb->frec; + hdb->iter = 0; + hdb->ba64 = (hdb->opts & HDBTLARGE); + hdb->msiz = msiz; + hdb->align = 1 << hdb->apow; + hdb->runit = tclmin(tclmax(hdb->align, HDBMINRUNIT), HDBIOBUFSIZ); + hdb->zmode = (hdb->opts & HDBTDEFLATE) || (hdb->opts & HDBTBZIP) || + (hdb->opts & HDBTTCBS) || (hdb->opts & HDBTEXCODEC); + hdb->ecode = TCESUCCESS; + hdb->fatal = false; + hdb->inode = (uint64_t) sbuf.st_ino; + hdb->mtime = sbuf.st_mtime; + hdb->dfcnt = 0; + hdb->tran = false; + hdb->walfd = INVALID_HANDLE_VALUE; + hdb->walend = 0; + if (hdb->omode & HDBOWRITER) { + bool err = false; + if (!(hdb->flags & HDBFOPEN) && !tchdbloadfbp(hdb)) err = true; + memset(hbuf, 0, 2); + if (!tchdbseekwrite(hdb, hdb->msiz, hbuf, 2)) err = true; + if (err) { + TCFREE(hdb->path); + TCFREE(hdb->fbpool); + if (hdb->map) { #ifdef _WIN32 - FlushViewOfFile((PCVOID) hdb->map, 0); - UnmapViewOfFile((LPCVOID) hdb->map); - CLOSEFH(hdb->w32hmap); + FlushViewOfFile((PCVOID) hdb->map, 0); + UnmapViewOfFile((LPCVOID) hdb->map); + CLOSEFH2(hdb->w32hmap); #else - munmap(hdb->map, xmsiz); + munmap(hdb->map, xmsiz); #endif - if (l) HDBUNLOCKSMEM(hdb); - CLOSEFH(fd); - hdb->fd = INVALID_HANDLE_VALUE; - return false; + hdb->map = NULL; + } + CLOSEFH2(hdb->fd); + return false; + } + tchdbsetflag(hdb, HDBFOPEN, true); } - tchdbsetflag(hdb, HDBFOPEN, true); - } - return true; + return true; } - /* Close a hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -static bool tchdbcloseimpl(TCHDB *hdb){ - assert(hdb); - bool err = false; - if(hdb->recc){ - tcmdbdel(hdb->recc); - hdb->recc = NULL; - } - if(hdb->omode & HDBOWRITER){ - if(!tchdbflushdrp(hdb)) err = true; - if(hdb->tran) hdb->fbpnum = 0; - if(!tchdbsavefbp(hdb)) err = true; - TCFREE(hdb->fbpool); - tchdbsetflag(hdb, HDBFOPEN, false); - } - if(hdb->tran){ - if(!tchdbwalrestore(hdb, hdb->path)) { - err = true; +static bool tchdbcloseimpl(TCHDB *hdb) { + assert(hdb); + bool err = false; + if ((hdb->omode & HDBOWRITER)) { + if (!tchdbflushdrp(hdb)) err = true; + } + if (hdb->tran) { + if (!tchdbwalrestore(hdb, hdb->path)) err = true; + hdb->tran = false; + hdb->fbpnum = 0; + } + if (hdb->recc) { + tcmdbdel(hdb->recc); + hdb->recc = NULL; + } + if ((hdb->omode & HDBOWRITER)) { + if (!tchdbsavefbp(hdb)) err = true; + TCFREE(hdb->fbpool); + tchdbsetflag(hdb, HDBFOPEN, false); + if (!err && !tchdbftruncate2(hdb, hdb->fsiz, HDBTRALLOWSHRINK)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + err = true; + } + if (!tchdbmemsync(hdb, false)) err = true; } - hdb->tran = false; - } else if ((hdb->omode & HDBOWRITER) && !tchdbmemsync(hdb, false)) { - err = true; - } - if((hdb->omode & HDBOWRITER) && !tchdbftruncate2(hdb, hdb->fsiz, HDBTRUNCSHRINKFILE)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - err = true; - } - - if (!HDBLOCKSMEM(hdb, true)) err = true; + if (!HDBLOCKSMEM2(hdb, true)) err = true; #ifndef _WIN32 - size_t xmsiz = (hdb->xmsiz > hdb->msiz) ? hdb->xmsiz : hdb->msiz; - if(!(hdb->omode & HDBOWRITER) && xmsiz > hdb->fsiz) xmsiz = hdb->fsiz; - if(munmap(hdb->map, xmsiz) == -1){ + size_t xmsiz = (hdb->xmsiz > hdb->msiz) ? hdb->xmsiz : hdb->msiz; + if (!(hdb->omode & HDBOWRITER) && xmsiz > hdb->fsiz) xmsiz = hdb->fsiz; + if (!hdb->map || munmap(hdb->map, xmsiz)) { #else - FlushViewOfFile((PCVOID) hdb->map, 0); - if (UnmapViewOfFile((LPVOID) hdb->map) && CloseHandle(hdb->w32hmap)) { - hdb->w32hmap = INVALID_HANDLE_VALUE; - }else{ + if (hdb->map) { + FlushViewOfFile((PCVOID) hdb->map, 0); + UnmapViewOfFile((LPVOID) hdb->map); + CloseHandle(hdb->w32hmap); + hdb->w32hmap = INVALID_HANDLE_VALUE; + } else { #endif - tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); - err = true; - } - hdb->map = NULL; - HDBUNLOCKSMEM(hdb); + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + err = true; + } + hdb->map = NULL; + HDBUNLOCKSMEM(hdb); - if(!INVALIDHANDLE(hdb->walfd)){ - if(!CLOSEFH(hdb->walfd)){ - tchdbsetecode(hdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; + if (!INVALIDHANDLE(hdb->walfd)) { + if (!CLOSEFH(hdb->walfd)) { + tchdbsetecode(hdb, TCECLOSE, __FILE__, __LINE__, __func__); + err = true; + } + if (!hdb->fatal && !tchdbwalremove(hdb, hdb->path)) { + err = true; + } } - if(!hdb->fatal && !tchdbwalremove(hdb, hdb->path)) { - err = true; + if (!INVALIDHANDLE(hdb->fd) && !CLOSEFH(hdb->fd)) { + tchdbsetecode(hdb, TCECLOSE, __FILE__, __LINE__, __func__); + err = true; } - } - if(!CLOSEFH(hdb->fd)){ - tchdbsetecode(hdb, TCECLOSE, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(hdb->path); - hdb->path = NULL; - hdb->fd = INVALID_HANDLE_VALUE; - hdb->walfd = INVALID_HANDLE_VALUE; - return !err; + TCFREE(hdb->path); + hdb->path = NULL; + hdb->fd = INVALID_HANDLE_VALUE; + hdb->walfd = INVALID_HANDLE_VALUE; + return !err; } - /* Store a record. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -3882,215 +3799,214 @@ static bool tchdbcloseimpl(TCHDB *hdb){ `dmode' specifies behavior when the key overlaps. If successful, the return value is true, else, it is false. */ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - const char *vbuf, int vsiz, int dmode){ - assert(hdb && kbuf && ksiz >= 0); - if(hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return false; - off_t entoff = 0; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - bool err = false; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - if(hash > rec.hash){ - off = rec.left; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(hash < rec.hash){ - off = rec.right; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - bool rv; - int nvsiz; - char *nvbuf; - HDBPDPROCOP *procptr; - switch(dmode){ - case HDBPDKEEP: - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return false; - case HDBPDCAT: - if(vsiz < 1){ - TCFREE(rec.bbuf); - return true; - } - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - TCFREE(rec.bbuf); - return false; - } - nvsiz = rec.vsiz + vsiz; - if(rec.bbuf){ - TCREALLOC(rec.bbuf, rec.bbuf, rec.ksiz + nvsiz); - memcpy(rec.bbuf + rec.ksiz + rec.vsiz, vbuf, vsiz); - rec.kbuf = rec.bbuf; - rec.vbuf = rec.kbuf + rec.ksiz; - rec.vsiz = nvsiz; + const char *vbuf, int vsiz, int dmode) { + assert(hdb && kbuf && ksiz >= 0); + if (hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return false; + off_t entoff = 0; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + bool err = false; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + if (hash > rec.hash) { + off = rec.left; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (hash < rec.hash) { + off = rec.right; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); } else { - TCMALLOC(rec.bbuf, nvsiz + 1); - memcpy(rec.bbuf, rec.vbuf, rec.vsiz); - memcpy(rec.bbuf + rec.vsiz, vbuf, vsiz); - rec.vbuf = rec.bbuf; - rec.vsiz = nvsiz; - } - rv = tchdbwriterec(hdb, &rec, bidx, entoff); - TCFREE(rec.bbuf); - return rv; - case HDBPDADDINT: - if(rec.vsiz != sizeof(int)){ - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return false; - } - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - TCFREE(rec.bbuf); - return false; - } - int lnum; - memcpy(&lnum, rec.vbuf, sizeof(lnum)); - if(*(int *)vbuf == 0){ - TCFREE(rec.bbuf); - *(int *)vbuf = lnum; - return true; - } - lnum += *(int *)vbuf; - rec.vbuf = (char *)&lnum; - *(int *)vbuf = lnum; - rv = tchdbwriterec(hdb, &rec, bidx, entoff); - TCFREE(rec.bbuf); - return rv; - case HDBPDADDDBL: - if(rec.vsiz != sizeof(double)){ - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return false; - } - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - TCFREE(rec.bbuf); - return false; - } - double dnum; - memcpy(&dnum, rec.vbuf, sizeof(dnum)); - if(*(double *)vbuf == 0.0){ - TCFREE(rec.bbuf); - *(double *)vbuf = dnum; - return true; - } - dnum += *(double *)vbuf; - rec.vbuf = (char *)&dnum; - *(double *)vbuf = dnum; - rv = tchdbwriterec(hdb, &rec, bidx, entoff); - TCFREE(rec.bbuf); - return rv; - case HDBPDPROC: - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - TCFREE(rec.bbuf); - return false; - } - procptr = *(HDBPDPROCOP **)((char *)kbuf - sizeof(procptr)); - nvbuf = procptr->proc(rec.vbuf, rec.vsiz, &nvsiz, procptr->op); - TCFREE(rec.bbuf); - if(nvbuf == (void *)-1){ - return tchdbremoverec(hdb, &rec, rbuf, bidx, entoff); - } else if(nvbuf){ - rec.kbuf = kbuf; - rec.ksiz = ksiz; - rec.vbuf = nvbuf; - rec.vsiz = nvsiz; - rv = tchdbwriterec(hdb, &rec, bidx, entoff); - TCFREE(nvbuf); - return rv; + bool rv; + int nvsiz; + char *nvbuf; + HDBPDPROCOP *procptr; + switch (dmode) { + case HDBPDKEEP: + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return false; + case HDBPDCAT: + if (vsiz < 1) { + TCFREE(rec.bbuf); + return true; + } + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + TCFREE(rec.bbuf); + return false; + } + nvsiz = rec.vsiz + vsiz; + if (rec.bbuf) { + TCREALLOC(rec.bbuf, rec.bbuf, rec.ksiz + nvsiz); + memcpy(rec.bbuf + rec.ksiz + rec.vsiz, vbuf, vsiz); + rec.kbuf = rec.bbuf; + rec.vbuf = rec.kbuf + rec.ksiz; + rec.vsiz = nvsiz; + } else { + TCMALLOC(rec.bbuf, nvsiz + 1); + memcpy(rec.bbuf, rec.vbuf, rec.vsiz); + memcpy(rec.bbuf + rec.vsiz, vbuf, vsiz); + rec.vbuf = rec.bbuf; + rec.vsiz = nvsiz; + } + rv = tchdbwriterec(hdb, &rec, bidx, entoff); + TCFREE(rec.bbuf); + return rv; + case HDBPDADDINT: + if (rec.vsiz != sizeof (int)) { + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return false; + } + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + TCFREE(rec.bbuf); + return false; + } + int lnum; + memcpy(&lnum, rec.vbuf, sizeof (lnum)); + if (*(int *) vbuf == 0) { + TCFREE(rec.bbuf); + *(int *) vbuf = lnum; + return true; + } + lnum += *(int *) vbuf; + rec.vbuf = (char *) &lnum; + *(int *) vbuf = lnum; + rv = tchdbwriterec(hdb, &rec, bidx, entoff); + TCFREE(rec.bbuf); + return rv; + case HDBPDADDDBL: + if (rec.vsiz != sizeof (double)) { + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return false; + } + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + TCFREE(rec.bbuf); + return false; + } + double dnum; + memcpy(&dnum, rec.vbuf, sizeof (dnum)); + if (*(double *) vbuf == 0.0) { + TCFREE(rec.bbuf); + *(double *) vbuf = dnum; + return true; + } + dnum += *(double *) vbuf; + rec.vbuf = (char *) &dnum; + *(double *) vbuf = dnum; + rv = tchdbwriterec(hdb, &rec, bidx, entoff); + TCFREE(rec.bbuf); + return rv; + case HDBPDPROC: + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + TCFREE(rec.bbuf); + return false; + } + procptr = *(HDBPDPROCOP **) ((char *) kbuf - sizeof (procptr)); + nvbuf = procptr->proc(rec.vbuf, rec.vsiz, &nvsiz, procptr->op); + TCFREE(rec.bbuf); + if (nvbuf == (void *) - 1) { + return tchdbremoverec(hdb, &rec, rbuf, bidx, entoff); + } else if (nvbuf) { + rec.kbuf = kbuf; + rec.ksiz = ksiz; + rec.vbuf = nvbuf; + rec.vsiz = nvsiz; + rv = tchdbwriterec(hdb, &rec, bidx, entoff); + TCFREE(nvbuf); + return rv; + } + tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); + return false; + default: + break; + } + TCFREE(rec.bbuf); + rec.ksiz = ksiz; + rec.vsiz = vsiz; + rec.kbuf = kbuf; + rec.vbuf = vbuf; + return tchdbwriterec(hdb, &rec, bidx, entoff); } - tchdbsetecode(hdb, TCEKEEP, __FILE__, __LINE__, __func__); - return false; - default: - break; } - TCFREE(rec.bbuf); - rec.ksiz = ksiz; - rec.vsiz = vsiz; - rec.kbuf = kbuf; - rec.vbuf = vbuf; - return tchdbwriterec(hdb, &rec, bidx, entoff); - } - } - } - if(!vbuf){ - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; - } - if(!HDBLOCKDB(hdb)) return false; - rec.rsiz = hdb->ba64 ? sizeof(uint8_t) * 2 + sizeof(uint64_t) * 2 + sizeof(uint16_t) : - sizeof(uint8_t) * 2 + sizeof(uint32_t) * 2 + sizeof(uint16_t); - if(ksiz < (1U << 7)){ - rec.rsiz += 1; - } else if(ksiz < (1U << 14)){ - rec.rsiz += 2; - } else if(ksiz < (1U << 21)){ - rec.rsiz += 3; - } else if(ksiz < (1U << 28)){ - rec.rsiz += 4; - } else { - rec.rsiz += 5; - } - if(vsiz < (1U << 7)){ - rec.rsiz += 1; - } else if(vsiz < (1U << 14)){ - rec.rsiz += 2; - } else if(vsiz < (1U << 21)){ - rec.rsiz += 3; - } else if(vsiz < (1U << 28)){ - rec.rsiz += 4; - } else { - rec.rsiz += 5; - } - if(!tchdbfbpsearch(hdb, &rec)){ - HDBUNLOCKDB(hdb); - return false; - } - rec.hash = hash; - rec.left = 0; - rec.right = 0; - rec.ksiz = ksiz; - rec.vsiz = vsiz; - rec.psiz = 0; - rec.kbuf = kbuf; - rec.vbuf = vbuf; - if(!tchdbwriterec(hdb, &rec, bidx, entoff)){ + } + if (!vbuf) { + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; + } + if (!HDBLOCKDB(hdb)) return false; + rec.rsiz = hdb->ba64 ? sizeof (uint8_t) * 2 + sizeof (uint64_t) * 2 + sizeof (uint16_t) : + sizeof (uint8_t) * 2 + sizeof (uint32_t) * 2 + sizeof (uint16_t); + if (ksiz < (1U << 7)) { + rec.rsiz += 1; + } else if (ksiz < (1U << 14)) { + rec.rsiz += 2; + } else if (ksiz < (1U << 21)) { + rec.rsiz += 3; + } else if (ksiz < (1U << 28)) { + rec.rsiz += 4; + } else { + rec.rsiz += 5; + } + if (vsiz < (1U << 7)) { + rec.rsiz += 1; + } else if (vsiz < (1U << 14)) { + rec.rsiz += 2; + } else if (vsiz < (1U << 21)) { + rec.rsiz += 3; + } else if (vsiz < (1U << 28)) { + rec.rsiz += 4; + } else { + rec.rsiz += 5; + } + if (!tchdbfbpsearch(hdb, &rec)) { + HDBUNLOCKDB(hdb); + return false; + } + rec.hash = hash; + rec.left = 0; + rec.right = 0; + rec.ksiz = ksiz; + rec.vsiz = vsiz; + rec.psiz = 0; + rec.kbuf = kbuf; + rec.vbuf = vbuf; + if (!tchdbwriterec(hdb, &rec, bidx, entoff)) { + HDBUNLOCKDB(hdb); + return false; + } + hdb->rnum++; + uint64_t llnum = hdb->rnum; + llnum = TCHTOILL(llnum); + if (HDBLOCKSMEM(hdb, false)) { + memcpy((void *) (hdb->map + HDBRNUMOFF), &llnum, sizeof (llnum)); + HDBUNLOCKSMEM(hdb); + } else { + err = true; + } HDBUNLOCKDB(hdb); - return false; - } - hdb->rnum++; - uint64_t llnum = hdb->rnum; - llnum = TCHTOILL(llnum); - if (HDBLOCKSMEM(hdb, true)) { - memcpy((void *)(hdb->map + HDBRNUMOFF), &llnum, sizeof(llnum)); - HDBUNLOCKSMEM(hdb); - } else { - err = true; - } - HDBUNLOCKDB(hdb); - return !err; + return !err; } - /* Append a record to the delayed record pool. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4099,46 +4015,45 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, `vsiz' specifies the size of the region of the value. `hash' specifies the second hash value. */ static void tchdbdrpappend(TCHDB *hdb, const char *kbuf, int ksiz, const char *vbuf, int vsiz, - uint8_t hash){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - TCDODEBUG(hdb->cnt_appenddrp++); - char rbuf[HDBIOBUFSIZ]; - char *wp = rbuf; - *(uint8_t *)(wp++) = HDBMAGICREC; - *(uint8_t *)(wp++) = hash; - if(hdb->ba64){ - memset(wp, 0, sizeof(uint64_t) * 2); - wp += sizeof(uint64_t) * 2; - } else { - memset(wp, 0, sizeof(uint32_t) * 2); - wp += sizeof(uint32_t) * 2; - } - uint16_t snum; - char *pwp = wp; - wp += sizeof(snum); - int step; - TCSETVNUMBUF(step, wp, ksiz); - wp += step; - TCSETVNUMBUF(step, wp, vsiz); - wp += step; - int32_t hsiz = wp - rbuf; - int32_t rsiz = hsiz + ksiz + vsiz; - uint16_t psiz = tchdbpadsize(hdb, hdb->fsiz + rsiz); - hdb->fsiz += rsiz + psiz; - snum = TCHTOIS(psiz); - memcpy(pwp, &snum, sizeof(snum)); - TCXSTR *drpool = hdb->drpool; - TCXSTRCAT(drpool, rbuf, hsiz); - TCXSTRCAT(drpool, kbuf, ksiz); - TCXSTRCAT(drpool, vbuf, vsiz); - if(psiz > 0){ - char pbuf[psiz]; - memset(pbuf, 0, psiz); - TCXSTRCAT(drpool, pbuf, psiz); - } + uint8_t hash) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + TCDODEBUG(hdb->cnt_appenddrp++); + char rbuf[HDBIOBUFSIZ]; + char *wp = rbuf; + *(uint8_t *) (wp++) = HDBMAGICREC; + *(uint8_t *) (wp++) = hash; + if (hdb->ba64) { + memset(wp, 0, sizeof (uint64_t) * 2); + wp += sizeof (uint64_t) * 2; + } else { + memset(wp, 0, sizeof (uint32_t) * 2); + wp += sizeof (uint32_t) * 2; + } + uint16_t snum; + char *pwp = wp; + wp += sizeof (snum); + int step; + TCSETVNUMBUF(step, wp, ksiz); + wp += step; + TCSETVNUMBUF(step, wp, vsiz); + wp += step; + int32_t hsiz = wp - rbuf; + int32_t rsiz = hsiz + ksiz + vsiz; + uint16_t psiz = tchdbpadsize(hdb, hdb->fsiz + rsiz); + hdb->fsiz += rsiz + psiz; + snum = TCHTOIS(psiz); + memcpy(pwp, &snum, sizeof (snum)); + TCXSTR *drpool = hdb->drpool; + TCXSTRCAT(drpool, rbuf, hsiz); + TCXSTRCAT(drpool, kbuf, ksiz); + TCXSTRCAT(drpool, vbuf, vsiz); + if (psiz > 0) { + char pbuf[psiz]; + memset(pbuf, 0, psiz); + TCXSTRCAT(drpool, pbuf, psiz); + } } - /* Store a record in asynchronus fashion. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4149,70 +4064,69 @@ static void tchdbdrpappend(TCHDB *hdb, const char *kbuf, int ksiz, const char *v `vsiz' specifies the size of the region of the value. If successful, the return value is true, else, it is false. */ static bool tchdbputasyncimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, - uint8_t hash, const char *vbuf, int vsiz){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); - if(hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); - if(!hdb->drpool){ - hdb->drpool = tcxstrnew3(HDBDRPUNIT + HDBDRPLAT); - hdb->drpdef = tcxstrnew3(HDBDRPUNIT); - hdb->drpoff = hdb->fsiz; - } - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return false; - off_t entoff = 0; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - if(off >= hdb->drpoff - hdb->runit){ - TCDODEBUG(hdb->cnt_deferdrp++); - TCXSTR *drpdef = hdb->drpdef; - TCXSTRCAT(drpdef, &ksiz, sizeof(ksiz)); - TCXSTRCAT(drpdef, &vsiz, sizeof(vsiz)); - TCXSTRCAT(drpdef, kbuf, ksiz); - TCXSTRCAT(drpdef, vbuf, vsiz); - if(TCXSTRSIZE(hdb->drpdef) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; - return true; - } - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - if(hash > rec.hash){ - off = rec.left; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(hash < rec.hash){ - off = rec.right; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - TCDODEBUG(hdb->cnt_deferdrp++); - TCXSTR *drpdef = hdb->drpdef; - TCXSTRCAT(drpdef, &ksiz, sizeof(ksiz)); - TCXSTRCAT(drpdef, &vsiz, sizeof(vsiz)); - TCXSTRCAT(drpdef, kbuf, ksiz); - TCXSTRCAT(drpdef, vbuf, vsiz); - if(TCXSTRSIZE(hdb->drpdef) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; - return true; - } - } - if(entoff > 0){ - if(hdb->ba64){ - uint64_t llnum = hdb->fsiz >> hdb->apow; - llnum = TCHTOILL(llnum); - if(!tchdbseekwrite(hdb, entoff, &llnum, sizeof(uint64_t))) return false; + uint8_t hash, const char *vbuf, int vsiz) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0); + if (hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); + if (!hdb->drpool) { + hdb->drpool = tcxstrnew3(HDBDRPUNIT + HDBDRPLAT); + hdb->drpdef = tcxstrnew3(HDBDRPUNIT); + hdb->drpoff = hdb->fsiz; + } + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return false; + off_t entoff = 0; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + if (off >= hdb->drpoff - hdb->runit) { + TCDODEBUG(hdb->cnt_deferdrp++); + TCXSTR *drpdef = hdb->drpdef; + TCXSTRCAT(drpdef, &ksiz, sizeof (ksiz)); + TCXSTRCAT(drpdef, &vsiz, sizeof (vsiz)); + TCXSTRCAT(drpdef, kbuf, ksiz); + TCXSTRCAT(drpdef, vbuf, vsiz); + if (TCXSTRSIZE(hdb->drpdef) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; + return true; + } + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + if (hash > rec.hash) { + off = rec.left; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (hash < rec.hash) { + off = rec.right; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + TCDODEBUG(hdb->cnt_deferdrp++); + TCXSTR *drpdef = hdb->drpdef; + TCXSTRCAT(drpdef, &ksiz, sizeof (ksiz)); + TCXSTRCAT(drpdef, &vsiz, sizeof (vsiz)); + TCXSTRCAT(drpdef, kbuf, ksiz); + TCXSTRCAT(drpdef, vbuf, vsiz); + if (TCXSTRSIZE(hdb->drpdef) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; + return true; + } + } + if (entoff > 0) { + if (hdb->ba64) { + uint64_t llnum = hdb->fsiz >> hdb->apow; + llnum = TCHTOILL(llnum); + if (!tchdbseekwrite(hdb, entoff, &llnum, sizeof (uint64_t))) return false; + } else { + uint32_t lnum = hdb->fsiz >> hdb->apow; + lnum = TCHTOIL(lnum); + if (!tchdbseekwrite(hdb, entoff, &lnum, sizeof (uint32_t))) return false; + } } else { - uint32_t lnum = hdb->fsiz >> hdb->apow; - lnum = TCHTOIL(lnum); - if(!tchdbseekwrite(hdb, entoff, &lnum, sizeof(uint32_t))) return false; + tchdbsetbucket(hdb, bidx, hdb->fsiz); } - } else { - tchdbsetbucket(hdb, bidx, hdb->fsiz); - } - tchdbdrpappend(hdb, kbuf, ksiz, vbuf, vsiz, hash); - hdb->rnum++; - if(TCXSTRSIZE(hdb->drpool) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; - return true; + tchdbdrpappend(hdb, kbuf, ksiz, vbuf, vsiz, hash); + hdb->rnum++; + if (TCXSTRSIZE(hdb->drpool) > HDBDRPUNIT && !tchdbflushdrp(hdb)) return false; + return true; } - /* Remove a record of a hash database object. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4220,52 +4134,51 @@ static bool tchdbputasyncimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t b `bidx' specifies the index of the bucket array. `hash' specifies the hash value for the collision tree. If successful, the return value is true, else, it is false. */ -static bool tchdboutimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash){ - assert(hdb && kbuf && ksiz >= 0); - if(hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return false; - off_t entoff = 0; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - if(hash > rec.hash){ - off = rec.left; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(hash < rec.hash){ - off = rec.right; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)); - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) + - (hdb->ba64 ? sizeof(uint64_t) : sizeof(uint32_t)); - } else { - TCFREE(rec.bbuf); - rec.bbuf = NULL; - return tchdbremoverec(hdb, &rec, rbuf, bidx, entoff); - } +static bool tchdboutimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash) { + assert(hdb && kbuf && ksiz >= 0); + if (hdb->recc) tcmdbout(hdb->recc, kbuf, ksiz); + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return false; + off_t entoff = 0; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + if (hash > rec.hash) { + off = rec.left; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (hash < rec.hash) { + off = rec.right; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)); + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + entoff = rec.off + (sizeof (uint8_t) + sizeof (uint8_t)) + + (hdb->ba64 ? sizeof (uint64_t) : sizeof (uint32_t)); + } else { + TCFREE(rec.bbuf); + rec.bbuf = NULL; + return tchdbremoverec(hdb, &rec, rbuf, bidx, entoff); + } + } } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; } - /* Retrieve a record in a hash database object. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4277,181 +4190,181 @@ static bool tchdboutimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, If successful, the return value is the pointer to the region of the value of the corresponding record. */ static char *tchdbgetimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - int *sp){ - assert(hdb && kbuf && ksiz >= 0 && sp); - if(hdb->recc){ - int tvsiz; - char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); - if(tvbuf){ - if(*tvbuf == '*'){ - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - TCFREE(tvbuf); - return NULL; - } - *sp = tvsiz - 1; - memmove(tvbuf, tvbuf + 1, tvsiz); - return tvbuf; - } - } - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return NULL; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return NULL; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - TCFREE(rec.bbuf); - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - return NULL; - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); - } - *sp = zsiz; - return zbuf; - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + int *sp) { + assert(hdb && kbuf && ksiz >= 0 && sp); + if (hdb->recc) { + int tvsiz; + char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); + if (tvbuf) { + if (*tvbuf == '*') { + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + TCFREE(tvbuf); + return NULL; + } + *sp = tvsiz - 1; + memmove(tvbuf, tvbuf + 1, tvsiz); + return tvbuf; } - if(rec.bbuf){ - memmove(rec.bbuf, rec.vbuf, rec.vsiz); - rec.bbuf[rec.vsiz] = '\0'; - *sp = rec.vsiz; - return rec.bbuf; + } + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return NULL; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return NULL; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + TCFREE(rec.bbuf); + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + return NULL; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); + } + *sp = zsiz; + return zbuf; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + if (rec.bbuf) { + memmove(rec.bbuf, rec.vbuf, rec.vsiz); + rec.bbuf[rec.vsiz] = '\0'; + *sp = rec.vsiz; + return rec.bbuf; + } + *sp = rec.vsiz; + char *rv; + TCMEMDUP(rv, rec.vbuf, rec.vsiz); + return rv; + } } - *sp = rec.vsiz; - char *rv; - TCMEMDUP(rv, rec.vbuf, rec.vsiz); - return rv; - } } - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; } static int tchdbgetintoxstrimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, TCXSTR *xstr) { - assert(hdb && kbuf && ksiz >= 0 && xstr); - if(hdb->recc){ - int tvsiz; - char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); - if(tvbuf){ - if(*tvbuf == '*'){ - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - TCFREE(tvbuf); - return -1; - } - tvsiz = tvsiz - 1; - TCXSTRCAT(xstr, tvbuf + 1, tvsiz); - TCFREE(tvbuf); //todo - return tvsiz; - } - } - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return -1; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return -1; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - TCFREE(rec.bbuf); - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - return -1; - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); - } - TCXSTRCAT(xstr, zbuf, zsiz); - TCFREE(zbuf); - return zsiz; + assert(hdb && kbuf && ksiz >= 0 && xstr); + if (hdb->recc) { + int tvsiz; + char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); + if (tvbuf) { + if (*tvbuf == '*') { + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + TCFREE(tvbuf); + return -1; + } + tvsiz = tvsiz - 1; + TCXSTRCAT(xstr, tvbuf + 1, tvsiz); + TCFREE(tvbuf); //todo + return tvsiz; } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return -1; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return -1; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + TCFREE(rec.bbuf); + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + return -1; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); + } + TCXSTRCAT(xstr, zbuf, zsiz); + TCFREE(zbuf); + return zsiz; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + TCXSTRCAT(xstr, rec.vbuf, rec.vsiz); + TCFREE(rec.bbuf); + return rec.vsiz; + } } - TCXSTRCAT(xstr, rec.vbuf, rec.vsiz); - TCFREE(rec.bbuf); - return rec.vsiz; - } } - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return -1; + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return -1; } /* Retrieve a record in a hash database object and write the value into a buffer. @@ -4465,95 +4378,94 @@ static int tchdbgetintoxstrimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t `max' specifies the size of the buffer. If successful, the return value is the size of the written data, else, it is -1. */ static int tchdbgetintobuf(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash, - char *vbuf, int max){ - assert(hdb && kbuf && ksiz >= 0 && vbuf && max >= 0); - if(hdb->recc){ - int tvsiz; - char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); - if(tvbuf){ - if(*tvbuf == '*'){ - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - TCFREE(tvbuf); - return -1; - } - tvsiz = tclmin(tvsiz - 1, max); - memcpy(vbuf, tvbuf + 1, tvsiz); - TCFREE(tvbuf); - return tvsiz; - } - } - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return -1; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return -1; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - TCFREE(rec.bbuf); - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - return -1; - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); - } - zsiz = tclmin(zsiz, max); - memcpy(vbuf, zbuf, zsiz); - TCFREE(zbuf); - return zsiz; + char *vbuf, int max) { + assert(hdb && kbuf && ksiz >= 0 && vbuf && max >= 0); + if (hdb->recc) { + int tvsiz; + char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); + if (tvbuf) { + if (*tvbuf == '*') { + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + TCFREE(tvbuf); + return -1; + } + tvsiz = tclmin(tvsiz - 1, max); + memcpy(vbuf, tvbuf + 1, tvsiz); + TCFREE(tvbuf); + return tvsiz; } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return -1; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return -1; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + TCFREE(rec.bbuf); + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + return -1; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); + } + zsiz = tclmin(zsiz, max); + memcpy(vbuf, zbuf, zsiz); + TCFREE(zbuf); + return zsiz; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + int vsiz = tclmin(rec.vsiz, max); + memcpy(vbuf, rec.vbuf, vsiz); + TCFREE(rec.bbuf); + return vsiz; + } } - int vsiz = tclmin(rec.vsiz, max); - memcpy(vbuf, rec.vbuf, vsiz); - TCFREE(rec.bbuf); - return vsiz; - } } - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return -1; + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return -1; } - /* Retrieve the next record of a record in a hash database object. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4565,182 +4477,181 @@ static int tchdbgetintobuf(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx If successful, the return value is the pointer to the region of the value of the next record. */ static char *tchdbgetnextimpl(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, - const char **vbp, int *vsp){ - assert(hdb && sp); - if(!kbuf){ - uint64_t iter = hdb->frec; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(iter < hdb->fsiz){ - rec.off = iter; - if(!tchdbreadrec(hdb, &rec, rbuf)) return NULL; - iter += rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(vbp){ - if(hdb->zmode){ - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return NULL; - } - char *rv; - TCMALLOC(rv, rec.ksiz + zsiz + 1); - memcpy(rv, rec.kbuf, rec.ksiz); - memcpy(rv + rec.ksiz, zbuf, zsiz); - *sp = rec.ksiz; - *vbp = rv + rec.ksiz; - *vsp = zsiz; - TCFREE(zbuf); - TCFREE(rec.bbuf); - return rv; - } - if(rec.vbuf){ - char *rv; - TCMALLOC(rv, rec.ksiz + rec.vsiz + 1); - memcpy(rv, rec.kbuf, rec.ksiz); - memcpy(rv + rec.ksiz, rec.vbuf, rec.vsiz); - *sp = rec.ksiz; - *vbp = rv + rec.ksiz; - *vsp = rec.vsiz; - return rv; - } - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - *sp = rec.ksiz; - *vbp = rec.vbuf; - *vsp = rec.vsiz; - return rec.bbuf; - } - if(rec.kbuf){ - *sp = rec.ksiz; - char *rv; - TCMEMDUP(rv, rec.kbuf, rec.ksiz); - return rv; - } - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - rec.bbuf[rec.ksiz] = '\0'; - *sp = rec.ksiz; - return rec.bbuf; - } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; - } - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return NULL; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return NULL; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - uint64_t iter = rec.off + rec.rsiz; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - while(iter < hdb->fsiz){ - rec.off = iter; - if(!tchdbreadrec(hdb, &rec, rbuf)) return NULL; - iter += rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(vbp){ - if(hdb->zmode){ - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + const char **vbp, int *vsp) { + assert(hdb && sp); + if (!kbuf) { + uint64_t iter = hdb->frec; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (iter < hdb->fsiz) { + rec.off = iter; + if (!tchdbreadrec(hdb, &rec, rbuf)) return NULL; + iter += rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (vbp) { + if (hdb->zmode) { + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return NULL; + } + char *rv; + TCMALLOC(rv, rec.ksiz + zsiz + 1); + memcpy(rv, rec.kbuf, rec.ksiz); + memcpy(rv + rec.ksiz, zbuf, zsiz); + *sp = rec.ksiz; + *vbp = rv + rec.ksiz; + *vsp = zsiz; + TCFREE(zbuf); + TCFREE(rec.bbuf); + return rv; + } + if (rec.vbuf) { + char *rv; + TCMALLOC(rv, rec.ksiz + rec.vsiz + 1); + memcpy(rv, rec.kbuf, rec.ksiz); + memcpy(rv + rec.ksiz, rec.vbuf, rec.vsiz); + *sp = rec.ksiz; + *vbp = rv + rec.ksiz; + *vsp = rec.vsiz; + return rv; + } + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + *sp = rec.ksiz; + *vbp = rec.vbuf; + *vsp = rec.vsiz; + return rec.bbuf; } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return NULL; + if (rec.kbuf) { + *sp = rec.ksiz; + char *rv; + TCMEMDUP(rv, rec.kbuf, rec.ksiz); + return rv; } - char *rv; - TCMALLOC(rv, rec.ksiz + zsiz + 1); - memcpy(rv, rec.kbuf, rec.ksiz); - memcpy(rv + rec.ksiz, zbuf, zsiz); - *sp = rec.ksiz; - *vbp = rv + rec.ksiz; - *vsp = zsiz; - TCFREE(zbuf); - TCFREE(rec.bbuf); - return rv; - } - if(rec.vbuf){ - char *rv; - TCMALLOC(rv, rec.ksiz + rec.vsiz + 1); - memcpy(rv, rec.kbuf, rec.ksiz); - memcpy(rv + rec.ksiz, rec.vbuf, rec.vsiz); + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + rec.bbuf[rec.ksiz] = '\0'; *sp = rec.ksiz; - *vbp = rv + rec.ksiz; - *vsp = rec.vsiz; - return rv; - } - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - *sp = rec.ksiz; - *vbp = rec.vbuf; - *vsp = rec.vsiz; - return rec.bbuf; + return rec.bbuf; } - if(rec.kbuf){ - *sp = rec.ksiz; - char *rv; - TCMEMDUP(rv, rec.kbuf, rec.ksiz); - return rv; - } - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - rec.bbuf[rec.ksiz] = '\0'; - *sp = rec.ksiz; - return rec.bbuf; - } } tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); return NULL; - } } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return NULL; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return NULL; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return NULL; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + uint64_t iter = rec.off + rec.rsiz; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + while (iter < hdb->fsiz) { + rec.off = iter; + if (!tchdbreadrec(hdb, &rec, rbuf)) return NULL; + iter += rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (vbp) { + if (hdb->zmode) { + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return NULL; + } + char *rv; + TCMALLOC(rv, rec.ksiz + zsiz + 1); + memcpy(rv, rec.kbuf, rec.ksiz); + memcpy(rv + rec.ksiz, zbuf, zsiz); + *sp = rec.ksiz; + *vbp = rv + rec.ksiz; + *vsp = zsiz; + TCFREE(zbuf); + TCFREE(rec.bbuf); + return rv; + } + if (rec.vbuf) { + char *rv; + TCMALLOC(rv, rec.ksiz + rec.vsiz + 1); + memcpy(rv, rec.kbuf, rec.ksiz); + memcpy(rv + rec.ksiz, rec.vbuf, rec.vsiz); + *sp = rec.ksiz; + *vbp = rv + rec.ksiz; + *vsp = rec.vsiz; + return rv; + } + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + *sp = rec.ksiz; + *vbp = rec.vbuf; + *vsp = rec.vsiz; + return rec.bbuf; + } + if (rec.kbuf) { + *sp = rec.ksiz; + char *rv; + TCMEMDUP(rv, rec.kbuf, rec.ksiz); + return rv; + } + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + rec.bbuf[rec.ksiz] = '\0'; + *sp = rec.ksiz; + return rec.bbuf; + } + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; + } + } + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; } - /* Get the size of the value of a record in a hash database object. `hdb' specifies the hash database object. `kbuf' specifies the pointer to the region of the key. @@ -4749,180 +4660,176 @@ static char *tchdbgetnextimpl(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, `hash' specifies the hash value for the collision tree. If successful, the return value is the size of the value of the corresponding record, else, it is -1. */ -static int tchdbvsizimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash){ - assert(hdb && kbuf && ksiz >= 0); - if(hdb->recc){ - int tvsiz; - char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); - if(tvbuf){ - if(*tvbuf == '*'){ - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - TCFREE(tvbuf); - return -1; - } - TCFREE(tvbuf); - return tvsiz - 1; - } - } - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return -1; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return -1; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - if(hdb->zmode){ - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - TCFREE(rec.bbuf); - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - return -1; - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); - } - TCFREE(zbuf); - return zsiz; +static int tchdbvsizimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx, uint8_t hash) { + assert(hdb && kbuf && ksiz >= 0); + if (hdb->recc) { + int tvsiz; + char *tvbuf = tcmdbget(hdb->recc, kbuf, ksiz, &tvsiz); + if (tvbuf) { + if (*tvbuf == '*') { + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + TCFREE(tvbuf); + return -1; + } + TCFREE(tvbuf); + return tvsiz - 1; } - if(hdb->recc && rec.vbuf){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return -1; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return -1; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + if (hdb->zmode) { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return -1; + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + TCFREE(rec.bbuf); + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + return -1; + } + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, zbuf, zsiz); + } + TCFREE(zbuf); + return zsiz; + } + if (hdb->recc && rec.vbuf) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput4(hdb->recc, kbuf, ksiz, "=", 1, rec.vbuf, rec.vsiz); + } + TCFREE(rec.bbuf); + return rec.vsiz; + } } - TCFREE(rec.bbuf); - return rec.vsiz; - } } - } - if(hdb->recc){ - if(tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); - tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return -1; + if (hdb->recc) { + if (tcmdbrnum(hdb->recc) >= hdb->rcnum) tchdbcacheadjust(hdb); + tcmdbput(hdb->recc, kbuf, ksiz, "*", 1); + } + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return -1; } - /* Initialize the iterator of a hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -static bool tchdbiterinitimpl(TCHDB *hdb){ - assert(hdb); - hdb->iter = hdb->frec; - return true; +static bool tchdbiterinitimpl(TCHDB *hdb) { + assert(hdb); + hdb->iter = hdb->frec; + return true; } - /* Get the next key of the iterator of a hash database object. `hdb' specifies the hash database object. `sp' specifies the pointer to the variable into which the size of the region of the return value is assigned. If successful, the return value is the pointer to the region of the next key, else, it is `NULL'. */ -static char *tchdbiternextimpl(TCHDB *hdb, int *sp){ - assert(hdb && sp); - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(hdb->iter < hdb->fsiz){ - rec.off = hdb->iter; - if(!tchdbreadrec(hdb, &rec, rbuf)) return NULL; - hdb->iter += rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(rec.kbuf){ - *sp = rec.ksiz; - char *rv; - TCMEMDUP(rv, rec.kbuf, rec.ksiz); - return rv; - } - if(!tchdbreadrecbody(hdb, &rec)) return NULL; - rec.bbuf[rec.ksiz] = '\0'; - *sp = rec.ksiz; - return rec.bbuf; +static char *tchdbiternextimpl(TCHDB *hdb, int *sp) { + assert(hdb && sp); + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (hdb->iter < hdb->fsiz) { + rec.off = hdb->iter; + if (!tchdbreadrec(hdb, &rec, rbuf)) return NULL; + hdb->iter += rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (rec.kbuf) { + *sp = rec.ksiz; + char *rv; + TCMEMDUP(rv, rec.kbuf, rec.ksiz); + return rv; + } + if (!tchdbreadrecbody(hdb, &rec)) return NULL; + rec.bbuf[rec.ksiz] = '\0'; + *sp = rec.ksiz; + return rec.bbuf; + } } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return NULL; + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return NULL; } - /* Get the next extensible objects of the iterator of a hash database object. */ -static bool tchdbiternextintoxstr(TCHDB *hdb, TCXSTR *kxstr, TCXSTR *vxstr){ +static bool tchdbiternextintoxstr(TCHDB *hdb, TCXSTR *kxstr, TCXSTR *vxstr) { return tchdbiternextintoxstr2(hdb, &(hdb->iter), kxstr, vxstr); } -static bool tchdbiternextintoxstr2(TCHDB *hdb, uint64_t *iter, TCXSTR *kxstr, TCXSTR *vxstr){ - assert(hdb && kxstr && vxstr); - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(*iter < hdb->fsiz){ - rec.off = *iter; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - *iter = *iter + rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return false; - tcxstrclear(kxstr); - TCXSTRCAT(kxstr, rec.kbuf, rec.ksiz); - tcxstrclear(vxstr); - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - if(!zbuf){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - TCFREE(rec.bbuf); - return false; +static bool tchdbiternextintoxstr2(TCHDB *hdb, uint64_t *iter, TCXSTR *kxstr, TCXSTR *vxstr) { + assert(hdb && kxstr && vxstr); + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (*iter < hdb->fsiz) { + rec.off = *iter; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + *iter = *iter + rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) return false; + tcxstrclear(kxstr); + TCXSTRCAT(kxstr, rec.kbuf, rec.ksiz); + tcxstrclear(vxstr); + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + if (!zbuf) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + TCFREE(rec.bbuf); + return false; + } + TCXSTRCAT(vxstr, zbuf, zsiz); + TCFREE(zbuf); + } else { + TCXSTRCAT(vxstr, rec.vbuf, rec.vsiz); + } + TCFREE(rec.bbuf); + return true; } - TCXSTRCAT(vxstr, zbuf, zsiz); - TCFREE(zbuf); - } else { - TCXSTRCAT(vxstr, rec.vbuf, rec.vsiz); - } - TCFREE(rec.bbuf); - return true; } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; } - /* Optimize the file of a hash database object. `hdb' specifies the hash database object. `bnum' specifies the number of elements of the bucket array. @@ -4930,426 +4837,434 @@ static bool tchdbiternextintoxstr2(TCHDB *hdb, uint64_t *iter, TCXSTR *kxstr, TC `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 tchdboptimizeimpl(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts){ - assert(hdb); - bool err = false; - char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", hdb->path, MYEXTCHR, MYEXTCHR, hdb->inode); - int omode = (hdb->omode & ~HDBOCREAT) & ~HDBOTRUNC; - TCHDB *thdb = tchdbnew(); - thdb->dbgfd = hdb->dbgfd; - thdb->enc = hdb->enc; - thdb->encop = hdb->encop; - thdb->dec = hdb->dec; - thdb->decop = hdb->decop; - if(bnum < 1){ - bnum = hdb->rnum * 2 + 1; - if(bnum < HDBDEFBNUM) bnum = HDBDEFBNUM; - } - if(apow < 0) apow = hdb->apow; - if(fpow < 0) fpow = hdb->fpow; - if(opts == UINT8_MAX) opts = hdb->opts; - tchdbtune(thdb, bnum, apow, fpow, opts); - if(!tchdbopen(thdb, tpath, HDBOWRITER | HDBOCREAT | HDBOTRUNC) || - !tchdbcopyopaque(thdb, hdb, 0, HDBOPAQUESZ)){ - tchdbdel(thdb); - TCFREE(tpath); - return false; - } - - uint64_t off = hdb->frec; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off < hdb->fsiz){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)){ - err = true; - break; - } - off += rec.rsiz; - if(rec.magic != HDBMAGICREC){ - continue; - } - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - if (rec.bbuf) TCFREE(rec.bbuf); - err = true; - break; - } - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - if(zbuf){ - if(!tchdbput(thdb, rec.kbuf, rec.ksiz, zbuf, zsiz)){ - tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); - err = true; +static bool tchdboptimizeimpl(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts) { + assert(hdb); + bool err = false; + char *tpath = tcsprintf("%s%ctmp%c%" PRIuMAX "", hdb->path, MYEXTCHR, MYEXTCHR, hdb->inode); + int omode = (hdb->omode & ~HDBOCREAT) & ~HDBOTRUNC; + TCHDB *thdb = tchdbnew(); + thdb->dbgfd = hdb->dbgfd; + thdb->enc = hdb->enc; + thdb->encop = hdb->encop; + thdb->dec = hdb->dec; + thdb->decop = hdb->decop; + if (bnum < 1) { + bnum = hdb->rnum * 2 + 1; + if (bnum < HDBDEFBNUM) bnum = HDBDEFBNUM; + } + if (apow < 0) apow = hdb->apow; + if (fpow < 0) fpow = hdb->fpow; + if (opts == UINT8_MAX) opts = hdb->opts; + tchdbtune(thdb, bnum, apow, fpow, opts); + if (!tchdbopen(thdb, tpath, HDBOWRITER | HDBOCREAT | HDBOTRUNC) || + !tchdbcopyopaque(thdb, hdb, 0, HDBOPAQUESZ)) { + tchdbdel(thdb); + TCFREE(tpath); + return false; + } + + uint64_t off = hdb->frec; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off < hdb->fsiz) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) { + err = true; + break; } - TCFREE(zbuf); - } else { - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + off += rec.rsiz; + if (rec.magic != HDBMAGICREC) { + continue; + } + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + if (rec.bbuf) TCFREE(rec.bbuf); + err = true; + break; + } + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + if (zbuf) { + if (!tchdbput(thdb, rec.kbuf, rec.ksiz, zbuf, zsiz)) { + tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); + err = true; + } + TCFREE(zbuf); + } else { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + err = true; + } + } else { + if (!tchdbput(thdb, rec.kbuf, rec.ksiz, rec.vbuf, rec.vsiz)) { + tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); + err = true; + } + } + TCFREE(rec.bbuf); + } + if (!tchdbclose(thdb)) { + tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); err = true; - } + } + bool esc = false; + if (err && (hdb->omode & HDBONOLCK) && !thdb->fatal) { + err = false; + esc = true; + } + tchdbdel(thdb); + if (err) { + TCFREE(tpath); + return false; + } + char *opath = tcstrdup(hdb->path); + if (!tchdbcloseimpl(hdb)) { + TCFREE(opath); + TCFREE(tpath); + return false; + } + + if (esc) { + char *bpath = tcsprintf("%s%cbroken", tpath, MYEXTCHR); + if (!tcrenamefile(opath, bpath)) { + tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + TCFREE(bpath); } else { - if(!tchdbput(thdb, rec.kbuf, rec.ksiz, rec.vbuf, rec.vsiz)){ - tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); + if (!tcunlinkfile(opath)) { + tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); + err = true; + } + } + + if (!tcrenamefile(tpath, opath)) { + tchdbsetecode(hdb, TCERENAME, __FILE__, __LINE__, __func__); err = true; - } - } - TCFREE(rec.bbuf); - } - if(!tchdbclose(thdb)){ - tchdbsetecode(hdb, thdb->ecode, __FILE__, __LINE__, __func__); - err = true; - } - bool esc = false; - if(err && (hdb->omode & HDBONOLCK) && !thdb->fatal){ - err = false; - esc = true; - } - tchdbdel(thdb); - if(err){ - TCFREE(tpath); - return false; - } - char *opath = tcstrdup(hdb->path); - if(!tchdbcloseimpl(hdb)){ - TCFREE(opath); + } TCFREE(tpath); - return false; - } - - if(esc){ - char *bpath = tcsprintf("%s%cbroken", tpath, MYEXTCHR); - if(!tcrenamefile(opath, bpath)){ - tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(bpath); - } else { - if(!tcunlinkfile(opath)){ - tchdbsetecode(hdb, TCEUNLINK, __FILE__, __LINE__, __func__); - err = true; - } - } - - if(!tcrenamefile(tpath, opath)){ - tchdbsetecode(hdb, TCERENAME, __FILE__, __LINE__, __func__); - err = true; - } - TCFREE(tpath); - if(err) { + if (err) { + TCFREE(opath); + return false; + } + bool rv = tchdbopenimpl(hdb, opath, omode); TCFREE(opath); - return false; - } - bool rv = tchdbopenimpl(hdb, opath, omode); - TCFREE(opath); - return rv; + return rv; } - /* Remove all records of a hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -static bool tchdbvanishimpl(TCHDB *hdb){ - assert(hdb); - char *path = tcstrdup(hdb->path); - int omode = hdb->omode; - bool err = false; - if(!tchdbcloseimpl(hdb)) err = true; - if(!tchdbopenimpl(hdb, path, HDBOTRUNC | omode)){ - tcpathunlock(hdb->rpath); - TCFREE(hdb->rpath); - err = true; - } - TCFREE(path); - return !err; +static bool tchdbvanishimpl(TCHDB *hdb) { + assert(hdb); + char *path = tcstrdup(hdb->path); + int omode = hdb->omode; + bool err = false; + if (!tchdbcloseimpl(hdb)) err = true; + if (!tchdbopenimpl(hdb, path, HDBOTRUNC | omode)) { + tcpathunlock(hdb->rpath); + TCFREE(hdb->rpath); + err = true; + } + TCFREE(path); + return !err; } - /* Copy the database file of a hash database object. `hdb' specifies the hash database object. `path' specifies the path of the destination file. If successful, the return value is true, else, it is false. */ -static bool tchdbcopyimpl(TCHDB *hdb, const char *path){ - assert(hdb && path); - bool err = false; - if(hdb->omode & HDBOWRITER){ - if(!tchdbsavefbp(hdb)) err = true; - if(!tchdbmemsync(hdb, false)) err = true; - tchdbsetflag(hdb, HDBFOPEN, false); - } - if(*path == '@'){ - char tsbuf[TCNUMBUFSIZ]; - sprintf(tsbuf, "%" PRIuMAX "", (unsigned long long)(tctime() * 1000000)); - const char *args[3]; - args[0] = path + 1; - args[1] = hdb->path; - args[2] = tsbuf; - if(tcsystem(args, sizeof(args) / sizeof(*args)) != 0) err = true; - } else { - if(!tccopyfile(hdb->path, path)){ - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); - err = true; - } - } - if(hdb->omode & HDBOWRITER) tchdbsetflag(hdb, HDBFOPEN, true); - return !err; +static bool tchdbcopyimpl(TCHDB *hdb, const char *path) { + assert(hdb && path); + bool err = false; + if (hdb->omode & HDBOWRITER) { + if (!tchdbsavefbp(hdb)) err = true; + if (!tchdbmemsync(hdb, false)) err = true; + tchdbsetflag(hdb, HDBFOPEN, false); + } + if (*path == '@') { + char tsbuf[TCNUMBUFSIZ]; + sprintf(tsbuf, "%" PRIuMAX "", (unsigned long long) (tctime() * 1000000)); + const char *args[3]; + args[0] = path + 1; + args[1] = hdb->path; + args[2] = tsbuf; + if (tcsystem(args, sizeof (args) / sizeof (*args)) != 0) err = true; + } else { + if (!tccopyfile(hdb->path, path)) { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + err = true; + } + } + if (hdb->omode & HDBOWRITER) tchdbsetflag(hdb, HDBFOPEN, true); + return !err; } - /* Perform dynamic defragmentation of a hash database object. `hdb' specifies the hash database object connected. `step' specifie the number of steps. If successful, the return value is true, else, it is false. */ -static bool tchdbdefragimpl(TCHDB *hdb, int64_t step){ - assert(hdb && step >= 0); - TCDODEBUG(hdb->cnt_defrag++); - hdb->dfcnt = 0; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - bool err = false; - while(true){ - if(hdb->dfcur >= hdb->fsiz){ - hdb->dfcur = hdb->frec; - return true; - } - if(step-- < 1) return true; - rec.off = hdb->dfcur; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - if(rec.magic == HDBMAGICFB) break; - hdb->dfcur += rec.rsiz; - } - uint32_t align = hdb->align; - uint64_t base = hdb->dfcur; - uint64_t dest = base; - uint64_t cur = base; - if(hdb->iter == cur) hdb->iter += rec.rsiz; - cur += rec.rsiz; - uint64_t fbsiz = cur - dest; - step++; - while(step > 0 && cur < hdb->fsiz){ - rec.off = cur; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - uint32_t rsiz = rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(rec.psiz >= align){ - int diff = rec.psiz - rec.psiz % align; - rec.psiz -= diff; - rec.rsiz -= diff; - fbsiz += diff; - } - if(!tchdbshiftrec(hdb, &rec, rbuf, dest)) { - fprintf(stderr, "\n %d %d %d %d @000010\n", (int) cur, (int) hdb->fsiz, (int) (hdb->fsiz - cur), (int) rsiz); - return false; - } - if(hdb->iter == cur) hdb->iter = dest; - dest += rec.rsiz; - step--; - } else { - if(hdb->iter == cur) hdb->iter += rec.rsiz; - fbsiz += rec.rsiz; - } - cur += rsiz; - } - if(cur < hdb->fsiz){ - if(fbsiz > HDBFBMAXSIZ){ - tchdbfbptrim(hdb, base, cur, 0, 0); - uint64_t off = dest; - uint64_t size = fbsiz; - while(size > 0){ - uint32_t rsiz = (size > HDBFBMAXSIZ) ? HDBFBMAXSIZ : size; - if(size - rsiz < HDBMINRUNIT) rsiz = size; - tchdbfbpinsert(hdb, off, rsiz); - if(!tchdbwritefb(hdb, off, rsiz)) return false; - off += rsiz; - size -= rsiz; - } - } else { - tchdbfbptrim(hdb, base, cur, dest, fbsiz); - if(!tchdbwritefb(hdb, dest, fbsiz)) return false; - } - hdb->dfcur = cur - fbsiz; - } else { - TCDODEBUG(hdb->cnt_trunc++); - if(hdb->tran && !tchdbwalwrite(hdb, dest, fbsiz)) { - return false; - } - tchdbfbptrim(hdb, base, cur, 0, 0); - hdb->dfcur = hdb->frec; - hdb->fsiz = dest; - uint64_t llnum = hdb->fsiz; - llnum = TCHTOILL(llnum); - if (HDBLOCKSMEM(hdb, true)) { - memcpy((void *)(hdb->map + HDBFSIZOFF), &llnum, sizeof(llnum)); - HDBUNLOCKSMEM(hdb); +static bool tchdbdefragimpl(TCHDB *hdb, int64_t step) { + assert(hdb && step >= 0); + TCDODEBUG(hdb->cnt_defrag++); + hdb->dfcnt = 0; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + bool err = false; + while (true) { + if (hdb->dfcur >= hdb->fsiz) { + hdb->dfcur = hdb->frec; + return true; + } + if (step-- < 1) return true; + rec.off = hdb->dfcur; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + if (rec.magic == HDBMAGICFB) break; + hdb->dfcur += rec.rsiz; + } + uint32_t align = hdb->align; + uint64_t base = hdb->dfcur; + uint64_t dest = base; + uint64_t cur = base; + if (hdb->iter == cur) hdb->iter += rec.rsiz; + cur += rec.rsiz; + uint64_t fbsiz = cur - dest; + step++; + while (step > 0 && cur < hdb->fsiz) { + rec.off = cur; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + uint32_t rsiz = rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (rec.psiz >= align) { + int diff = rec.psiz - rec.psiz % align; + rec.psiz -= diff; + rec.rsiz -= diff; + fbsiz += diff; + } + if (!tchdbshiftrec(hdb, &rec, rbuf, dest)) { + fprintf(stderr, "\n %d %d %d %d @000010\n", (int) cur, (int) hdb->fsiz, (int) (hdb->fsiz - cur), (int) rsiz); + return false; + } + if (hdb->iter == cur) hdb->iter = dest; + dest += rec.rsiz; + step--; + } else { + if (hdb->iter == cur) hdb->iter += rec.rsiz; + fbsiz += rec.rsiz; + } + cur += rsiz; + } + if (cur < hdb->fsiz) { + if (fbsiz > HDBFBMAXSIZ) { + tchdbfbptrim(hdb, base, cur, 0, 0); + uint64_t off = dest; + uint64_t size = fbsiz; + while (size > 0) { + uint32_t rsiz = (size > HDBFBMAXSIZ) ? HDBFBMAXSIZ : size; + if (size - rsiz < HDBMINRUNIT) rsiz = size; + tchdbfbpinsert(hdb, off, rsiz); + if (!tchdbwritefb(hdb, off, rsiz)) return false; + off += rsiz; + size -= rsiz; + } + } else { + tchdbfbptrim(hdb, base, cur, dest, fbsiz); + if (!tchdbwritefb(hdb, dest, fbsiz)) return false; + } + hdb->dfcur = cur - fbsiz; } else { - err = true; - } - if(hdb->iter >= hdb->fsiz) { - hdb->iter = UINT64_MAX; - } - if(!hdb->tran && !tchdbftruncate(hdb, hdb->fsiz)){ - tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); - return false; + TCDODEBUG(hdb->cnt_trunc++); + if (hdb->tran && !tchdbwalwrite(hdb, dest, fbsiz)) { + return false; + } + tchdbfbptrim(hdb, base, cur, 0, 0); + hdb->dfcur = hdb->frec; + hdb->fsiz = dest; + uint64_t llnum = hdb->fsiz; + llnum = TCHTOILL(llnum); + if (HDBLOCKSMEM(hdb, false)) { + memcpy((void *) (hdb->map + HDBFSIZOFF), &llnum, sizeof (llnum)); + HDBUNLOCKSMEM(hdb); + } else { + err = true; + } + if (hdb->iter >= hdb->fsiz) { + hdb->iter = UINT64_MAX; + } + if (!hdb->tran && !tchdbftruncate(hdb, hdb->fsiz)) { + tchdbsetecode(hdb, TCETRUNC, __FILE__, __LINE__, __func__); + return false; + } } - } - return !err; + return !err; } - /* Move the iterator to the record corresponding a key of a hash database object. `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. If successful, the return value is true, else, it is false. */ -static bool tchdbiterjumpimpl(TCHDB *hdb, const char *kbuf, int ksiz){ - assert(hdb && kbuf && ksiz); - uint8_t hash; - uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); - off_t off = tchdbgetbucket(hdb, bidx); - if (off == -1) return false; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - while(off > 0){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)) return false; - if(hash > rec.hash){ - off = rec.left; - } else if(hash < rec.hash){ - off = rec.right; - } else { - if(!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; - int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); - if(kcmp > 0){ - off = rec.left; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else if(kcmp < 0){ - off = rec.right; - TCFREE(rec.bbuf); - rec.kbuf = NULL; - rec.bbuf = NULL; - } else { - hdb->iter = off; - return true; - } +static bool tchdbiterjumpimpl(TCHDB *hdb, const char *kbuf, int ksiz) { + assert(hdb && kbuf && ksiz); + uint8_t hash; + uint64_t bidx = tchdbbidx(hdb, kbuf, ksiz, &hash); + off_t off = tchdbgetbucket(hdb, bidx); + if (off == -1) return false; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + while (off > 0) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) return false; + if (hash > rec.hash) { + off = rec.left; + } else if (hash < rec.hash) { + off = rec.right; + } else { + if (!rec.kbuf && !tchdbreadrecbody(hdb, &rec)) return false; + int kcmp = tcreckeycmp(kbuf, ksiz, rec.kbuf, rec.ksiz); + if (kcmp > 0) { + off = rec.left; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else if (kcmp < 0) { + off = rec.right; + TCFREE(rec.bbuf); + rec.kbuf = NULL; + rec.bbuf = NULL; + } else { + hdb->iter = off; + return true; + } + } } - } - tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); - return false; + tchdbsetecode(hdb, TCENOREC, __FILE__, __LINE__, __func__); + return false; } - /* Process each record atomically of a hash database object. `hdb' specifies the hash database object. `func' specifies the pointer to the iterator function called for each record. `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If successful, the return value is true, else, it is false. */ -static bool tchdbforeachimpl(TCHDB *hdb, TCITER iter, void *op){ - assert(hdb && iter); - bool err = false; - uint64_t off = hdb->frec; - TCHREC rec; - char rbuf[HDBIOBUFSIZ]; - bool cont = true; - while(cont && off < hdb->fsiz){ - rec.off = off; - if(!tchdbreadrec(hdb, &rec, rbuf)){ - err = true; - break; - } - off += rec.rsiz; - if(rec.magic == HDBMAGICREC){ - if(!rec.vbuf && !tchdbreadrecbody(hdb, &rec)){ - TCFREE(rec.bbuf); - err = true; - } else { - if(hdb->zmode){ - int zsiz; - char *zbuf; - if(hdb->opts & HDBTDEFLATE){ - zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); - } else if(hdb->opts & HDBTBZIP){ - zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); - } else if(hdb->opts & HDBTTCBS){ - zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); - } else { - zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); - } - if(zbuf){ - cont = iter(rec.kbuf, rec.ksiz, zbuf, zsiz, op); - TCFREE(zbuf); - } else { - tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); +static bool tchdbforeachimpl(TCHDB *hdb, TCITER iter, void *op) { + assert(hdb && iter); + bool err = false; + uint64_t off = hdb->frec; + TCHREC rec; + char rbuf[HDBIOBUFSIZ]; + bool cont = true; + while (cont && off < hdb->fsiz) { + rec.off = off; + if (!tchdbreadrec(hdb, &rec, rbuf)) { err = true; - } - } else { - cont = iter(rec.kbuf, rec.ksiz, rec.vbuf, rec.vsiz, op); + break; + } + off += rec.rsiz; + if (rec.magic == HDBMAGICREC) { + if (!rec.vbuf && !tchdbreadrecbody(hdb, &rec)) { + TCFREE(rec.bbuf); + err = true; + } else { + if (hdb->zmode) { + int zsiz; + char *zbuf; + if (hdb->opts & HDBTDEFLATE) { + zbuf = _tc_inflate(rec.vbuf, rec.vsiz, &zsiz, _TCZMRAW); + } else if (hdb->opts & HDBTBZIP) { + zbuf = _tc_bzdecompress(rec.vbuf, rec.vsiz, &zsiz); + } else if (hdb->opts & HDBTTCBS) { + zbuf = tcbsdecode(rec.vbuf, rec.vsiz, &zsiz); + } else { + zbuf = hdb->dec(rec.vbuf, rec.vsiz, &zsiz, hdb->decop); + } + if (zbuf) { + cont = iter(rec.kbuf, rec.ksiz, zbuf, zsiz, op); + TCFREE(zbuf); + } else { + tchdbsetecode(hdb, TCEMISC, __FILE__, __LINE__, __func__); + err = true; + } + } else { + cont = iter(rec.kbuf, rec.ksiz, rec.vbuf, rec.vsiz, op); + } + } + TCFREE(rec.bbuf); } - } - TCFREE(rec.bbuf); } - } - return !err; + return !err; } - /* Lock a method of the hash database object. `hdb' specifies the hash database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdblockmethod(TCHDB *hdb, bool wr){ - assert(hdb); - if(wr ? pthread_rwlock_wrlock(hdb->mmtx) != 0 : pthread_rwlock_rdlock(hdb->mmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdblockmethod(TCHDB *hdb, bool wr) { + assert(hdb); + if (wr ? pthread_rwlock_wrlock(hdb->mmtx) != 0 : pthread_rwlock_rdlock(hdb->mmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock a method of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdbunlockmethod(TCHDB *hdb){ - assert(hdb); - if(pthread_rwlock_unlock(hdb->mmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdbunlockmethod(TCHDB *hdb) { + assert(hdb); + if (pthread_rwlock_unlock(hdb->mmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } /* Lock shared memory */ -EJDB_INLINE bool tchdblocksmem(TCHDB *hdb, bool wr){ - assert(hdb); - if(wr ? pthread_rwlock_wrlock(hdb->smtx) != 0 : pthread_rwlock_rdlock(hdb->smtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdblocksmem(TCHDB *hdb, bool wr) { + assert(hdb); + if (wr ? pthread_rwlock_wrlock(hdb->smtx) != 0 : pthread_rwlock_rdlock(hdb->smtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + if (hdb->map == NULL) { + tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); + tchdbunlocksmem(hdb); + return false; + } + TCTESTYIELD(); + return true; +} + +EJDB_INLINE bool tchdblocksmem2(TCHDB *hdb, bool wr) { + assert(hdb); + if (wr ? pthread_rwlock_wrlock(hdb->smtx) != 0 : pthread_rwlock_rdlock(hdb->smtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } /* Unlock shared memory */ -EJDB_INLINE bool tchdbunlocksmem(TCHDB *hdb){ - assert(hdb); - if(pthread_rwlock_unlock(hdb->smtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdbunlocksmem(TCHDB *hdb) { + assert(hdb); + if (pthread_rwlock_unlock(hdb->smtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } /* Lock a record of the hash database object. @@ -5357,125 +5272,118 @@ EJDB_INLINE bool tchdbunlocksmem(TCHDB *hdb){ `bidx' specifies the bucket index of the record. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdblockrecord(TCHDB *hdb, uint8_t bidx, bool wr){ - assert(hdb); - if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)hdb->rmtxs + bidx) != 0 : - pthread_rwlock_rdlock((pthread_rwlock_t *)hdb->rmtxs + bidx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdblockrecord(TCHDB *hdb, uint8_t bidx, bool wr) { + assert(hdb); + if (wr ? pthread_rwlock_wrlock((pthread_rwlock_t *) hdb->rmtxs + bidx) != 0 : + pthread_rwlock_rdlock((pthread_rwlock_t *) hdb->rmtxs + bidx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock a record of the hash database object. `hdb' specifies the hash database object. `bidx' specifies the bucket index of the record. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdbunlockrecord(TCHDB *hdb, uint8_t bidx){ - assert(hdb); - if(pthread_rwlock_unlock((pthread_rwlock_t *)hdb->rmtxs + bidx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdbunlockrecord(TCHDB *hdb, uint8_t bidx) { + assert(hdb); + if (pthread_rwlock_unlock((pthread_rwlock_t *) hdb->rmtxs + bidx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock all records of the hash database object. `hdb' specifies the hash database object. `wr' specifies whether the lock is writer or not. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdblockallrecords(TCHDB *hdb, bool wr){ - assert(hdb); - for(int i = 0; i <= UINT8_MAX; i++){ - if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)hdb->rmtxs + i) != 0 : - pthread_rwlock_rdlock((pthread_rwlock_t *)hdb->rmtxs + i) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - while(--i >= 0){ - pthread_rwlock_unlock((pthread_rwlock_t *)hdb->rmtxs + i); - } - return false; +EJDB_INLINE bool tchdblockallrecords(TCHDB *hdb, bool wr) { + assert(hdb); + for (int i = 0; i <= UINT8_MAX; i++) { + if (wr ? pthread_rwlock_wrlock((pthread_rwlock_t *) hdb->rmtxs + i) != 0 : + pthread_rwlock_rdlock((pthread_rwlock_t *) hdb->rmtxs + i) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + while (--i >= 0) { + pthread_rwlock_unlock((pthread_rwlock_t *) hdb->rmtxs + i); + } + return false; + } } - } - TCTESTYIELD(); - return true; + TCTESTYIELD(); + return true; } - /* Unlock all records of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdbunlockallrecords(TCHDB *hdb){ - assert(hdb); - bool err = false; - for(int i = UINT8_MAX; i >= 0; i--){ - if(pthread_rwlock_unlock((pthread_rwlock_t *)hdb->rmtxs + i)) err = true; - } - TCTESTYIELD(); - if(err){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - return true; +EJDB_INLINE bool tchdbunlockallrecords(TCHDB *hdb) { + assert(hdb); + bool err = false; + for (int i = UINT8_MAX; i >= 0; i--) { + if (pthread_rwlock_unlock((pthread_rwlock_t *) hdb->rmtxs + i)) err = true; + } + TCTESTYIELD(); + if (err) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + return true; } - /* Lock the whole database of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdblockdb(TCHDB *hdb){ - assert(hdb); - if(pthread_mutex_lock(hdb->dmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdblockdb(TCHDB *hdb) { + assert(hdb); + if (pthread_mutex_lock(hdb->dmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock the whole database of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdbunlockdb(TCHDB *hdb){ - assert(hdb); - if(pthread_mutex_unlock(hdb->dmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdbunlockdb(TCHDB *hdb) { + assert(hdb); + if (pthread_mutex_unlock(hdb->dmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Lock the write ahead logging file of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdblockwal(TCHDB *hdb){ - assert(hdb); - if(pthread_mutex_lock(hdb->wmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdblockwal(TCHDB *hdb) { + assert(hdb); + if (pthread_mutex_lock(hdb->wmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } - /* Unlock the write ahead logging file of the hash database object. `hdb' specifies the hash database object. If successful, the return value is true, else, it is false. */ -EJDB_INLINE bool tchdbunlockwal(TCHDB *hdb){ - assert(hdb); - if(pthread_mutex_unlock(hdb->wmtx) != 0){ - tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); - return false; - } - TCTESTYIELD(); - return true; +EJDB_INLINE bool tchdbunlockwal(TCHDB *hdb) { + assert(hdb); + if (pthread_mutex_unlock(hdb->wmtx) != 0) { + tchdbsetecode(hdb, TCETHREAD, __FILE__, __LINE__, __func__); + return false; + } + TCTESTYIELD(); + return true; } static bool tchdbftruncate(TCHDB *hdb, off_t length) { @@ -5485,12 +5393,12 @@ static bool tchdbftruncate(TCHDB *hdb, off_t length) { static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts) { #ifndef _WIN32 length = length ? tcpagealign(length) : 0; - if (!(hdb->omode & HDBOWRITER) || (length <= hdb->xfsiz && !(opts & HDBTRUNCSHRINKFILE))) { + if (!(hdb->omode & HDBOWRITER) || (length <= hdb->xfsiz && !(opts & HDBTRALLOWSHRINK))) { return true; } - if (length > hdb->xfsiz && !(opts & HDBTRUNCSHRINKFILE)) { + if (length > hdb->xfsiz && !(opts & HDBTRALLOWSHRINK)) { off_t o1 = tcpagealign((_maxof(off_t) - length < HDBXFSIZINC) ? length : length + HDBXFSIZINC); - off_t o2 = tcpagealign(((long double) 1.5) * length); + off_t o2 = tcpagealign((((uint64_t) length) * 3) >> 1); length = MAX(o1, o2); } if (ftruncate(hdb->fd, length) == 0) { @@ -5503,18 +5411,18 @@ static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts) { bool err = false; LARGE_INTEGER size; //MSDN: Applications should test for files with a length of 0 (zero) and reject those files. - size.QuadPart = (hdb->omode & HDBOWRITER) ? tcpagealign((length == 0) ? 1 : length) : length; + size.QuadPart = (hdb->omode & HDBOWRITER) ? tcpagealign((length == 0) ? 1 : length) : length; if (hdb->map && - length > 0 && - (!(hdb->omode & HDBOWRITER) || (size.QuadPart <= hdb->xfsiz && !(opts & HDBTRUNCSHRINKFILE)))) { + length > 0 && + (!(hdb->omode & HDBOWRITER) || (size.QuadPart <= hdb->xfsiz && !(opts & HDBTRALLOWSHRINK)))) { return true; } - if (!(opts & HDBWRITENOLOCK) && !HDBLOCKSMEM(hdb, true)) { + if (!(opts & HDBWRITENOLOCK) && !HDBLOCKSMEM2(hdb, true)) { return false; } - if ((hdb->omode & HDBOWRITER) && size.QuadPart > hdb->xfsiz && !(opts & HDBTRUNCSHRINKFILE)) { - off_t o1 = tcpagealign((_maxof(off_t) - size.QuadPart < HDBXFSIZINC) ? size.QuadPart : size.QuadPart + HDBXFSIZINC); - off_t o2 = tcpagealign(((long double) 1.5) * size.QuadPart); + if ((hdb->omode & HDBOWRITER) && size.QuadPart > hdb->xfsiz && !(opts & HDBTRALLOWSHRINK)) { + off_t o1 = tcpagealign((_maxof(off_t) - (off_t) size.QuadPart < HDBXFSIZINC) ? size.QuadPart : size.QuadPart + HDBXFSIZINC); + off_t o2 = tcpagealign((((uint64_t) size.QuadPart) * 3) >> 1); size.QuadPart = MAX(o1, o2); } if (hdb->map) { @@ -5569,113 +5477,115 @@ finish: * debugging functions *************************************************************************************************/ - /* Print meta data of the header into the debugging output. `hdb' specifies the hash database object. */ -void tchdbprintmeta(TCHDB *hdb){ - assert(hdb); - HANDLE dbgfd = hdb->dbgfd; - if(INVALIDHANDLE(dbgfd)) { - dbgfd = GET_STDOUT_HANDLE(); - } - char buf[HDBIOBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "META:"); - wp += sprintf(wp, " mmtx=%p", (void *)hdb->mmtx); - wp += sprintf(wp, " rmtxs=%p", (void *)hdb->rmtxs); - wp += sprintf(wp, " dmtx=%p", (void *)hdb->dmtx); - wp += sprintf(wp, " smtx=%p", (void *)hdb->smtx); - wp += sprintf(wp, " wmtx=%p", (void *)hdb->wmtx); - wp += sprintf(wp, " eckey=%p", (void *)hdb->eckey); - wp += sprintf(wp, " rpath=%s", hdb->rpath ? hdb->rpath : "-"); - wp += sprintf(wp, " type=%02X", hdb->type); - wp += sprintf(wp, " flags=%02X", hdb->flags); - wp += sprintf(wp, " bnum=%" PRIuMAX "", (unsigned long long)hdb->bnum); - wp += sprintf(wp, " apow=%u", hdb->apow); - wp += sprintf(wp, " fpow=%u", hdb->fpow); - wp += sprintf(wp, " opts=%u", hdb->opts); - wp += sprintf(wp, " path=%s", hdb->path ? hdb->path : "-"); - wp += sprintf(wp, " fd=%d", hdb->fd); - wp += sprintf(wp, " omode=%u", hdb->omode); - wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long)hdb->rnum); - wp += sprintf(wp, " fsiz=%" PRIuMAX "", (unsigned long long)hdb->fsiz); - wp += sprintf(wp, " frec=%" PRIuMAX "", (unsigned long long)hdb->frec); - wp += sprintf(wp, " dfcur=%" PRIuMAX "", (unsigned long long)hdb->dfcur); - wp += sprintf(wp, " iter=%" PRIuMAX "", (unsigned long long)hdb->iter); - wp += sprintf(wp, " map=%p", (void *)hdb->map); - wp += sprintf(wp, " msiz=%" PRIuMAX "", (unsigned long long)hdb->msiz); - wp += sprintf(wp, " ba64=%d", hdb->ba64); - wp += sprintf(wp, " align=%u", hdb->align); - wp += sprintf(wp, " runit=%u", hdb->runit); - wp += sprintf(wp, " zmode=%u", hdb->zmode); - wp += sprintf(wp, " fbpmax=%d", hdb->fbpmax); - wp += sprintf(wp, " fbpool=%p", (void *)hdb->fbpool); - wp += sprintf(wp, " fbpnum=%d", hdb->fbpnum); - wp += sprintf(wp, " fbpmis=%d", hdb->fbpmis); - wp += sprintf(wp, " drpool=%p", (void *)hdb->drpool); - wp += sprintf(wp, " drpdef=%p", (void *)hdb->drpdef); - wp += sprintf(wp, " drpoff=%" PRIuMAX "", (unsigned long long)hdb->drpoff); - wp += sprintf(wp, " recc=%p", (void *)hdb->recc); - wp += sprintf(wp, " rcnum=%u", hdb->rcnum); - wp += sprintf(wp, " ecode=%d", hdb->ecode); - wp += sprintf(wp, " fatal=%u", hdb->fatal); - wp += sprintf(wp, " inode=%" PRIuMAX "", (unsigned long long)(uint64_t)hdb->inode); - wp += sprintf(wp, " mtime=%" PRIuMAX "", (unsigned long long)(uint64_t)hdb->mtime); - wp += sprintf(wp, " dfunit=%u", hdb->dfunit); - wp += sprintf(wp, " dfcnt=%u", hdb->dfcnt); - wp += sprintf(wp, " tran=%d", hdb->tran); - wp += sprintf(wp, " walfd=%d", hdb->walfd); - wp += sprintf(wp, " walend=%" PRIuMAX "", (unsigned long long)hdb->walend); - wp += sprintf(wp, " dbgfd=%d", hdb->dbgfd); - wp += sprintf(wp, " cnt_writerec=%" PRIdMAX "", (long long)hdb->cnt_writerec); - wp += sprintf(wp, " cnt_reuserec=%" PRIdMAX "", (long long)hdb->cnt_reuserec); - wp += sprintf(wp, " cnt_moverec=%" PRIdMAX "", (long long)hdb->cnt_moverec); - wp += sprintf(wp, " cnt_readrec=%" PRIdMAX "", (long long)hdb->cnt_readrec); - wp += sprintf(wp, " cnt_searchfbp=%" PRIdMAX "", (long long)hdb->cnt_searchfbp); - wp += sprintf(wp, " cnt_insertfbp=%" PRIdMAX "", (long long)hdb->cnt_insertfbp); - wp += sprintf(wp, " cnt_splicefbp=%" PRIdMAX "", (long long)hdb->cnt_splicefbp); - wp += sprintf(wp, " cnt_dividefbp=%" PRIdMAX "", (long long)hdb->cnt_dividefbp); - wp += sprintf(wp, " cnt_mergefbp=%" PRIdMAX "", (long long)hdb->cnt_mergefbp); - wp += sprintf(wp, " cnt_reducefbp=%" PRIdMAX "", (long long)hdb->cnt_reducefbp); - wp += sprintf(wp, " cnt_appenddrp=%" PRIdMAX "", (long long)hdb->cnt_appenddrp); - wp += sprintf(wp, " cnt_deferdrp=%" PRIdMAX "", (long long)hdb->cnt_deferdrp); - wp += sprintf(wp, " cnt_flushdrp=%" PRIdMAX "", (long long)hdb->cnt_flushdrp); - wp += sprintf(wp, " cnt_adjrecc=%" PRIdMAX "", (long long)hdb->cnt_adjrecc); - wp += sprintf(wp, " cnt_defrag=%" PRIdMAX "", (long long)hdb->cnt_defrag); - wp += sprintf(wp, " cnt_shiftrec=%" PRIdMAX "", (long long)hdb->cnt_shiftrec); - wp += sprintf(wp, " cnt_trunc=%" PRIdMAX "", (long long)hdb->cnt_trunc); - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); -} +void tchdbprintmeta(TCHDB *hdb) { + assert(hdb); + HANDLE dbgfd = hdb->dbgfd; + if (INVALIDHANDLE(dbgfd)) { + dbgfd = GET_STDOUT_HANDLE(); + } + char buf[HDBIOBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "META:"); + wp += sprintf(wp, " mmtx=%p", (void *) hdb->mmtx); + wp += sprintf(wp, " rmtxs=%p", (void *) hdb->rmtxs); + wp += sprintf(wp, " dmtx=%p", (void *) hdb->dmtx); + wp += sprintf(wp, " smtx=%p", (void *) hdb->smtx); + wp += sprintf(wp, " wmtx=%p", (void *) hdb->wmtx); + wp += sprintf(wp, " eckey=%p", (void *) hdb->eckey); + wp += sprintf(wp, " rpath=%s", hdb->rpath ? hdb->rpath : "-"); + wp += sprintf(wp, " type=%02X", hdb->type); + wp += sprintf(wp, " flags=%02X", hdb->flags); + wp += sprintf(wp, " bnum=%" PRIuMAX "", (unsigned long long) hdb->bnum); + wp += sprintf(wp, " apow=%u", hdb->apow); + wp += sprintf(wp, " fpow=%u", hdb->fpow); + wp += sprintf(wp, " opts=%u", hdb->opts); + wp += sprintf(wp, " path=%s", hdb->path ? hdb->path : "-"); + wp += sprintf(wp, " fd=%d", hdb->fd); + wp += sprintf(wp, " omode=%u", hdb->omode); + wp += sprintf(wp, " rnum=%" PRIuMAX "", (unsigned long long) hdb->rnum); + wp += sprintf(wp, " fsiz=%" PRIuMAX "", (unsigned long long) hdb->fsiz); + wp += sprintf(wp, " frec=%" PRIuMAX "", (unsigned long long) hdb->frec); + wp += sprintf(wp, " dfcur=%" PRIuMAX "", (unsigned long long) hdb->dfcur); + wp += sprintf(wp, " iter=%" PRIuMAX "", (unsigned long long) hdb->iter); + wp += sprintf(wp, " map=%p", (void *) hdb->map); + wp += sprintf(wp, " msiz=%" PRIuMAX "", (unsigned long long) hdb->msiz); + wp += sprintf(wp, " ba64=%d", hdb->ba64); + wp += sprintf(wp, " align=%u", hdb->align); + wp += sprintf(wp, " runit=%u", hdb->runit); + wp += sprintf(wp, " zmode=%u", hdb->zmode); + wp += sprintf(wp, " fbpmax=%d", hdb->fbpmax); + wp += sprintf(wp, " fbpool=%p", (void *) hdb->fbpool); + wp += sprintf(wp, " fbpnum=%d", hdb->fbpnum); + wp += sprintf(wp, " fbpmis=%d", hdb->fbpmis); + wp += sprintf(wp, " drpool=%p", (void *) hdb->drpool); + wp += sprintf(wp, " drpdef=%p", (void *) hdb->drpdef); + wp += sprintf(wp, " drpoff=%" PRIuMAX "", (unsigned long long) hdb->drpoff); + wp += sprintf(wp, " recc=%p", (void *) hdb->recc); + wp += sprintf(wp, " rcnum=%u", hdb->rcnum); + wp += sprintf(wp, " ecode=%d", hdb->ecode); + wp += sprintf(wp, " fatal=%u", hdb->fatal); + wp += sprintf(wp, " inode=%" PRIuMAX "", (unsigned long long) (uint64_t) hdb->inode); + wp += sprintf(wp, " mtime=%" PRIuMAX "", (unsigned long long) (uint64_t) hdb->mtime); + wp += sprintf(wp, " dfunit=%u", hdb->dfunit); + wp += sprintf(wp, " dfcnt=%u", hdb->dfcnt); + wp += sprintf(wp, " tran=%d", hdb->tran); + wp += sprintf(wp, " walfd=%d", hdb->walfd); + wp += sprintf(wp, " walend=%" PRIuMAX "", (unsigned long long) hdb->walend); + wp += sprintf(wp, " dbgfd=%d", hdb->dbgfd); + +#ifndef NDEBUG + wp += sprintf(wp, " cnt_writerec=%" PRIdMAX "", (long long) hdb->cnt_writerec); + wp += sprintf(wp, " cnt_reuserec=%" PRIdMAX "", (long long) hdb->cnt_reuserec); + wp += sprintf(wp, " cnt_moverec=%" PRIdMAX "", (long long) hdb->cnt_moverec); + wp += sprintf(wp, " cnt_readrec=%" PRIdMAX "", (long long) hdb->cnt_readrec); + wp += sprintf(wp, " cnt_searchfbp=%" PRIdMAX "", (long long) hdb->cnt_searchfbp); + wp += sprintf(wp, " cnt_insertfbp=%" PRIdMAX "", (long long) hdb->cnt_insertfbp); + wp += sprintf(wp, " cnt_splicefbp=%" PRIdMAX "", (long long) hdb->cnt_splicefbp); + wp += sprintf(wp, " cnt_dividefbp=%" PRIdMAX "", (long long) hdb->cnt_dividefbp); + wp += sprintf(wp, " cnt_mergefbp=%" PRIdMAX "", (long long) hdb->cnt_mergefbp); + wp += sprintf(wp, " cnt_reducefbp=%" PRIdMAX "", (long long) hdb->cnt_reducefbp); + wp += sprintf(wp, " cnt_appenddrp=%" PRIdMAX "", (long long) hdb->cnt_appenddrp); + wp += sprintf(wp, " cnt_deferdrp=%" PRIdMAX "", (long long) hdb->cnt_deferdrp); + wp += sprintf(wp, " cnt_flushdrp=%" PRIdMAX "", (long long) hdb->cnt_flushdrp); + wp += sprintf(wp, " cnt_adjrecc=%" PRIdMAX "", (long long) hdb->cnt_adjrecc); + wp += sprintf(wp, " cnt_defrag=%" PRIdMAX "", (long long) hdb->cnt_defrag); + wp += sprintf(wp, " cnt_shiftrec=%" PRIdMAX "", (long long) hdb->cnt_shiftrec); + wp += sprintf(wp, " cnt_trunc=%" PRIdMAX "", (long long) hdb->cnt_trunc); +#endif + *(wp++) = '\n'; + tcwrite(dbgfd, buf, wp - buf); +} /* Print a record information into the debugging output. `hdb' specifies the hash database object. `rec' specifies the record. */ -void tchdbprintrec(TCHDB *hdb, TCHREC *rec){ - assert(hdb && rec); - HANDLE dbgfd = hdb->dbgfd; - if(INVALIDHANDLE(dbgfd)) { - dbgfd = GET_STDOUT_HANDLE(); - } - char buf[HDBIOBUFSIZ]; - char *wp = buf; - wp += sprintf(wp, "REC:"); - wp += sprintf(wp, " off=%" PRIuMAX "", (unsigned long long)rec->off); - wp += sprintf(wp, " rsiz=%u", rec->rsiz); - wp += sprintf(wp, " magic=%02X", rec->magic); - wp += sprintf(wp, " hash=%02X", rec->hash); - wp += sprintf(wp, " left=%" PRIuMAX "", (unsigned long long)rec->left); - wp += sprintf(wp, " right=%" PRIuMAX "", (unsigned long long)rec->right); - wp += sprintf(wp, " ksiz=%u", rec->ksiz); - wp += sprintf(wp, " vsiz=%u", rec->vsiz); - wp += sprintf(wp, " psiz=%u", rec->psiz); - wp += sprintf(wp, " kbuf=%p", (void *)rec->kbuf); - wp += sprintf(wp, " vbuf=%p", (void *)rec->vbuf); - wp += sprintf(wp, " boff=%" PRIuMAX "", (unsigned long long)rec->boff); - wp += sprintf(wp, " bbuf=%p", (void *)rec->bbuf); - *(wp++) = '\n'; - tcwrite(dbgfd, buf, wp - buf); +void tchdbprintrec(TCHDB *hdb, TCHREC *rec) { + assert(hdb && rec); + HANDLE dbgfd = hdb->dbgfd; + if (INVALIDHANDLE(dbgfd)) { + dbgfd = GET_STDOUT_HANDLE(); + } + char buf[HDBIOBUFSIZ]; + char *wp = buf; + wp += sprintf(wp, "REC:"); + wp += sprintf(wp, " off=%" PRIuMAX "", (unsigned long long) rec->off); + wp += sprintf(wp, " rsiz=%u", rec->rsiz); + wp += sprintf(wp, " magic=%02X", rec->magic); + wp += sprintf(wp, " hash=%02X", rec->hash); + wp += sprintf(wp, " left=%" PRIuMAX "", (unsigned long long) rec->left); + wp += sprintf(wp, " right=%" PRIuMAX "", (unsigned long long) rec->right); + wp += sprintf(wp, " ksiz=%u", rec->ksiz); + wp += sprintf(wp, " vsiz=%u", rec->vsiz); + wp += sprintf(wp, " psiz=%u", rec->psiz); + wp += sprintf(wp, " kbuf=%p", (void *) rec->kbuf); + wp += sprintf(wp, " vbuf=%p", (void *) rec->vbuf); + wp += sprintf(wp, " boff=%" PRIuMAX "", (unsigned long long) rec->boff); + wp += sprintf(wp, " bbuf=%p", (void *) rec->bbuf); + *(wp++) = '\n'; + tcwrite(dbgfd, buf, wp - buf); } diff --git a/tcejdb/tchdb.h b/tcejdb/tchdb.h index 130391e..492b7ad 100644 --- a/tcejdb/tchdb.h +++ b/tcejdb/tchdb.h @@ -24,6 +24,7 @@ #define __TCHDB_CLINKAGEBEGIN #define __TCHDB_CLINKAGEEND #endif + __TCHDB_CLINKAGEBEGIN @@ -36,103 +37,106 @@ __TCHDB_CLINKAGEBEGIN *************************************************************************************************/ -typedef struct { /* type of structure for a hash database */ - void *mmtx; /* mutex for method */ - void *rmtxs; /* mutexes for records */ - void *dmtx; /* mutex for the while database */ - void *smtx; /* rw mutex for shared memory */ - void *wmtx; /* mutex for write ahead logging */ - void *eckey; /* key for thread specific error code */ - char *rpath; /* real path for locking */ - uint8_t type; /* database type */ - uint8_t flags; /* additional flags */ - uint64_t bnum; /* number of the bucket array */ - uint8_t apow; /* power of record alignment */ - uint8_t fpow; /* power of free block pool number */ - uint8_t opts; /* options */ - char *path; /* path of the database file */ - HANDLE fd; /* file descriptor of the database file */ - uint32_t omode; /* open mode */ - uint64_t rnum; /* number of the records */ - uint64_t fsiz; /* size of the database file */ - uint64_t frec; /* offset of the first record */ - uint64_t dfcur; /* offset of the cursor for defragmentation */ - uint64_t iter; /* offset of the iterator */ - volatile char *map; /* pointer to the mapped memory */ - uint64_t msiz; /* size of the mapped memory */ - uint64_t xmsiz; /* size of the extra mapped memory */ - uint64_t xfsiz; /* extra size of the file for mapped memory */ - bool ba64; /* using of 64-bit bucket array */ - uint32_t align; /* record alignment */ - uint32_t runit; /* record reading unit */ - bool zmode; /* whether compression is used */ - int32_t fbpmax; /* maximum number of the free block pool */ - void *fbpool; /* free block pool */ - int32_t fbpnum; /* number of the free block pool */ - int32_t fbpmis; /* number of missing retrieval of the free block pool */ - bool async; /* whether asynchronous storing is called */ - TCXSTR *drpool; /* delayed record pool */ - TCXSTR *drpdef; /* deferred records of the delayed record pool */ - uint64_t drpoff; /* offset of the delayed record pool */ - TCMDB *recc; /* cache for records */ - uint32_t rcnum; /* maximum number of cached records */ - TCCODEC enc; /* pointer to the encoding function */ - void *encop; /* opaque object for the encoding functions */ - TCCODEC dec; /* pointer to the decoding function */ - void *decop; /* opaque object for the decoding functions */ - volatile int ecode; /* last happened error code */ - bool fatal; /* whether a fatal error occured */ - uint64_t inode; /* inode number */ - time_t mtime; /* modification time */ - uint32_t dfunit; /* unit step number of auto defragmentation */ - uint32_t dfcnt; /* counter of auto defragmentation */ - bool tran; /* whether in the transaction */ - HANDLE walfd; /* file descriptor of write ahead logging */ - uint64_t walend; /* end offset of write ahead logging */ - HANDLE dbgfd; /* file descriptor for debugging */ - volatile int64_t cnt_writerec; /* tesing counter for record write times */ - volatile int64_t cnt_reuserec; /* tesing counter for record reuse times */ - volatile int64_t cnt_moverec; /* tesing counter for record move times */ - volatile int64_t cnt_readrec; /* tesing counter for record read times */ - volatile int64_t cnt_searchfbp; /* tesing counter for FBP search times */ - volatile int64_t cnt_insertfbp; /* tesing counter for FBP insert times */ - volatile int64_t cnt_splicefbp; /* tesing counter for FBP splice times */ - volatile int64_t cnt_dividefbp; /* tesing counter for FBP divide times */ - volatile int64_t cnt_mergefbp; /* tesing counter for FBP merge times */ - volatile int64_t cnt_reducefbp; /* tesing counter for FBP reduce times */ - volatile int64_t cnt_appenddrp; /* tesing counter for DRP append times */ - volatile int64_t cnt_deferdrp; /* tesing counter for DRP defer times */ - volatile int64_t cnt_flushdrp; /* tesing counter for DRP flush times */ - volatile int64_t cnt_adjrecc; /* tesing counter for record cache adjust times */ - volatile int64_t cnt_defrag; /* tesing counter for defragmentation times */ - volatile int64_t cnt_shiftrec; /* tesing counter for record shift times */ - volatile int64_t cnt_trunc; /* tesing counter for truncation times */ +typedef struct { /* type of structure for a hash database */ + bool ba64; /* using of 64-bit bucket array */ + bool tran; /* whether in the transaction */ + bool zmode; /* whether compression is used */ + bool async; /* whether asynchronous storing is called */ + bool fatal; /* whether a fatal error occured */ + uint8_t type; /* database type */ + uint8_t flags; /* additional flags */ + uint8_t apow; /* power of record alignment */ + uint8_t fpow; /* power of free block pool number */ + uint8_t opts; /* options */ + void *mmtx; /* mutex for method */ + void *rmtxs; /* mutexes for records */ + void *dmtx; /* mutex for the while database */ + void *smtx; /* rw mutex for shared memory */ + void *wmtx; /* mutex for write ahead logging */ + void *eckey; /* key for thread specific error code */ + char *rpath; /* real path for locking */ + char *path; /* path of the database file */ + void *fbpool; /* free block pool */ + char *map; /* pointer to the mapped memory */ + TCXSTR *drpool; /* delayed record pool */ + TCXSTR *drpdef; /* deferred records of the delayed record pool */ + TCCODEC enc; /* pointer to the encoding function */ + TCCODEC dec; /* pointer to the decoding function */ + TCMDB *recc; /* cache for records */ + void *encop; /* opaque object for the encoding functions */ + void *decop; /* opaque object for the decoding functions */ + volatile int ecode; /* last happened error code */ + int32_t fbpmax; /* maximum number of the free block pool */ + int32_t fbpnum; /* number of the free block pool */ + int32_t fbpmis; /* number of missing retrieval of the free block pool */ + uint32_t align; /* record alignment */ + uint32_t runit; /* record reading unit */ + uint32_t rcnum; /* maximum number of cached records */ + uint32_t dfunit; /* unit step number of auto defragmentation */ + uint32_t dfcnt; /* counter of auto defragmentation */ + uint32_t omode; /* open mode */ + HANDLE fd; /* file descriptor of the database file */ + HANDLE walfd; /* file descriptor of write ahead logging */ + HANDLE dbgfd; /* file descriptor for debugging */ #ifdef _WIN32 - volatile HANDLE w32hmap; /* win32 file mappings for mmap */ + HANDLE w32hmap; /* win32 file mappings for mmap */ +#endif + time_t mtime; /* modification time */ + uint64_t bnum; /* number of the bucket array */ + uint64_t rnum; /* number of the records */ + uint64_t fsiz; /* size of the database file */ + uint64_t frec; /* offset of the first record */ + uint64_t dfcur; /* offset of the cursor for defragmentation */ + uint64_t iter; /* offset of the iterator */ + uint64_t msiz; /* size of the mapped memory */ + uint64_t xmsiz; /* size of the extra mapped memory */ + uint64_t xfsiz; /* extra size of the file for mapped memory */ + uint64_t drpoff; /* offset of the delayed record pool */ + uint64_t inode; /* inode number */ + uint64_t walend; /* end offset of write ahead logging */ + +#ifndef NDEBUG + volatile int64_t cnt_writerec; /* tesing counter for record write times */ + volatile int64_t cnt_reuserec; /* tesing counter for record reuse times */ + volatile int64_t cnt_moverec; /* tesing counter for record move times */ + volatile int64_t cnt_readrec; /* tesing counter for record read times */ + volatile int64_t cnt_searchfbp; /* tesing counter for FBP search times */ + volatile int64_t cnt_insertfbp; /* tesing counter for FBP insert times */ + volatile int64_t cnt_splicefbp; /* tesing counter for FBP splice times */ + volatile int64_t cnt_dividefbp; /* tesing counter for FBP divide times */ + volatile int64_t cnt_mergefbp; /* tesing counter for FBP merge times */ + volatile int64_t cnt_reducefbp; /* tesing counter for FBP reduce times */ + volatile int64_t cnt_appenddrp; /* tesing counter for DRP append times */ + volatile int64_t cnt_deferdrp; /* tesing counter for DRP defer times */ + volatile int64_t cnt_flushdrp; /* tesing counter for DRP flush times */ + volatile int64_t cnt_adjrecc; /* tesing counter for record cache adjust times */ + volatile int64_t cnt_defrag; /* tesing counter for defragmentation times */ + volatile int64_t cnt_shiftrec; /* tesing counter for record shift times */ + volatile int64_t cnt_trunc; /* tesing counter for truncation times */ #endif } TCHDB; -enum { /* enumeration for additional flags */ - HDBFOPEN = 1 << 0, /* whether opened */ - HDBFFATAL = 1 << 1 /* whether with fatal error */ +enum { /* enumeration for additional flags */ + HDBFOPEN = 1 << 0, /* whether opened */ + HDBFFATAL = 1 << 1 /* whether with fatal error */ }; -enum { /* enumeration for tuning options */ - HDBTLARGE = 1 << 0, /* use 64-bit bucket array */ - HDBTDEFLATE = 1 << 1, /* compress each record with Deflate */ - HDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ - HDBTTCBS = 1 << 3, /* compress each record with TCBS */ - HDBTEXCODEC = 1 << 4 /* compress each record with custom functions */ +enum { /* enumeration for tuning options */ + HDBTLARGE = 1 << 0, /* use 64-bit bucket array */ + HDBTDEFLATE = 1 << 1, /* compress each record with Deflate */ + HDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ + HDBTTCBS = 1 << 3, /* compress each record with TCBS */ + HDBTEXCODEC = 1 << 4 /* compress each record with custom functions */ }; -enum { /* enumeration for open modes */ - HDBOREADER = 1 << 0, /* open as a reader */ - HDBOWRITER = 1 << 1, /* open as a writer */ - HDBOCREAT = 1 << 2, /* writer creating */ - HDBOTRUNC = 1 << 3, /* writer truncating */ - HDBONOLCK = 1 << 4, /* open without locking */ - HDBOLCKNB = 1 << 5, /* lock without blocking */ - HDBOTSYNC = 1 << 6 /* synchronize every transaction */ +enum { /* enumeration for open modes */ + HDBOREADER = 1 << 0, /* open as a reader */ + HDBOWRITER = 1 << 1, /* open as a writer */ + HDBOCREAT = 1 << 2, /* writer creating */ + HDBOTRUNC = 1 << 3, /* writer truncating */ + HDBONOLCK = 1 << 4, /* open without locking */ + HDBOLCKNB = 1 << 5, /* lock without blocking */ + HDBOTSYNC = 1 << 6 /* synchronize every transaction */ }; @@ -806,7 +810,7 @@ EJDB_EXPORT bool tchdbcacheclear(TCHDB *hdb); Note that the callback function can not perform any database operation because the function is called in the critical section guarded by the same locks of database operations. */ EJDB_EXPORT bool tchdbputproc(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, - TCPDPROC proc, void *op); + TCPDPROC proc, void *op); /* Retrieve the next record of a record in a hash database object. diff --git a/tcejdb/tchmttest.c b/tcejdb/tchmttest.c index 68e265d..73a69de 100644 --- a/tcejdb/tchmttest.c +++ b/tcejdb/tchmttest.c @@ -202,9 +202,10 @@ static void eprint(TCHDB *hdb, int line, const char *func){ /* print members of hash database */ static void mprint(TCHDB *hdb){ - if(hdb->cnt_writerec < 0) return; iprintf("bucket number: %" PRIdMAX "\n", (long long)tchdbbnum(hdb)); iprintf("used bucket number: %" PRIdMAX "\n", (long long)tchdbbnumused(hdb)); +#ifndef NDEBUG + if(hdb->cnt_writerec < 0) return; iprintf("cnt_writerec: %" PRIdMAX "\n", (long long)hdb->cnt_writerec); iprintf("cnt_reuserec: %" PRIdMAX "\n", (long long)hdb->cnt_reuserec); iprintf("cnt_moverec: %" PRIdMAX "\n", (long long)hdb->cnt_moverec); @@ -222,6 +223,7 @@ static void mprint(TCHDB *hdb){ iprintf("cnt_defrag: %" PRIdMAX "\n", (long long)hdb->cnt_defrag); iprintf("cnt_shiftrec: %" PRIdMAX "\n", (long long)hdb->cnt_shiftrec); iprintf("cnt_trunc: %" PRIdMAX "\n", (long long)hdb->cnt_trunc); +#endif } diff --git a/tcejdb/tchtest.c b/tcejdb/tchtest.c index 2f3036b..9a49ca7 100644 --- a/tcejdb/tchtest.c +++ b/tcejdb/tchtest.c @@ -159,6 +159,7 @@ static void mprint(TCHDB *hdb){ iprintf("xmsiz: %" PRIdMAX "\n", hdb->xmsiz); iprintf("fbpnum: %" PRIdMAX "\n", hdb->fbpnum); iprintf("fbpool: %p\n", hdb->fbpool); +#ifndef NDEBUG iprintf("cnt_writerec: %" PRIdMAX "\n", (long long)hdb->cnt_writerec); iprintf("cnt_reuserec: %" PRIdMAX "\n", (long long)hdb->cnt_reuserec); iprintf("cnt_moverec: %" PRIdMAX "\n", (long long)hdb->cnt_moverec); @@ -176,6 +177,7 @@ static void mprint(TCHDB *hdb){ iprintf("cnt_defrag: %" PRIdMAX "\n", (long long)hdb->cnt_defrag); iprintf("cnt_shiftrec: %" PRIdMAX "\n", (long long)hdb->cnt_shiftrec); iprintf("cnt_trunc: %" PRIdMAX "\n", (long long)hdb->cnt_trunc); +#endif } diff --git a/tcejdb/tctmgr.c b/tcejdb/tctmgr.c index cf0fc05..4269909 100644 --- a/tcejdb/tctmgr.c +++ b/tcejdb/tctmgr.c @@ -683,8 +683,10 @@ static int procinform(const char *path, int omode){ if(flags & TDBFFATAL) printf(" fatal"); printf("\n"); printf("bucket number: %" PRIuMAX "\n", (unsigned long long)tctdbbnum(tdb)); +#ifndef NDEBUG if(tdb->hdb->cnt_writerec >= 0) printf("used bucket number: %" PRIdMAX "\n", (long long)tctdbbnumused(tdb)); +#endif printf("alignment: %u\n", tctdbalign(tdb)); printf("free block pool: %u\n", tctdbfbpmax(tdb)); printf("index number: %d\n", tctdbinum(tdb)); -- 2.7.4