--- /dev/null
+#ifndef __DB_H__
+#define __DB_H__
+#include <cstring>
+#include <stdint.h>
+#include <malloc.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#define freeStoreIndex indecies[freeStoreIdx]
+#define addrStoreIndex indecies[addrStoreIdx]
+#define freeSpaceIndex indecies[freeSpaceIdx]
+#define addrSpaceIndex indecies[addrSpaceIdx]
+#define entityIdIndex indecies[entityIdIdx]
+#define entityNmIndex indecies[entityNmIdx]
+
+#define noThrow std::nothrow
+#ifndef likely
+#define likely(x) (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 1))
+#define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 0))
+#endif
+#ifndef lengthof
+#define lengthof(x) ((int)(sizeof(x)/sizeof(x[0])))
+#endif
+
+#if 0
+inline void *operator new(size_t n) { void *vp = malloc(n); bzero(vp,n); return vp; }
+inline void operator delete(void *t) { free(t); }
+inline void operator delete(void *t,size_t n) { free(t); }
+inline void *operator new[](size_t n) { void *vp = malloc(n); bzero(vp,n); return vp; }
+inline void operator delete[](void *t) { free(t); }
+inline void operator delete[](void *t,size_t n) { free(t); }
+#endif
+
+#define ZMEDIA
+#define ZFUTEX
+#ifdef ZFUTEX
+#include <unistd.h>
+#include <endian.h>
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#else
+#include <pthread.h>
+#endif
+
+#if 1
+//entity definitions
+#define DbObj(nm) \
+ class nm##Obj : public Db::Obj { public:
+
+#define DbLoc(nm) \
+ class nm##Loc : public Db::ObjectLoc { public: \
+ nm##Obj *operator ->() { return (nm##Obj *)addr(); } \
+ nm##Loc(Db::Entity *ep) : Db::ObjectLoc(ep) {} \
+ nm##Loc(Db::Entity &e) : Db::ObjectLoc(&e) {}
+
+//basic definitions
+#define basic_def(ty,n) class t_##n { public: ty v; t_##n() {} \
+ t_##n(const ty &i) : v(i) {} \
+ t_##n(const t_##n &i) : v(i.v) {} \
+ t_##n &operator =(const t_##n &i) { v = i.v; return *this; } \
+ ty &operator =(const ty &i) { return v = i; } \
+ ty *addr() { return &v; } int size() { return sizeof(v); } \
+ } v_##n \
+
+//array definitions
+#define array_def(ty,n,l) class t_##n { public: ty v[l]; t_##n() {} \
+ t_##n(const t_##n &i) { memcpy(&v,&i.v,sizeof(v)); } \
+ t_##n(ty *i) { memcpy(&v,i,sizeof(v)); } \
+ t_##n(ty(*i)[l]) { memcpy(&v,i,sizeof(v)); } \
+ ty *operator =(const ty *i) { memcpy(&v,i,sizeof(v)); return &v[0]; } \
+ ty *addr() { return &v[0]; } int size() { return sizeof(v); } \
+ } v_##n \
+
+// variable array definitions
+#define varray_def(ty,n) \
+ class t_##n { public: char *v; int l; t_##n() {} \
+ t_##n(const char *i, int sz) { v = (char *)i; l = sz; } \
+ t_##n(const unsigned char *i, int sz) { v = (char *)i; l = sz; } \
+ ty *addr() { return (ty *)v; } int size() { return l; } \
+ }; Db::varObj v_##n \
+
+// string array definitions
+#define sarray_def(ty,n) \
+ class t_##n { public: char *v; int l; t_##n() {} \
+ t_##n(const char *i, int sz) { v = (char *)i; l = sz; } \
+ t_##n(const unsigned char *i, int sz) { v = (char *)i; l = sz; } \
+ t_##n(const char *i) { t_##n(i,strlen(i)+1); } \
+ t_##n(const unsigned char *i) { t_##n(i,strlen(v)+1); } \
+ ty *addr() { return (ty *)v; } int size() { return l; } \
+ }; Db::varObj v_##n \
+
+//basic type ref
+#define basic_ref(ty,n) \
+ ty *_##n() { return (*this)->v_##n.addr(); } \
+ ty n() { return *_##n(); } \
+ void n(ty i) { _wr(); *_##n() = i; } \
+ int size_##n() { return (*this)->v_##n.size(); } \
+
+//array type ref
+#define array_ref(ty,n,l) \
+ ty *_##n() { return (*this)->v_##n.addr(); } \
+ ty (&n())[l] { return *(ty (*)[l])_##n(); } \
+ void n(const ty *i,int m) { _wr(); if( m > 0 ) memcpy(n(),i,m); } \
+ void n(const ty *i) { n(i,(*this)->v_##n.size()); } \
+ int size_##n() { return (*this)->v_##n.size(); } \
+
+//variable array type ref
+#define varray_ref(ty,n) \
+ ty *_##n() { return (ty *)addr((*this)->v_##n); } \
+ ty *_##n(int sz) { size((*this)->v_##n, sz); \
+ return sz > 0 ? (ty *)addr_wr((*this)->v_##n) : 0; } \
+ ty (&n())[] { return *(ty (*)[])_##n(); } \
+ int n(const ty *v, int sz) { ty *vp=_##n(sz); \
+ if( vp && sz > 0 ) memcpy(vp, v, sz); return 0; } \
+ int size_##n() { return (*this)->v_##n.size(); } \
+
+//string array type ref
+#define sarray_ref(ty,n) \
+ ty *_##n() { return (ty *)addr((*this)->v_##n); } \
+ ty *_##n(int sz) { size((*this)->v_##n, sz); \
+ return sz > 0 ? (ty *)addr_wr((*this)->v_##n) : 0; } \
+ ty (&n())[] { return *(ty (*)[])_##n(); } \
+ int n(const ty *v, int sz) { ty *vp=_##n(sz); \
+ if( vp && sz > 0 ) memcpy(vp, v, sz); return 0; } \
+ int n(const char *v) { return n((ty *)v,strlen(v)+1); } \
+ int n(const unsigned char *v) { return n((const char *)v); } \
+ int size_##n() { return (*this)->v_##n.size(); } \
+
+#endif
+
+#define DEBUG
+#define DEBUG_TIMESTAMPS
+#define DBBUG_ERR 0x00000001
+#define DBBUG_FAIL 0x00000002
+#define CHK
+//#define CHK 1 ? 0 :
+
+class Db;
+
+class Db {
+public:
+ typedef int pageId;
+ typedef int transId;
+ typedef long ioAddr;
+
+private:
+ int root_info_id;
+ int index_info_id;
+ int page_info_id;
+
+ class RootInfo {
+ public:
+ int root_magic; // info_magic label
+ int root_info_size; // root_info blob size
+ int last_info_size;
+ int entity_max_id;
+ int entity_count;
+ ioAddr root_info_addr;
+ ioAddr last_info_addr;
+ transId transaction_id; // current transaction
+ ioAddr file_size; // current file size
+ pageId freePages; // free page table page list
+ int indeciesUsed; // number of active indecies
+ int pageTableUsed; // number of active pages
+
+ int init();
+ } *root_info;
+
+ int shm_init, no_shm;
+
+ static void *get_mem8_t(int id);
+ static void *new_mem8_t(int size, int &id);
+ static int del_mem8_t(const void *vp, int id);
+ static void *get_shm8_t(int id);
+ static void *new_shm8_t(int size, int &id);
+ static int del_shm8_t(const void *vp, int id);
+ void *(*get_mem)(int id);
+ void *(*new_mem)(int size, int &id);
+ int (*del_mem)(const void *vp, int id);
+
+protected:
+ uint8_t *get_uint8_t(int id, int pg=-1);
+ uint8_t *new_uint8_t(int size, int &id, int pg=-1);
+ int del_uint8_t(const void *vp, int id=-1, int pg=-1);
+
+public:
+ typedef int (*CmprFn)(char *,char *);
+ static int cmprFrSt(char *a, char *b);
+ static int cmprAdSt(char *a, char *b);
+ static int cmprFrSp(char *a, char *b);
+ static int cmprAdSp(char *a, char *b);
+ static int cmprOIds(char *a, char *b);
+ static int cmprStr(char *a, char *b);
+ static int cmprKey(char *a, char *b);
+ static int cmprLast(char *a, char *b);
+ static CmprFn cmprFns[];
+ typedef void (*errCallback)(Db *db, int v);
+ static const pageId NIL=-1, DDONE=-2;
+ enum {
+ errNoCmprFn = 0,
+ errNotFound = -1,
+ errDuplicate = -2,
+ errNoPage = -3,
+ errNoMemory = -4,
+ errIoRead = -5,
+ errIoWrite = -6,
+ errIoSeek = -7,
+ errIoStat = -8,
+ errBadMagic = -9,
+ errCorrupt = -10,
+ errInvalid = -11,
+ errPrevious = -12,
+ errObjEntity = -13,
+ errLimit = -14,
+ errUser = -15,
+ idxId = 0, nmSz = 32,
+ keysz = 256,
+ keyLT=-2, keyLE=-1, keyEQ=0, keyGE=1, keyGT=2,
+ };
+
+ class pgRef {
+ public:
+ pageId id;
+ int offset;
+ };
+
+ static void zincr(volatile int &v) { /* atomic(++v) */
+ asm ( " lock incl %1\n" : "+m" (v) :: );
+ }
+ static void zdecr(volatile int &v) { /* atomic(--v) */
+ asm ( " lock decl %1\n" : "+m" (v) :: );
+ }
+ static char tdecr(volatile int &v) {
+ char ret; /* ret = atomic(--loc >= 0 ? 1 : 0) */
+ asm ( " lock decl %1\n setge %0\n" : "=r" (ret), "+m" (v) :: );
+ return ret;
+ }
+ static char tincr(volatile int &v) {
+ char ret; /* ret = atomic(++loc > 0 ? 1 : 0) */
+ asm ( " lock incl %1\n setg %0\n" : "=r" (ret), "+m" (v) :: );
+ return ret;
+ }
+ static int zcmpxchg(int old, int val, volatile int &v) {
+ int ret = old;
+ asm volatile( " lock\n cmpxchgl %2,%1\n"
+ : "+a" (ret), "+m" (v) : "r" (val) : "memory" );
+ return ret;
+ }
+ static int zxchg(int val, volatile int &v) {
+ asm volatile( " xchgl %0,%1\n"
+ : "+r" (val), "+m" (v) :: "memory" );
+ return val;
+ }
+ static int zadd(int n, volatile int &v) {
+ int old, mod, val;
+ do { val = (old=v)+n; mod = zcmpxchg(old,val,v);
+ } while( mod != old );
+ return val;
+ }
+ static void zmfence() {
+ asm volatile ( " mfence\n" ::: "memory" );
+ }
+
+ class zlock_t;
+ class zblock_t;
+ class zrwlock_t;
+
+#ifdef ZFUTEX
+#define ZLOCK_INIT zzlock_t()
+ class zloc_t {
+ protected:
+ volatile int loc;
+ int zfutex(int op, int val, timespec *time=0) {
+ return syscall(SYS_futex,&loc,op,val,time,0,0);
+ }
+ int zyield();
+ int zgettid();
+ public:
+ int zwake(int nwakeups);
+ int zwait(int val, timespec *ts=0);
+ int zwait() { return zwait(loc); }
+ zloc_t() : loc(-1) {}
+ ~zloc_t() {}
+ };
+
+ class zlock_t : zloc_t {
+ void *owner;
+ void *self() {
+#ifdef __x86_64__
+ void *vp; asm ("movq %%fs:%c1,%q0" : "=r" (vp) : "i" (16));
+#else
+ void *vp; asm ("mov %%fs:%c1,%q0" : "=r" (vp) : "i" (16));
+#endif
+ return vp;
+ }
+ protected:
+ friend class zblock_t;
+ friend class zrwlock_t;
+ int zlock(int v);
+ int zunlock(int nwakeups=1);
+ static int zemsg1();
+ public:
+ int lock() {
+ int v, ret = unlikely( (v=zcmpxchg(-1,0,loc)) >= 0 ) ? zlock(v) : 0;
+ owner = self();
+ return ret;
+ }
+ int unlock() {
+ if( unlikely(loc < 0) ) { return zemsg1(); }
+ owner = 0;
+ int v, ret = unlikely( (v=zcmpxchg(0,-1,loc)) != 0 ) ? zunlock() : 0;
+ return ret;
+ }
+ zlock_t() { owner = 0; }
+ ~zlock_t() {}
+ };
+
+ class zblock_t : zlock_t {
+ public:
+ void block() { loc = 0; zwait(0); }
+ void unblock() { loc = -1; zwake(INT_MAX); }
+ zblock_t() {}
+ ~zblock_t() {}
+ };
+
+ class zrwlock_t : zloc_t {
+ zlock_t lk;
+ void zenter();
+ void zleave();
+ public:
+ void enter() { zincr(loc); if( unlikely( lk.loc >= 0 ) ) zenter(); }
+ void leave() { if( unlikely( !tdecr(loc) ) ) zleave(); }
+ void write_enter();
+ void write_leave();
+ int locked() { return loc >= 0 ? 0 : lk.loc >= 0 ? 1 : -1; }
+ int blocked() { return lk.loc >= 0 ? 1 : 0; }
+ zrwlock_t() {}
+ ~zrwlock_t() {}
+ };
+
+#else
+#define ZLOCK_INIT { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER }
+
+ class zlock_t {
+ protected:
+ pthread_mutex_t zlock;
+ public:
+ void lock() { pthread_mutex_lock(&zlock); }
+ void unlock() { pthread_mutex_unlock(&zlock); }
+ zlock_t() { pthread_mutex_init(&zlock, 0); }
+ ~zlock_t() { pthread_mutex_destroy(&zlock); }
+ };
+
+ class zblock_t {
+ pthread_mutex_t zblock;
+ pthread_cond_t cond;
+ public:
+ zblock_t() {
+ pthread_mutex_init(&zblock, 0);
+ pthread_cond_init(&cond, 0);
+ }
+ ~zblock_t() {
+ pthread_mutex_destroy(&zblock);
+ pthread_cond_destroy(&cond);
+ }
+ void block() {
+ pthread_mutex_lock(&zblock);
+ pthread_cond_wait(&cond, &zblock);
+ pthread_mutex_unlock(&zblock);
+ }
+ void unblock() { pthread_cond_broadcast(&cond); }
+ };
+
+ class zrwlock_t : zlock_t {
+ volatile int blocking, users;
+ zlock_t lk;
+ pthread_cond_t cond;
+ void wait() { pthread_cond_wait(&cond, &zlock); }
+ void wake() { pthread_cond_signal(&cond); }
+ public:
+ void enter() { lock();
+ while( blocking ) { unlock(); lk.lock(); lk.unlock(); lock(); }
+ ++users; unlock();
+ }
+ void leave() { lock(); if( !--users && blocking ) wake(); unlock(); }
+ void write_enter() { lk.lock(); blocking = 1;
+ lock(); while( users ) wait(); unlock();
+ }
+ void write_leave() { blocking = 0; lk.unlock(); }
+ int count() { return users; }
+ int locked() { return users ? 0 : blocking ? 1 : -1; }
+ int blocked() { return blocking; }
+
+ zrwlock_t() { pthread_cond_init(&cond, 0); users = 0; blocking = 0; }
+ ~zrwlock_t() { pthread_cond_destroy(&cond); }
+ };
+
+#endif
+
+ class locked {
+ zlock_t &lk;
+ public:
+ locked(zlock_t &l) : lk(l) { lk.lock(); }
+ ~locked() { lk.unlock(); }
+ };
+
+ class read_locked {
+ zrwlock_t &rwlk;
+ public:
+ read_locked(zrwlock_t &l) : rwlk(l) { rwlk.enter(); }
+ ~read_locked() { rwlk.leave(); }
+ };
+
+ class write_blocked {
+ zrwlock_t &rwlk;
+ public:
+ write_blocked(zrwlock_t &l) : rwlk(l) { rwlk.write_enter(); }
+ ~write_blocked() { rwlk.write_leave(); }
+ };
+
+private:
+ enum {
+ db_magic_offset=0,
+ db_magic=0x00624474, // tDb
+ idx_magic=0x00786469, // idx
+ info_magic=0x6f666e69, // info
+ root_magic=0x746f6f72, // root
+ page_magic=0x6770, // pg
+ entity_magic = 0x6d65, // em
+ root_info_offset=4,
+ root_info_extra_pages = 2,
+ idxNil=0, idxBin=1, idxStr=2,
+ opDelete=-1, opFind=0, opInsert=1,
+ pg_unknown=0, pg_root_info=1, pg_free=2,
+ pg_entity=0x0100, pg_index=0x1000,
+ max_entity_type = pg_index-pg_entity-1,
+ max_index_type = 0x10000-pg_index-1,
+ min_heap_allocation = 32,
+ freeStoreIdx = 0, addrStoreIdx = 1,
+ freeSpaceIdx = 2, addrSpaceIdx = 3,
+ entityIdIdx = 4, entityNmIdx = 5, usrIdx = 6,
+ fl_wr=1, fl_rd=2, fl_new=4, fl_free=8,
+ defaultNoShm = 1,
+ defaultStoreBlockSize = 8192,
+ defaultPageTableHunkSize = 8192,
+ defaultIndexTableHunkSize = 4096,
+ defaultBinaryBlockSize = 16384,
+ defaultStringBlockSize = 4096,
+ defaultEntityPageSize = 65536,
+ };
+
+ int key, fd;
+ int err_no;
+ errCallback err_callback;
+ int my_pid;
+ transId active_transaction;
+
+#ifdef DEBUG
+ static int debug;
+ static const char *errMsgs[];
+ static void dmsg(int msk, const char *msg,...);
+ int _err_(int v,const char *fn,int ln);
+ int _fail_(int v,const char *fn,int ln);
+#define err_(v) _err_(v,__func__,__LINE__)
+#define fail_(v) _fail_(v,__func__,__LINE__)
+#else
+ static void dmsg(int msk, const char *msg,...) {}
+ int _err_(int v) { error(v); return v; }
+ int _fail_(int v) { return v; }
+#define err_(v) _err_(v)
+#define fail_(v) _fail_(v)
+#endif
+
+#define Err(v) return err_(v)
+#define Fail(v) return fail_(v)
+
+#define if_ret(fn) do{ int _ret; \
+ if(unlikely((_ret=(fn))<0)) return _ret; \
+}while(0)
+#define if_err(fn) do{ int _ret; \
+ if(unlikely((_ret=(fn))<0)) Err(_ret); \
+}while(0)
+#define if_fail(fn) do{ int _ret; \
+ if(unlikely((_ret=(fn))<0)) Fail(_ret); \
+}while(0)
+
+ class DbInfo {
+ public:
+ int magic;
+ int owner, last_owner;
+ int info_key, info_id;
+ int root_info_id;
+ int index_info_id;
+ int page_info_id;
+ zlock_t infoLk; // lock dbinfo up to here
+ zrwlock_t dbRwLk; // global lock
+ zrwlock_t pgTblLk;// pageTable realloc
+ zlock_t pgAlLk; // new page pagesUsed/pagesAllocated
+ zlock_t pgLdLk; // pageLoad
+ zlock_t blkAlLk; // blockAllocate/Free
+ zlock_t objAlLk; // objectAllocate/Free
+ zrwlock_t rw_locks[max_entity_type];
+
+ DbInfo(int pid, int key, int id);
+ } *db_info;
+ int new_info(int key);
+ int get_info(int key);
+ int del_info();
+
+ int attach_wr();
+ int attach_rd();
+ int attach_rw(int zrw) { return zrw ? attach_wr() : attach_rd(); }
+ void detach_rw();
+
+ class Page;
+
+ class pagePrefix {
+ public:
+ unsigned short magic;
+ unsigned short type;
+ int used;
+ };
+
+ Page *get_Page(pageId pid) volatile { return pageTable[pid]; }
+ void set_Page(pageId pid, Page *pp) { pageTable[pid] = pp; }
+ //Page *get_page(pageId pid) { blocked by(pgTblk); return get_Page(pid); }
+ Page *get_page(pageId pid); // locked pageTable access
+
+ static pageId getPageId(unsigned char *&bp) {
+ int i = sizeof(pageId); pageId id;
+ for( id = *bp++; --i > 0; id |= *bp++ ) id <<= 8;
+ return id;
+ }
+ static void putPageId(unsigned char *&bp, pageId id) {
+ int i = sizeof(pageId) * 8;
+ while( (i -= 8) >= 0 ) *bp++ = id >> i;
+ }
+ static pageId readPageId(char *cp) {
+ unsigned char *bp = (unsigned char *)cp;
+ return getPageId(bp);
+ }
+ static void writePageId(char *cp, pageId id) {
+ unsigned char *bp = (unsigned char *)cp;
+ putPageId(bp,id);
+ }
+
+ class keyBlock : public pagePrefix {
+ char rightLink[sizeof(pageId)];
+ public:
+ int right_link() { return readPageId(&rightLink[0]); }
+ void right_link(pageId id) { writePageId(&rightLink[0],id); }
+ };
+
+ static int defaultBlockSizes[];
+
+ class IndexTypeInfo {
+ public:
+ int magic;
+ int type; /* type of index */
+ char name[nmSz]; /* index string identifier */
+ };
+
+ class IndexBaseType : public IndexTypeInfo {
+ public:
+ IndexBaseType(int typ);
+ };
+
+ class IndexRecdInfo {
+ public:
+ int idx; /* index in db->indecies[] */
+ int keySz, dataSz; /* sizeof key/data fields in bytes */
+ pageId rootPageId; /* index root page ID */
+ pageId rightHandSide; /* the right hand side of the tree for this index */
+ pageId freeBlocks; /* free index page list */
+ unsigned int blockSize; /* size of new index blocks */
+ int pad1;
+ long count; /* index population count */
+ };
+
+ class IndexBaseRecd : public IndexRecdInfo {
+ public:
+ IndexBaseRecd(int typ, int zidx, int ksz, int dsz);
+ };
+
+ class IndexBaseStorage;
+ class IndexBaseInfo : public IndexTypeInfo, public IndexRecdInfo {
+ public:
+ operator IndexBaseStorage *() { return (IndexBaseStorage *)this; }
+ };
+
+ class IndexBaseStorage : public IndexBaseInfo {
+ public:
+ IndexBaseStorage(int typ, int zidx, int ksz, int dsz);
+ IndexBaseStorage() {}
+ ~IndexBaseStorage() {}
+ };
+
+ class IndexBase {
+ IndexBaseStorage *st;
+ friend class Db;
+ Db *db; /* owner db */
+ zlock_t idxLk;
+ pgRef lastAccess, lastFind; /* last operational access/find location */
+ pgRef lastInsert, lastDelete; /* last operational insert/delete location */
+ pgRef lastNext; /* last operational next location */
+ int kdSz; /* keySz + dataSz */
+ int lastOp; /* last operation, delete=-1/find=0/insert=1 */
+ int cInsCount; /* number of consecutive insertions */
+ int cFindCount; /* number of consecutive finds */
+ int cDelCount; /* number of consecutive deletions */
+
+ void init(Db *zdb);
+ virtual int keyMap(pageId s, int(IndexBase::*fn)(pageId id)) = 0;
+ virtual int keyCopy(pageId s, IndexBase *ib) = 0;
+ int blockAllocate(pageId &pid, keyBlock *&bp);
+ int blockAllocate(pageId &pid, keyBlock *&bp, Page *&pp, char *&cp) {
+ pp = 0; cp = 0; if_err( blockAllocate(pid, bp) );
+ pp = db->get_page(pid); cp = (char *)(bp + 1);
+ return 0;
+ }
+ int blockFree(pageId pid);
+ int blockRelease(pageId pid);
+ int deleteFreeBlocks();
+ void chkLastInsert();
+ void chkLastDelete();
+ void chkLastFind(pgRef &last);
+ public:
+#ifdef DEBUG
+ int _err_(int v,const char *fn,int ln) { return db->_err_(v,fn,ln); }
+ int _fail_(int v,const char *fn,int ln) { return db->_fail_(v,fn,ln); }
+#else
+ int _err_(int v) { return db->_err_(v); }
+ int _fail_(int v) { return db->_fail_(v); }
+#endif
+ virtual int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData) = 0;
+ virtual int Find(void *key,void *rtnData) = 0;
+ virtual int Insert(void *key,void *data) = 0;
+ virtual int Delete(void *key) = 0;
+ virtual int First(void *rtnKey,void *rtnData) = 0;
+ virtual int Last(void *rtnKey,void *rtnData) = 0;
+ virtual int Modify(void *key,void *recd) = 0;
+ virtual int Next(pgRef &loc,void *rtnKey,void *rtnData) = 0;
+ int First(pgRef &loc,void *rtnKey,void *rtnData) {
+ if_fail( First(rtnKey, rtnData) );
+ loc = lastNext;
+ return 0;
+ }
+ int Next(void *rtnKey,void *rtnData) {
+ if( lastNext.id < 0 ) Fail(errInvalid);
+ return Next(lastNext,rtnKey,rtnData);
+ }
+ long Count() { return st->count; }
+ int MakeRoot();
+ int UnmakeRoot();
+ int Clear();
+ int NextLoc(pgRef &loc) { loc = lastNext; return 0; }
+ IndexBase(Db *zdb, int typ, int zidx, int ksz, int dsz);
+ IndexBase(Db *zdb, IndexBaseStorage &d);
+ virtual ~IndexBase();
+ } **indecies;
+
+ int indeciesAllocated, indecies_sz;
+
+ class IndexBinaryStorage;
+ class IndexBinaryInfo {
+ public:
+ operator IndexBinaryStorage *() { return (IndexBinaryStorage *)this; }
+ int cmprId;
+ };
+
+ class IndexBinaryStorage : public IndexBinaryInfo {
+ public:
+ IndexBinaryStorage(int cmprId) { this->cmprId = cmprId; }
+ IndexBinaryStorage() {}
+ ~IndexBinaryStorage() {}
+ };
+
+ class IndexBinary : public IndexBase {
+ IndexBinaryStorage *bst;
+ friend class Db;
+ CmprFn compare; /* the key compare function type */
+ char *akey; /* pointer to key argument */
+ int keyInterior; /* last insert interior/exterior */
+ int idf; /* interior delete flag */
+ char *iky, *tky; /* search/promoted temp key storage */
+
+ void init();
+ int keyMap(pageId s, int(IndexBase::*fn)(pageId id));
+ int keyCopy(pageId s, IndexBase *ib);
+ int keyBlockUnderflow(int &t,keyBlock *lbb,pageId p,keyBlock *pbb,int pi);
+ void makeKey(char *cp,char *key,int l,char *recd,int n);
+ void setLastKey(pageId s,pageId u,int k);
+ int keyLocate(pgRef &last,pageId s, int op,void *ky, CmprFn cmpr);
+ int chkNext(pgRef &loc, char *&kp);
+ int keyNext(pgRef &loc, char *kp);
+ int chkFind(pgRef &loc, char *key);
+ int keyFind(pgRef &loc,void *ky, pageId s);
+ int chkInsert(void *key,void *data);
+ int keyInsert(pageId s, pageId &t);
+ int chkDelete(pgRef &loc, void *kp);
+ int keyDelete(int &t,void *kp,pageId s,pageId p,keyBlock *pbb,int pi);
+ int keyFirst(pgRef &loc, pageId s);
+ int keyLast(pgRef &loc, pageId s);
+
+ int refLocate(pgRef &loc, int op,void *key, CmprFn cmpr);
+ int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData);
+ int refFind(pgRef &loc, void *key);
+ int Find(void *key,void *rtnData);
+ int Insert(void *key,void *data);
+ int Delete(void *key);
+ int First(void *rtnKey,void *rtnData);
+ int Last(void *rtnKey,void *rtnData);
+ int Modify(void *key,void *recd);
+ int Next(pgRef &loc,void *rtnKey,void *rtnData);
+ int Next(void *rtnKey,void *rtnData) {
+ return IndexBase::Next(rtnKey,rtnData);
+ }
+
+ char *ikey() { return iky; }
+ char *tkey() { return tky; }
+ public:
+ IndexBinary(Db *zdb, int zidx, int ksz, int dsz, CmprFn cmpr);
+ IndexBinary(Db *zdb, IndexBaseStorage *b, IndexBinaryStorage *d);
+ IndexBinary(IndexBase *ib, IndexBaseStorage *b, IndexBinaryStorage *d);
+ ~IndexBinary();
+ };
+ friend class IndexBinary;
+
+ class IndexStringStorage;
+ class IndexStringInfo {
+ char dummy; // compiler needs this for some reason
+ public:
+ operator IndexStringStorage *() { return (IndexStringStorage *)this; }
+ };
+
+ class IndexStringStorage : public IndexStringInfo {
+ public:
+ IndexStringStorage() {}
+ ~IndexStringStorage() {}
+ };
+
+ class IndexString : public IndexBase {
+ IndexStringStorage *sst;
+ friend class Db;
+ static int ustrcmp(unsigned char *a, unsigned char *b) {
+ return strncmp((char *)a,(char *)b,keysz);
+ }
+ static void ustrcpy(unsigned char *a, unsigned char *b) {
+ strncpy((char *)a,(char *)b,keysz);
+ }
+ static void umemmove(unsigned char *&a, unsigned char *b, int n) {
+ memmove(a,b,n); a += n;
+ }
+ static int kpress(unsigned char *kp, unsigned char *lp, unsigned char *cp);
+ int split(int n, int i, pageId s, pageId &l, pageId r);
+ void init();
+ int keyMap(pageId s, int(IndexBase::*fn)(pageId id));
+ int keyCopy(pageId s, IndexBase *ib);
+ int chkInsert(void *key,void *data);
+ int keyInsert(pageId &t, pageId s);
+ int keyFirst(pageId s);
+ int keyLast(pageId s);
+ int keyLocate(pgRef &last,pageId s,int &t, int op,
+ unsigned char *ky,CmprFn cmpr, unsigned char *rky);
+ int chkFind(pgRef &loc, char *key, unsigned char *lkey, unsigned char *lky=0);
+ int keyFind(pgRef &loc, unsigned char *ky);
+ int keyNext(pgRef &loc, unsigned char *rky);
+ int keyUnderflow(pageId s, pageId &t, int k);
+ int keyOverflow(pageId s, pageId &t, int k, int o);
+ int keyRemap(pageId s, pageId &t, int k, int o);
+ int keyDelete(pageId s, pageId &t);
+
+ unsigned char lastAccKey[keysz], lastFndKey[keysz];
+ unsigned char lastInsKey[keysz], lastDelKey[keysz];
+ unsigned char lastNxtKey[keysz];
+ unsigned char *tky, *dky; // dataSz+keysz+1
+ unsigned char *tbfr; // 3*allocated
+ unsigned char akey[keysz]; // key in use
+ int idf; /* interior delete flag */
+
+ int refLocate(pgRef &loc, int op, void *key, CmprFn cmpr, unsigned char *rkey);
+ int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData);
+ int refFind(pgRef &loc, void *key);
+ int Find(void *key,void *rtnData);
+ int Insert(void *key,void *data);
+ int Delete(void *key);
+ int First(void *rtnKey,void *rtnData);
+ int Last(void *rtnKey,void *rtnData);
+ int Modify(void *key,void *recd);
+ int Next(pgRef &loc,void *rtnKey,void *rtnData);
+ int Next(void *rtnKey,void *rtnData) {
+ return IndexBase::Next(rtnKey,rtnData);
+ }
+
+ public:
+ IndexString(Db *zdb, int zidx, int dsz);
+ IndexString(Db *zdb, IndexBaseStorage *b, IndexStringStorage *d);
+ IndexString(IndexBase *ib, IndexBaseStorage *b, IndexStringStorage *d);
+ ~IndexString();
+ };
+ friend class IndexString;
+
+ class IndexBinaryData : public IndexBaseInfo, public IndexBinaryInfo {};
+ class IndexStringData : public IndexBaseInfo, public IndexStringInfo {};
+
+ typedef union {
+ IndexBaseInfo base;
+ IndexBinaryData bin;
+ IndexStringData str;
+ } IndexInfo;
+ IndexInfo *index_info; /* image for index storage */
+
+ class allocPrefix {
+ public:
+ unsigned short magic;
+ unsigned short type;
+ int size;
+ };
+
+ class freeStoreRecord {
+ public:
+ long size;
+ ioAddr io_addr;
+ };
+
+ class addrStoreRecord {
+ public:
+ ioAddr io_addr;
+ long size;
+ };
+
+ class freeSpaceRecord {
+ public:
+ long size;
+ pageId id;
+ int offset;
+ };
+
+ class addrSpaceRecord {
+ public:
+ pageId id;
+ int offset;
+ long size;
+ };
+
+ class AllocCache {
+ pgRef loc;
+ int avail;
+ public:
+ int cacheFlush(Db *db);
+ int Get(Db *db,int &size, pgRef &ref);
+ int Load(Db *db, pageId id, int ofs, int sz);
+ void init() { loc.id = NIL; loc.offset = 0; avail = 0; }
+ void init(pageId id, int ofs, int sz) {
+ loc.id = id; loc.offset = ofs; avail = sz;
+ }
+ void dmp() {
+ printf("loc: %d/%d avl: %d\n", loc.id,loc.offset,avail);
+ }
+ } alloc_cache;
+ int cacheFlush() {
+ return alloc_cache.cacheFlush(this);
+ }
+ int cache_all_flush();
+
+ class PageStorage {
+ public:
+ unsigned int used;
+ unsigned int allocated;
+ unsigned short flags;
+ unsigned short type;
+ int io_allocated;
+ int wr_allocated;
+ int shmid;
+ pageId link;
+ transId trans_id;
+ ioAddr io_addr;
+ ioAddr wr_io_addr;
+
+ void init();
+ PageStorage() { init(); }
+ ~PageStorage() {}
+ int chk_flags(int fl) { return flags & fl; }
+ int set_flags(int fl) { return flags |= fl; }
+ int clr_flags(int fl) { return flags &= ~fl; }
+ } *page_info;
+
+ class Page {
+ zlock_t pgLk;
+ PageStorage *st;
+ pagePrefix *addr;
+ int shm_id;
+ void init();
+ public:
+ // PageStorage access
+ int iused() { return st->used-sizeof(keyBlock); }
+ void iused(int v) { st->used = v+sizeof(keyBlock); }
+ int iallocated() { return st->allocated-sizeof(keyBlock); }
+ void iallocated(int v) { st->allocated = v+sizeof(keyBlock); }
+ PageStorage *operator ->() { return st; }
+ int release();
+ void reset_to(Page *pp);
+ Page(PageStorage &d) { st = &d; init(); }
+ ~Page() {}
+ friend class Db;
+ } **pageTable;
+ int pageTableAllocated, page_table_sz;
+
+ int entityPageSize;
+ int storeBlockSize;
+ int pageTableHunkSize;
+ int indexTableHunkSize;
+
+ class undoData {
+ public:
+ class cfnData {
+ public:
+ int cmprId;
+ CmprFn compare;
+ } *cfn;
+ int cfnAllocated, cfnUsed;
+ undoData() : cfn(0), cfnAllocated(0), cfnUsed(0) {}
+ ~undoData() { delete [] cfn; cfnAllocated = cfnUsed = 0; }
+ int save(Db *db);
+ int restore(Db *db);
+ } undata;
+
+ ioAddr file_position;
+
+ char *bfr, *lmt, *inp;
+ int open_bfr();
+ int close_bfr();
+ int flush_bfr();
+ int write_bfr(char *dp, int sz);
+
+public:
+#ifdef ZMEDIA
+
+ // count of on bits
+ inline static unsigned int on_bits(unsigned int n) {
+ n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
+ n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
+ n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
+ n += n >> 8; n += n >> 16; //ok, fldsz > 5 bits
+ return n & 0x1f;
+ }
+
+ // lowest on bit
+ inline static unsigned int low_bit(unsigned int n) {
+ return n & ~(n-1);
+ }
+
+ // bit number of lowest on bit
+ inline static unsigned int low_bit_no(unsigned int n) {
+ return on_bits(low_bit(n) - 1);
+ }
+
+ // highest on bit, and all lower bits set
+ inline static unsigned int high_bit_mask(unsigned int n) {
+ n |= n >> 1; n |= n >> 2;
+ n |= n >> 4; n |= n >> 8;
+ n |= n >> 16;
+ return n;
+ }
+
+ // highest on bit
+ inline static unsigned int high_bit(unsigned int n) {
+ unsigned m = high_bit_mask(n);
+ return m & ~(m>>1);
+ }
+
+ // bit number of highest on bit
+ inline static unsigned int high_bit_no(unsigned int n) {
+ return on_bits(high_bit_mask(n)) - 1;
+ }
+
+ class pack {
+ static inline int cpu_aligned() {
+ unsigned long flags;
+ asm volatile( "pushf\n" "pop %0\n" : "=rm" (flags) );
+ return (flags>>18) & 1;
+ }
+ static int aligned;
+ int idx;
+ uint8_t *bits;
+ uint64_t vmx;
+ uint64_t clip(int64_t v) { return v<0 ? 0 : (uint64_t)v>vmx ? vmx : v; }
+ public:
+ enum { alignBits = 8, };
+
+ static void init(int v=-1) { aligned = v >= 0 ? v : cpu_aligned(); }
+ void put(uint64_t v, int n);
+ void putc(uint64_t v, int n) { put(clip(v), n); }
+ void iput(int v) { put(v, 8*sizeof(int)); }
+ void lput(int64_t v) { put(v, 8*sizeof(int64_t)); }
+ uint64_t get(int n);
+ int iget() { return get(8*sizeof(int)); }
+ int64_t lget() { return get(8*sizeof(int64_t)); }
+ int pos() { return idx; }
+ void seek(int i) { idx = i; }
+ void init(uint8_t *bp) { bits = bp; idx = 0; vmx = 0; }
+ uint8_t *bfr() { return this->bits; }
+ void align() { idx = (idx+alignBits-1) & ~(alignBits-1); }
+ void *addr() { return &bits[idx/8]; }
+ void set_max(uint64_t v) { vmx = v; }
+
+ pack() : bits(0) { idx = 0; }
+ pack(uint8_t *bp) { init(bp); }
+ ~pack() {}
+ };
+
+ class mediaKey {
+ int w, len;
+ int64_t cnt;
+ uint8_t *bp;
+
+ public:
+ static int64_t bit_size(int len, int w);
+ static int64_t byte_size(int len, int w);
+ static void build(uint8_t *kp, uint8_t *bp, int w, int len) {
+ mediaKey key(kp, bp, w, len);
+ }
+ static int64_t count(void *kp) {
+ mediaKey *mkp = (mediaKey *)kp;
+ return be64toh(mkp->cnt);
+ }
+ static int64_t set_count(void *kp, int64_t v) {
+ mediaKey *mkp = (mediaKey *)kp;
+ return mkp->cnt = htobe64(v);
+ }
+ static int64_t incr_count(void *kp, int64_t dv) {
+ return set_count(kp, count(kp) + dv);
+ }
+ static int64_t count1(uint8_t *kp);
+ mediaKey(uint8_t *kp, uint8_t *bp, int w, int len);
+ ~mediaKey();
+ };
+
+ class mediaLoad {
+ pack pb, pk;
+ int w, len, dsz, psz, spos;
+ int64_t cnt, *dat, **dp;
+ void get_fields(int n, int k);
+ int dsize(int n) { int m = (n+1)/2; return m>1 ? m+dsize(m) : 1; }
+
+ public:
+ void load(uint8_t *kp);
+
+ mediaLoad(uint8_t *bp);
+ ~mediaLoad();
+ };
+
+ class mediaCmpr {
+ pack pb, pk;
+ int w, len, dsz, psz, spos;
+ int64_t acnt, bcnt, *adat, *bdat, **adp, **bdp;
+ uint64_t err, lmt;
+ uint64_t sqr(int64_t v) { return v*v; }
+ int dsize(int n) { int m = (n+1)/2; return m>1 ? m+dsize(m) : 1; }
+ uint64_t chk_fields(int m, int k);
+ int cmpr_fields(int m, int k);
+
+ public:
+ uint64_t chk(uint8_t *kp, uint64_t lmt=~0);
+ int cmpr(uint8_t *kp, uint64_t lmt=~0);
+
+ mediaCmpr(uint8_t *bp);
+ ~mediaCmpr();
+ };
+#endif
+
+ class Entity;
+ class ObjectLoc;
+ typedef IndexBase *Index;
+ int new_entity(Entity &entity, const char *nm, int sz);
+ int get_entity(Entity &entity, const char *nm);
+ int del_entity(Entity &entity);
+
+ class Obj { /* per object storage base class */
+ public:
+ int id;
+ };
+
+ class varObj {
+ public:
+ int len; pgRef loc;
+ int size() { return len; }
+ void init() { len = -1; loc.id = NIL; loc.offset = 0; }
+ void del(Entity *entity) { len = -1; entity->deallocate(loc); }
+ };
+ typedef varObj Obj::*vRef;
+
+ class ObjectLoc {
+ public:
+ Entity *entity;
+ pgRef obj;
+ Obj *addr(pgRef &loc) {
+ char *op = 0;
+ return loc.id < 0 || entity->db->addrRead(loc,op) ? 0 : (Obj *)op;
+ }
+ Obj *addr_wr(pgRef &loc) {
+ char *op = 0;
+ return loc.id < 0 || entity->db->addrWrite(loc,op) ? 0 : (Obj *)op;
+ }
+ void _wr() { Page &pg = *entity->db->get_page(obj.id); pg->set_flags(fl_wr); }
+ Obj *addr() { return addr(obj); }
+ Obj *addr_wr() { return addr_wr(obj); }
+ void *addr(varObj &vobj) { return addr(vobj.loc); }
+ void *addr_wr(varObj &vobj) { return addr_wr(vobj.loc); }
+ Obj *operator ->() { return (Obj *)addr(); }
+ ObjectLoc(Entity *ep) : entity(ep) { obj.id = NIL; obj.offset = 0; }
+ ~ObjectLoc() {}
+
+ virtual int allocate(int sz=0) { return entity->allocate(*this,sz); }
+ virtual int construct() { return entity->construct(*this); }
+ virtual int destruct() { return entity->destruct(*this); }
+ virtual int deallocate() { return entity->deallocate(*this); }
+ virtual int insertCascade() { return 0; }
+ virtual int insertProhibit() { return 0; }
+ virtual int deleteCascade() { return 0; }
+ virtual int deleteProhibit() { return 0; }
+ virtual int modifyCascade() { return 0; }
+ virtual int modifyProhibit() { return 0; }
+ virtual int copy(ObjectLoc &dobj);
+ int id() { ObjectLoc &oloc = *this; return oloc->id; }
+ const int *_id() { ObjectLoc &oloc = *this; return &oloc->id; }
+ int _id_size() { return sizeof(int); }
+ int size(varObj &vobj) { return vobj.len; }
+ int size(varObj &vobj, int sz);
+ Index index(int i) { return entity->index(i); }
+ void v_init();
+ void v_del();
+
+ int FindId(int id) { return index(idxId)->Find(&id,&obj); }
+ int LocateId(int op, int id) { return index(idxId)->Locate(op,&id,0,0,&obj); }
+ int FirstId() { return index(idxId)->First(0,&obj); }
+ int LastId() { return index(idxId)->Last(0,&obj); }
+ int NextId() { return index(idxId)->Next(0,&obj); }
+ int FirstId(pgRef &loc) { return index(idxId)->First(loc,0,&obj); }
+ int NextId(pgRef &loc) { return index(idxId)->Next(loc,0,&obj); }
+ int NextLocId(pgRef &loc) { return index(idxId)->NextLoc(loc); }
+
+ static int cmpr_char(const char *ap, int asz, const char *bp, int bsz);
+ static int cmpr_uchar(const unsigned char *ap, int asz, const unsigned char *bp, int bsz);
+ static int cmpr_short(const short *ap, int asz, const short *bp, int bsz);
+ static int cmpr_ushort(const unsigned short *ap, int asz, const unsigned short *bp, int bsz);
+ static int cmpr_int(const int *ap, int asz, const int *bp, int bsz);
+ static int cmpr_uint(const unsigned int *ap, int asz, const unsigned int *bp, int bsz);
+ static int cmpr_long(const long *ap, int asz, const long *bp, int bsz);
+ static int cmpr_ulong(const unsigned long *ap, int asz, const unsigned long *bp, int bsz);
+ static int cmpr_float(const float *ap, int asz, const float *bp, int bsz);
+ static int cmpr_double(const double *ap, int asz, const double *bp, int bsz);
+#ifdef ZMEDIA
+ static int cmpr_media(const unsigned char *ap, int asz, const unsigned char *bp, int bsz);
+#endif
+
+#ifdef DEBUG
+ int _err_(int v,const char *fn,int ln) { return entity->db->_err_(v,fn,ln); }
+ int _fail_(int v,const char *fn,int ln) { return entity->db->_fail_(v,fn,ln); }
+#else
+ int _err_(int v) { return entity->db->_err_(v); }
+ int _fail_(int v) { return entity->db->_fail_(v); }
+#endif
+
+ int last(int idx,int (ObjectLoc::*ip)());
+ int last(const char *nm,int (ObjectLoc::*ip)());
+ unsigned int last(int idx,unsigned int (ObjectLoc::*ip)());
+ unsigned int last(const char *nm,unsigned int (ObjectLoc::*ip)());
+ };
+
+ class Key {
+ public:
+ ObjectLoc &loc;
+ Index idx;
+ CmprFn cmpr;
+ Key(Index i, ObjectLoc &l, CmprFn c) : loc(l), idx(i), cmpr(c) {}
+ Key(const char *nm, ObjectLoc &l, CmprFn c) : loc(l), cmpr(c) {
+ idx = loc.entity->index(nm);
+ }
+ operator void *() { return (void *)this; }
+#ifdef DEBUG
+ int _err_(int v,const char *fn,int ln) { return loc._err_(v,fn,ln); }
+ int _fail_(int v,const char *fn,int ln) { return loc._fail_(v,fn,ln); }
+#else
+ int _err_(int v) { return loc._err_(v); }
+ int _fail_(int v) { return loc._fail_(v); }
+#endif
+ };
+
+ class iKey : public Key {
+ public:
+ iKey(Index i, ObjectLoc &l, CmprFn c) : Key(i,l,c) {}
+ iKey(const char *nm, ObjectLoc &l, CmprFn c) : Key(nm,l,c) {}
+ int NextLoc(pgRef &pos) { return idx->NextLoc(pos); }
+ int Find();
+ int Locate(int op=keyGE);
+ };
+
+ class rKey : public Key {
+ public:
+ rKey(Index i, ObjectLoc &l, CmprFn c) : Key(i,l,c) {}
+ rKey(const char *nm, ObjectLoc &l, CmprFn c) : Key(nm,l,c) {}
+ int NextLoc(pgRef &pos) { return idx->NextLoc(pos); }
+ int First(); int First(pgRef &pos);
+ int Next(); int Next(pgRef &pos);
+ int Last();
+ int Locate(int op=keyGE);
+ };
+
+private:
+ class EntityObj : public Obj { /* entity storage */
+ public:
+ char name[nmSz]; /* string identifier */
+ AllocCache alloc_cache; /* entity allocator cache */
+ int maxId; /* highest ID value */
+ int recdSz; /* record size in bytes */
+ int count; /* number of records */
+ int nidxs; /* index count */
+ int indexs[1]; /* id/loc index */
+ EntityObj(EntityObj &eobj, int eid);
+ };
+
+ class EntityLoc : public ObjectLoc {
+ public:
+ EntityObj *operator ->() { return (EntityObj *)addr(); }
+ EntityLoc(Entity *ep) : ObjectLoc(ep) {}
+ ~EntityLoc() {}
+ int cacheFlush() {
+ EntityLoc &eloc = *this; _wr();
+ return eloc->alloc_cache.cacheFlush(entity->db);
+ }
+ };
+
+ class varObjRef;
+ typedef varObjRef *varObjs;
+ class varObjRef {
+ public:
+ varObjs next;
+ vRef ref;
+ varObjRef(varObjs &lp, vRef rp) : next(lp), ref(rp) {}
+ };
+
+ static int ioCmpr(const void *a, const void *b, void *c);
+public:
+
+ class Entity {
+ public:
+ Db *const db;
+ EntityLoc ent;
+ varObjs vobjs;
+ zrwlock_t *rw_lock;
+ operator zrwlock_t&() { return *rw_lock; }
+
+#ifdef DEBUG
+ int _err_(int v,const char *fn,int ln) { return db->_err_(v,fn,ln); }
+ int _fail_(int v,const char *fn,int ln) { return db->_fail_(v,fn,ln); }
+#else
+ int _err_(int v) { return db->_err_(v); }
+ int _fail_(int v) { return db->_fail_(v); }
+#endif
+ Entity(Db *const db) : db(db), ent(this), vobjs(0) {}
+ ~Entity() {}
+
+ int allocate(ObjectLoc &loc,int sz=0);
+ int construct_(ObjectLoc &loc, int id);
+ int construct(ObjectLoc &loc) { return construct_(loc,ent->maxId); }
+ int destruct_(ObjectLoc &loc, int id);
+ int destruct(ObjectLoc &loc) { return destruct_(loc, loc->id); }
+ int deallocate(pgRef &obj) { return db->deallocate(obj,ent->alloc_cache); }
+ int deallocate(ObjectLoc &loc) { return deallocate(loc.obj); }
+ int get_index(const char *nm, CmprFn cmpr=0);
+ int key_index(const char *nm) { return get_index(nm,Db::cmprKey); }
+ Index index(int i) { return db->indecies[ent->indexs[i]]; }
+ Index index(const char *nm) {
+ int idx = get_index(nm);
+ return idx >= 0 ? index(idx) : 0;
+ }
+ int MaxId() { return ent->maxId; }
+ int Count() { return ent->count; }
+ int add_index(int idx);
+ int add_bindex(const char *nm,int keySz,int dataSz) {
+ int idx = db->new_binary_index(nm,keySz,dataSz);
+ if_err( idx ); if_err( add_index(idx) );
+ return 0;
+ }
+ int add_kindex(const char *nm) { return add_bindex(nm,0,sizeof(int)); }
+ int add_sindex(const char *nm,int dataSz) {
+ int idx = db->new_string_index(nm,dataSz);
+ if_err( idx ); if_err( add_index(idx) );
+ return 0;
+ }
+ int del_index_(int idx);
+ int del_index(int idx);
+ int del_index(const char *nm);
+ int new_entity(const char *nm, int sz) { return db->new_entity(*this,nm,sz); }
+ int get_entity(const char *nm) { return db->get_entity(*this,nm); }
+ int del_entity() { return db->del_entity(*this); }
+ void add_vref(vRef rp) { vobjs = new varObjRef(vobjs,rp); }
+ };
+
+ class ObjectList;
+ typedef ObjectList *Objects;
+ static void finit(Objects objects);
+
+ class ObjectList {
+ public:
+ Objects next;
+ ObjectLoc *obj;
+ ObjectList(Objects op, ObjectLoc &o) : next(op), obj(&o) {}
+ };
+
+private:
+ int new_entity_(Entity &entity, const char *nm, int sz);
+
+ int findCmprFn(CmprFn fn);
+ int pageLoad(pageId id, Page &pg);
+ int addrRead_(pgRef &loc, char *&vp, int mpsz=0) {
+ Page &pg = *get_page(loc.id); vp = 0;
+ if( unlikely( !pg.addr || pg->chk_flags(fl_rd) ) ) {
+ if_err( pageLoad(loc.id, pg) );
+ }
+ vp = (char *)pg.addr+loc.offset+mpsz;
+ return 0;
+ }
+ int addrRead_(pgRef &loc, keyBlock *&vp, int mpsz=0) {
+ return addrRead_(loc,*(char**)&vp, mpsz);
+ }
+ int addrRead_(pgRef &loc, allocPrefix *&vp, int mpsz=0) {
+ return addrRead_(loc,*(char**)&vp, mpsz);
+ }
+ int addrRead_(pgRef &loc, pagePrefix *&vp, int mpsz=0) {
+ return addrRead_(loc,*(char**)&vp, mpsz);
+ }
+ int addrWrite_(pgRef &loc, char *&vp, int mpsz=0) {
+ Page &pg = *get_page(loc.id); vp = 0;
+ if( unlikely( !pg.addr || pg->chk_flags(fl_rd) ) ) {
+ if_err( pageLoad(loc.id, pg) );
+ }
+ pg->set_flags(fl_wr);
+ vp = (char *)pg.addr+loc.offset+mpsz;
+ return 0;
+ }
+ int addrWrite_(pgRef &loc, keyBlock *&vp, int mpsz=0) {
+ return addrWrite_(loc,*(char**)&vp, mpsz);
+ }
+ int addrWrite_(pgRef &loc, allocPrefix *&vp, int mpsz=0) {
+ return addrWrite_(loc,*(char**)&vp, mpsz);
+ }
+ int addrWrite_(pgRef &loc, pagePrefix *&vp, int mpsz=0) {
+ return addrWrite_(loc,*(char**)&vp, mpsz);
+ }
+ int addrRead(pgRef &loc, char *&vp) {
+ return addrRead_(loc, vp, sizeof(allocPrefix));
+ }
+ int addrWrite(pgRef &loc, char *&vp) {
+ return addrWrite_(loc, vp, sizeof(allocPrefix));
+ }
+
+ int objectHeapInsert(int sz,int pg,int off);
+ int objectHeapDelete(int sz,int pg,int off);
+ int objectAllocate(int typ, int &size, pgRef &loc,AllocCache &cache);
+ int objectFree(pgRef &loc);
+ int pgRefGet(int &size, pgRef &loc,AllocCache &cache);
+ int pgRefNew(int &size, pgRef &lo,AllocCache &cache);
+ int pgRefAllocate(int &size, pgRef &lo,AllocCache &cache);
+
+ int storeInsert(long size, ioAddr io_addr);
+ int storeDelete(long size, ioAddr io_addr);
+ int storeGet(int &size, ioAddr &io_addr);
+ int storeNew(int &size, ioAddr &io_addr);
+ int storeAllocate(int &size, ioAddr &io_addr);
+ int storeFree(int size, ioAddr io_addr);
+
+ int icommit(int force);
+ int iundo();
+ int iclose();
+ int ireopen();
+ int iattach();
+ int iopen(int undo_save=1);
+
+protected:
+
+ pageId new_page();
+ void del_page(int id);
+ int alloc_pageTable(int sz);
+ void free_page_(int pid);
+ void free_page(int pid) { locked by(db_info->pgAlLk); free_page_(pid); }
+ pageId lower_page(int mid);
+ int alloc_indecies(int n);
+ int new_index();
+ void del_index(int idx);
+ int new_index(IndexBase *&ibp, IndexBaseInfo *b, IndexBinaryInfo *d);
+ int new_index(IndexBase *&ibp, IndexBaseInfo *b, IndexStringInfo *d);
+ int indexRead(pageId pid, int df, keyBlock *&bp) {
+ pgRef pg; pg.id = pid; pg.offset = 0;
+ return !df ? addrRead_(pg,*(char**)&bp) : addrWrite_(pg,*(char**)&bp);
+ }
+ int indexRead(pageId pid,int df,keyBlock *&bp, Page *&pp, char *&cp) {
+ pp = 0; cp = 0; if_err( indexRead(pid, df, bp) );
+ pp = get_page(pid); cp = (char *)(bp + 1);
+ return 0;
+ }
+ void pageDealloc(Page &pg, int mode=1);
+ int pageRead(ioAddr io_adr, uint8_t *bp, int len);
+ int pageWrite(Page &pg);
+ int seek_data(ioAddr io_addr);
+ int size_data(char *dp, int sz);
+ int read_data(char *dp, int sz);
+ int write_data(char *dp, int sz);
+ int write_zeros(ioAddr io_addr);
+ int write_padding(ioAddr io_addr);
+ int readRootInfo(int(Db::*fn)(char *dp,int sz));
+ int writeRootInfo(int(Db::*fn)(char *dp,int sz));
+ ioAddr storeBlocks(ioAddr sz) { return (sz+storeBlockSize-1)/storeBlockSize; }
+ ioAddr entityPages(ioAddr sz) { return (sz+entityPageSize-1)/entityPageSize; }
+ int indeciesHunks(int sz) { return (sz+indexTableHunkSize-1)/indexTableHunkSize; }
+ int pageTableHunks(int sz) { return (sz+pageTableHunkSize-1)/pageTableHunkSize; }
+ int pagePrefixHunks(int sz) { return (sz+sizeof(pagePrefix)-1)/sizeof(pagePrefix); }
+ int init_idx();
+ void init_shm();
+ void init();
+ void deinit();
+ void reset();
+ int start_transaction(int undo_save=1);
+ void enter() { db_info->dbRwLk.enter(); }
+ void leave() { db_info->dbRwLk.leave(); }
+ void write_enter() { db_info->dbRwLk.write_enter(); }
+ void write_leave() { db_info->dbRwLk.write_leave(); }
+
+public:
+ // 1:wr, 0:rd, -1:unlocked
+ int is_locked() { return db_info->dbRwLk.locked(); }
+ int is_blocked() { return db_info->dbRwLk.blocked(); }
+
+ int make(int zfd);
+ int open(int zfd, int zkey=-1);
+ int close();
+
+ int attach(int zrw, int zfd, int zkey);
+ int attach(int zrw=0) { return attach(fd, key, zrw); }
+ int detach();
+
+ int copy(Db *db, Objects objs);
+ int new_binary_index(const char *nm, int ksz, int dsz, CmprFn cmpr=0);
+ int new_string_index(const char *nm, int dsz);
+ int get_index(const char *nm, CmprFn cmpr=0);
+ long get_count(int r);
+ int ins (int r, void *key, void *data);
+ int del (int r, void *key);
+ int find (int r, void *key, void *rtnData=0);
+ int locate(int r, int op, void *key, CmprFn cmpr, void *rtnKey, void *rtnData=0);
+ int locate(int r, int op, void *key, void *rtnKey, void *rtnData=0) {
+ return locate(r,op,key,0,rtnKey,rtnData);
+ }
+ int first (int r, void *key, void *rtnData=0);
+ int last (int r, void *key, void *rtnData=0);
+ int next (int r, void *key, void *rtnData=0);
+ int nextloc(int r, pgRef &loc);
+ int allocate(int typ, int size, pgRef &loc, AllocCache &cache);
+ int reallocate(int size, pgRef &loc, AllocCache &cache);
+ int deallocate(pgRef &loc, AllocCache &cache);
+ int commit(int force=0);
+ int flush ();
+ int undo ();
+
+ int transaction() { return !root_info ? -1 : root_info->transaction_id; }
+ int64_t filesize() { return !root_info ? -1 : root_info->file_size; }
+ int opened() { return fd>=0 ? 1 : 0; }
+ void use_shm(int v) { no_shm = v ? 0 : 1; }
+ int error() { return err_no; }
+ void error(int v);
+ void Error(int v,const char *msg);
+ int load();
+
+ Db();
+ ~Db();
+
+#ifdef DEBUG
+ void dmp();
+ void tdmp();
+ void pdmp();
+ void fdmp();
+ void admp(); void achk(); void fchk();
+ void edmp();
+ void bdmp();
+ void stats(int chk=1);
+#endif
+
+};
+
+#endif