no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / db / tdb.h
1 #if defined(__i386__) || defined(__x86_64__)
2 #if defined (__linux__)
3 #ifndef __DB_H__
4 #define __DB_H__
5 #include <cstring>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <limits.h>
9 #include <sys/types.h>
10
11 #define entityIdIndex indecies[entityIdIdx]
12 #define entityNmIndex indecies[entityNmIdx]
13 #define freeStoreIndex indecies[freeStoreIdx]
14 #define addrStoreIndex indecies[addrStoreIdx]
15 #define freeSpaceIndex indecies[cache.freeIdx]
16 #define addrSpaceIndex indecies[cache.addrIdx]
17
18 #define noThrow std::nothrow
19 #ifndef likely
20 #define likely(x)   (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 1))
21 #define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __builtin_expect(!!(x), 0))
22 #endif
23 #ifndef lengthof
24 #define lengthof(x) ((int)(sizeof(x)/sizeof(x[0])))
25 #endif
26
27 #if 0
28 inline void *operator new(size_t n) { void *vp = malloc(n); bzero(vp,n); return vp; }
29 inline void operator delete(void *t) { free(t); }
30 inline void operator delete(void *t,size_t n) { free(t); }
31 inline void *operator new[](size_t n) { void *vp = malloc(n); bzero(vp,n); return vp; }
32 inline void operator delete[](void *t) { free(t); }
33 inline void operator delete[](void *t,size_t n) { free(t); }
34 #endif
35
36 #define ZMEDIA
37 #define ZFUTEX
38 #ifdef ZFUTEX
39 #include <unistd.h>
40 #include <endian.h>
41 #include <linux/futex.h>
42 #include <sys/syscall.h>
43 #else
44 #include <pthread.h>
45 #endif
46
47 #if 1
48 //entity definitions
49 #define DbObj(nm) \
50   class nm##Obj : public Db::Obj { public:
51
52 #define DbLoc(nm) \
53   class nm##Loc : public Db::ObjectLoc { public: \
54     nm##Obj *operator ->() { return (nm##Obj *)addr(); } \
55     nm##Loc(Db::Entity *ep) : Db::ObjectLoc(ep) {} \
56     nm##Loc(Db::Entity &e) : Db::ObjectLoc(&e) {}
57
58 //basic definitions
59 #define basic_def(ty,n) class t_##n { public: ty v; t_##n() {} \
60  t_##n(const ty &i) : v(i) {} \
61  t_##n(const t_##n &i) : v(i.v) {} \
62  t_##n &operator =(const t_##n &i) { v = i.v; return *this; } \
63  ty &operator =(const ty &i) { return v = i; } \
64  ty *addr() { return &v; } int size() { return sizeof(v); } \
65  } v_##n \
66
67 //array definitions
68 #define array_def(ty,n,l) class t_##n { public: ty v[l]; t_##n() {} \
69  t_##n(const t_##n &i) { memcpy(&v,&i.v,sizeof(v)); } \
70  t_##n(ty *i) { memcpy(&v,i,sizeof(v)); } \
71  t_##n(ty(*i)[l]) { memcpy(&v,i,sizeof(v)); } \
72  ty *operator =(const ty *i) { memcpy(&v,i,sizeof(v)); return &v[0]; } \
73  ty *addr() { return &v[0]; } int size() { return sizeof(v); } \
74  } v_##n \
75
76 // variable array definitions
77 #define varray_def(ty,n) \
78  class t_##n { public: char *v; int l; t_##n() {} \
79  t_##n(const char *i, int sz) { v = (char *)i; l = sz; } \
80  t_##n(const unsigned char *i, int sz) { v = (char *)i; l = sz; } \
81  ty *addr() { return (ty *)v; } int size() { return l; } \
82  }; Db::varObj v_##n \
83
84 // string array definitions
85 #define sarray_def(ty,n) \
86  class t_##n { public: char *v; int l; t_##n() {} \
87  t_##n(const char *i, int sz) { v = (char *)i; l = sz; } \
88  t_##n(const unsigned char *i, int sz) { v = (char *)i; l = sz; } \
89  t_##n(const char *i) { t_##n(i,strlen(i)+1); } \
90  t_##n(const unsigned char *i) { t_##n(i,strlen(v)+1); } \
91  ty *addr() { return (ty *)v; } int size() { return l; } \
92  }; Db::varObj v_##n \
93
94 //basic type ref
95 #define basic_ref(ty,n) \
96  ty *_##n() { return (*this)->v_##n.addr(); } \
97  ty n() { return *_##n(); } \
98  void n(ty i) { _wr(); *_##n() = i; } \
99  int size_##n() { return (*this)->v_##n.size(); } \
100
101 //array type ref
102 #define array_ref(ty,n,l) \
103  ty *_##n() { return (*this)->v_##n.addr(); } \
104  ty (&n())[l] { return *(ty (*)[l])_##n(); } \
105  void n(const ty *i,int m) { _wr(); if( m > 0 ) memcpy(n(),i,m); } \
106  void n(const ty *i) { n(i,(*this)->v_##n.size()); } \
107  int size_##n() { return (*this)->v_##n.size(); } \
108
109 //variable array type ref
110 #define varray_ref(ty,n) \
111  ty *_##n() { return (ty *)addr((*this)->v_##n); } \
112  ty *_##n(int sz) { size((*this)->v_##n, sz); \
113    return sz > 0 ? (ty *)addr_wr((*this)->v_##n) : 0; } \
114  ty (&n())[] { return *(ty (*)[])_##n(); } \
115  int n(const ty *v, int sz) { ty *vp=_##n(sz); \
116   if( vp && sz > 0 ) memcpy(vp, v, sz); return 0; } \
117  int size_##n() { return (*this)->v_##n.size(); } \
118
119 //string array type ref
120 #define sarray_ref(ty,n) \
121  ty *_##n() { return (ty *)addr((*this)->v_##n); } \
122  ty *_##n(int sz) { size((*this)->v_##n, sz); \
123    return sz > 0 ? (ty *)addr_wr((*this)->v_##n) : 0; } \
124  ty (&n())[] { return *(ty (*)[])_##n(); } \
125  int n(const ty *v, int sz) { ty *vp=_##n(sz); \
126   if( vp && sz > 0 ) memcpy(vp, v, sz); return 0; } \
127  int n(const char *v) { return n((ty *)v,strlen(v)+1); } \
128  int n(const unsigned char *v) { return n((const char *)v); } \
129  int size_##n() { return (*this)->v_##n.size(); } \
130
131 #endif
132
133 #define DEBUG
134 #define DEBUG_TIMESTAMPS
135 #define DBBUG_ERR   0x00000001
136 #define DBBUG_FAIL  0x00000002
137 #define CHK
138 //#define CHK 1 ? 0 :
139
140 class Db;
141
142 class Db {
143 public:
144   typedef int pageId;
145   typedef int transId;
146   typedef long ioAddr;
147
148 private:
149   int root_info_id;
150   int index_info_id;
151   int page_info_id;
152
153   class RootInfo {
154   public:
155     int root_magic;           // info_magic label
156     int root_info_size;       // root_info blob size
157     int last_info_size;
158     int entity_max_id;
159     int entity_count;
160     ioAddr root_info_addr;
161     ioAddr last_info_addr;
162     transId transaction_id;   // current transaction
163     ioAddr file_size;         // current file size
164     pageId freePages;         // free page table page list
165     int indeciesUsed;         // number of active indecies
166     int pageTableUsed;        // number of active pages
167
168     int init();
169   } *root_info;
170
171   int shm_init, no_shm;
172
173   static void *get_mem8_t(int id);
174   static void *new_mem8_t(int size, int &id);
175   static int del_mem8_t(const void *vp, int id);
176   static void *get_shm8_t(int id);
177   static void *new_shm8_t(int size, int &id);
178   static int del_shm8_t(const void *vp, int id);
179   void *(*get_mem)(int id);
180   void *(*new_mem)(int size, int &id);
181   int (*del_mem)(const void *vp, int id);
182
183 protected:
184   uint8_t *get_uint8_t(int id, int pg=-1);
185   uint8_t *new_uint8_t(int size, int &id, int pg=-1);
186   int del_uint8_t(const void *vp, int id=-1, int pg=-1);
187
188 public:
189   typedef int (*CmprFn)(char *,char *);
190   static int cmprFrSt(char *a, char *b);
191   static int cmprAdSt(char *a, char *b);
192   static int cmprFrSp(char *a, char *b);
193   static int cmprAdSp(char *a, char *b);
194   static int cmprOIds(char *a, char *b);
195   static int cmprStr(char *a, char *b);
196   static int cmprKey(char *a, char *b);
197   static int cmprLast(char *a, char *b);
198   static CmprFn cmprFns[];
199   typedef void (*errCallback)(Db *db, int v);
200   static const pageId NIL=-1, DDONE=-2;
201   enum {
202     errNoCmprFn = 0,
203     errNotFound = -1,
204     errDuplicate = -2,
205     errNoPage = -3,
206     errNoMemory = -4,
207     errIoRead = -5,
208     errIoWrite = -6,
209     errIoSeek = -7,
210     errIoStat = -8,
211     errBadMagic = -9,
212     errCorrupt = -10,
213     errInvalid = -11,
214     errPrevious = -12,
215     errObjEntity = -13,
216     errLimit = -14,
217     errUser = -15,
218     idxId = 0, nmSz = 32,
219     keysz = 256,
220     keyLT=-2, keyLE=-1, keyEQ=0, keyGE=1, keyGT=2,
221   };
222
223   class pgRef {
224   public:
225     pageId id;
226     int offset;
227   };
228
229   static void zincr(volatile int &v) { /* atomic(++v) */
230     asm ( " lock incl %1\n" : "+m" (v) :: );
231   }
232   static void zdecr(volatile int &v) { /* atomic(--v) */
233     asm ( " lock decl %1\n" : "+m" (v) :: );
234   }
235   static char tdecr(volatile int &v) {
236     char ret; /* ret = atomic(--loc >= 0 ? 1 : 0) */
237     asm ( " lock decl %1\n setge %0\n" : "=r" (ret), "+m" (v) :: );
238     return ret;
239   }
240   static char tincr(volatile int &v) {
241     char ret; /* ret = atomic(++loc > 0 ? 1 : 0) */
242     asm ( " lock incl %1\n setg %0\n" : "=r" (ret), "+m" (v) :: );
243     return ret;
244   }
245   static int zcmpxchg(int old, int val, volatile int &v) {
246     int ret = old;
247     asm volatile( " lock\n cmpxchgl %2,%1\n"
248       : "+a" (ret), "+m" (v) :  "r" (val) : "memory" );
249     return ret;
250   }
251   static int zxchg(int val, volatile int &v) {
252     asm volatile( " xchgl %0,%1\n"
253       : "+r" (val), "+m" (v) :: "memory" );
254     return val;
255   }
256   static int zadd(int n, volatile int &v) {
257     int old, mod, val;
258     do { val = (old=v)+n; mod = zcmpxchg(old,val,v);
259     } while( mod != old );
260     return val;
261   }
262   static void zmfence() {
263     asm volatile ( " mfence\n" ::: "memory" );
264   }
265
266   class zlock_t;
267   class zblock_t;
268   class zrwlock_t;
269
270 #ifdef ZFUTEX
271 #define ZLOCK_INIT zzlock_t()
272   class zloc_t {
273   protected:
274     volatile int loc;
275     int zfutex(int op, int val, timespec *time=0) {
276       return syscall(SYS_futex,&loc,op,val,time,0,0);
277     }
278     int zyield();
279     int zgettid();
280   public:
281     int zwake(int nwakeups);
282     int zwait(int val, timespec *ts=0);
283     int zwait() { return zwait(loc); }
284     zloc_t() : loc(-1) {}
285     ~zloc_t() {}
286   };
287
288   class zlock_t : zloc_t {
289     void *owner;
290     void *self() {
291 #ifdef __x86_64__
292      void *vp; asm ("movq %%fs:%c1,%q0" : "=r" (vp) : "i" (16));
293 #else
294      void *vp; asm ("mov %%fs:%c1,%q0" : "=r" (vp) : "i" (16));
295 #endif
296      return vp;
297    }
298   protected:
299     friend class zblock_t;
300     friend class zrwlock_t;
301     int zlock(int v);
302     int zunlock(int nwakeups=1);
303     static int zemsg1();
304   public:
305     int lock() {
306       int v, ret = unlikely( (v=zcmpxchg(-1,0,loc)) >= 0 ) ? zlock(v) : 0;
307       owner = self();
308       return ret;
309     }
310     int unlock() {
311       if( unlikely(loc < 0) ) { return zemsg1(); }
312       owner = 0;
313       int v, ret = unlikely( (v=zcmpxchg(0,-1,loc)) != 0 ) ? zunlock() : 0;
314       return ret;
315     }
316     zlock_t() { owner = 0; }
317     ~zlock_t() {}
318   };
319
320   class zblock_t : zlock_t {
321   public:
322     void block() { loc = 0; zwait(0); }
323     void unblock() { loc = -1; zwake(INT_MAX); }
324     zblock_t() {}
325     ~zblock_t() {}
326   };
327
328   class zrwlock_t : zloc_t {
329     zlock_t lk;
330     void zenter();
331     void zleave();
332   public:
333     void enter() { zincr(loc); if( unlikely( lk.loc >= 0 ) ) zenter(); }
334     void leave() { if( unlikely( !tdecr(loc) ) ) zleave(); }
335     void write_enter();
336     void write_leave();
337     int locked() { return loc >= 0 ? 0 : lk.loc >= 0 ? 1 : -1; }
338     int blocked() { return lk.loc >= 0 ? 1 : 0; }
339     zrwlock_t() {}
340     ~zrwlock_t() {}
341   };
342
343 #else
344 #define ZLOCK_INIT { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER }
345
346   class zlock_t {
347   protected:
348     pthread_mutex_t zlock;
349   public:
350     void lock() { pthread_mutex_lock(&zlock); }
351     void unlock() { pthread_mutex_unlock(&zlock); }
352     zlock_t() { pthread_mutex_init(&zlock, 0); }
353     ~zlock_t() { pthread_mutex_destroy(&zlock); }
354   };
355
356   class zblock_t {
357     pthread_mutex_t zblock;
358     pthread_cond_t cond;
359   public:
360     zblock_t() {
361       pthread_mutex_init(&zblock, 0);
362       pthread_cond_init(&cond, 0);
363     }
364     ~zblock_t() {
365       pthread_mutex_destroy(&zblock);
366       pthread_cond_destroy(&cond);
367     }
368     void block() {
369       pthread_mutex_lock(&zblock);
370       pthread_cond_wait(&cond, &zblock);
371       pthread_mutex_unlock(&zblock);
372     }
373     void unblock() { pthread_cond_broadcast(&cond); }
374   };
375
376   class zrwlock_t : zlock_t {
377     volatile int blocking, users;
378     zlock_t lk;
379     pthread_cond_t cond;
380     void wait() { pthread_cond_wait(&cond, &zlock); }
381     void wake() { pthread_cond_signal(&cond); }
382   public:
383     void enter() { lock();
384       while( blocking ) { unlock(); lk.lock(); lk.unlock(); lock(); }
385       ++users;  unlock();
386     }
387     void leave() { lock();  if( !--users && blocking ) wake();  unlock(); }
388     void write_enter() { lk.lock();  blocking = 1;
389       lock(); while( users ) wait(); unlock();
390     }
391     void write_leave() { blocking = 0; lk.unlock(); }
392     int count() { return users; }
393     int locked() { return users ? 0 : blocking ? 1 : -1; }
394     int blocked() { return blocking; }
395
396     zrwlock_t() { pthread_cond_init(&cond, 0); users = 0; blocking = 0; }
397     ~zrwlock_t() { pthread_cond_destroy(&cond); }
398   };
399
400 #endif
401
402   class locked {
403     zlock_t &lk;
404   public:
405     locked(zlock_t &l) : lk(l) { lk.lock(); }
406     ~locked() { lk.unlock(); }
407   };
408
409   class read_locked {
410     zrwlock_t &rwlk;
411   public:
412     read_locked(zrwlock_t &l) : rwlk(l) { rwlk.enter(); }
413     ~read_locked() { rwlk.leave(); }
414   };
415
416   class write_blocked {
417     zrwlock_t &rwlk;
418   public:
419     write_blocked(zrwlock_t &l) : rwlk(l) { rwlk.write_enter(); }
420     ~write_blocked() { rwlk.write_leave(); }
421   };
422
423 private:
424   enum {
425     db_magic_offset=0,
426     db_magic=0x00624474,   // tDb
427     idx_magic=0x00786469,  // idx
428     info_magic=0x6f666e69, // info
429     root_magic=0x746f6f72, // root
430     page_magic=0x6770,     // pg
431     entity_magic = 0x6d65, // em
432     root_info_offset=4,
433     root_info_extra_pages = 2,
434     idxNil=0, idxBin=1, idxStr=2,
435     ktyBin=0, ktyInd=1, ktyDir=2,
436     opDelete=-1, opFind=0, opInsert=1,
437     pg_unknown=0, pg_root_info=1, pg_free=2,
438     pg_entity=0x0100, pg_index=0x1000,
439     max_entity_type = pg_index-pg_entity-1,
440     max_index_type = 0x10000-pg_index-1,
441     min_heap_allocation = 32,
442     entityIdIdx = 0, entityNmIdx = 1,
443     freeStoreIdx = 2, addrStoreIdx = 3,
444     freeSpaceIdx = 4, addrSpaceIdx = 5,
445     usrIdx = 6,
446     fl_wr=1, fl_rd=2, fl_new=4, fl_free=8,
447     defaultNoShm = 1,
448     defaultStoreBlockSize = 8192,
449     defaultPageTableHunkSize = 8192,
450     defaultIndexTableHunkSize = 4096,
451     defaultBinaryBlockSize = 16384,
452     defaultStringBlockSize = 4096,
453     defaultEntityPageSize = 65536,
454   };
455
456   int key, fd;
457   int err_no;
458   errCallback err_callback;
459   int my_pid;
460   transId active_transaction;
461
462 #ifdef DEBUG
463   static int debug;
464   static const char *errMsgs[];
465   static void dmsg(int msk, const char *msg,...);
466   int _err_(int v,const char *fn,int ln);
467   int _fail_(int v,const char *fn,int ln);
468 #define err_(v) _err_(v,__func__,__LINE__)
469 #define fail_(v) _fail_(v,__func__,__LINE__)
470 #else
471   static void dmsg(int msk, const char *msg,...) {}
472   int _err_(int v) { error(v); return v; }
473   int _fail_(int v) { return v; }
474 #define err_(v) _err_(v)
475 #define fail_(v) _fail_(v)
476 #endif
477
478 #define Err(v) return err_(v)
479 #define Fail(v) return fail_(v)
480
481 #define if_ret(fn) do{ int _ret; \
482  if(unlikely((_ret=(fn))<0)) return _ret; \
483 }while(0)
484 #define if_err(fn) do{ int _ret; \
485  if(unlikely((_ret=(fn))<0)) Err(_ret); \
486 }while(0)
487 #define if_fail(fn) do{ int _ret; \
488  if(unlikely((_ret=(fn))<0)) Fail(_ret); \
489 }while(0)
490
491   class DbInfo {
492   public:
493     int magic;
494     int owner, last_owner;
495     int info_key, info_id;
496     int root_info_id;
497     int index_info_id;
498     int page_info_id;
499     zlock_t infoLk;   // lock dbinfo up to here
500     zrwlock_t dbRwLk; // global lock
501     zrwlock_t pgTblLk;// pageTable realloc
502     zlock_t pgAlLk;   // new page pagesUsed/pagesAllocated
503     zlock_t pgLdLk;   // pageLoad
504     zlock_t blkAlLk;  // blockAllocate/Free
505     zlock_t objAlLk;  // objectAllocate/Free
506     zrwlock_t rw_locks[max_entity_type];
507
508     DbInfo(int pid, int key, int id);
509   } *db_info;
510   int new_info(int key);
511   int get_info(int key);
512   int del_info();
513
514   int attach_wr();
515   int attach_rd();
516   int attach_rw(int zrw) { return zrw ? attach_wr() : attach_rd(); }
517   void detach_rw();
518
519   class Page;
520
521   class pagePrefix {
522   public:
523     unsigned short magic;
524     unsigned short type;
525     int used;
526   };
527
528   Page *get_Page(pageId pid) volatile { return pageTable[pid]; }
529   void set_Page(pageId pid, Page *pp) { pageTable[pid] = pp; }
530   //Page *get_page(pageId pid) { blocked by(pgTblk); return get_Page(pid); }
531   Page *get_page(pageId pid); // locked pageTable access
532
533   static pageId getPageId(unsigned char *&bp) {
534     int i = sizeof(pageId);  pageId id;
535     for( id = *bp++; --i > 0; id |= *bp++ ) id <<= 8;
536     return id;
537   }
538   static void putPageId(unsigned char *&bp, pageId id) {
539     int i = sizeof(pageId) * 8;
540     while( (i -= 8) >= 0 ) *bp++ = id >> i;
541   }
542   static pageId readPageId(char *cp) {
543     unsigned char *bp = (unsigned char *)cp;
544     return getPageId(bp);
545   }
546   static void writePageId(char *cp, pageId id) {
547     unsigned char *bp = (unsigned char *)cp;
548     putPageId(bp,id);
549   }
550
551   class keyBlock : public pagePrefix {
552     char rightLink[sizeof(pageId)];
553   public:
554     int right_link() { return readPageId(&rightLink[0]); }
555     void right_link(pageId id) { writePageId(&rightLink[0],id); }
556   };
557
558   static int defaultBlockSizes[];
559
560   class IndexTypeInfo {
561   public:
562     int magic;
563     short type;                    /* type of index */
564     short key_type;
565     char name[nmSz];               /* index string identifier */
566   };
567
568   class IndexBaseType : public IndexTypeInfo {
569   public:
570     IndexBaseType(int typ);
571   };
572
573   class IndexRecdInfo {
574   public:
575     int idx;                       /* index in db->indecies[] */
576     int keySz, dataSz;             /* sizeof key/data fields in bytes */
577     pageId rootPageId;             /* index root page ID */
578     pageId rightHandSide;          /* the right hand side of the tree for this index */
579     pageId freeBlocks;             /* free index page list */
580     unsigned int blockSize;        /* size of new index blocks */
581     int pad1;
582     long count;                    /* index population count */
583   };
584
585   class IndexBaseRecd : public IndexRecdInfo {
586   public:
587     IndexBaseRecd(int typ, int zidx, int ksz, int dsz);
588   };
589
590   class IndexBaseStorage;
591   class IndexBaseInfo : public IndexTypeInfo, public IndexRecdInfo {
592   public:
593     operator IndexBaseStorage *() { return (IndexBaseStorage *)this; }
594   };
595  
596   class IndexBaseStorage : public IndexBaseInfo { 
597   public:
598     IndexBaseStorage(int typ, int zidx, int ksz, int dsz);
599     IndexBaseStorage() {}
600     ~IndexBaseStorage() {}
601   };
602
603   class IndexBase {
604     IndexBaseStorage *st;
605     friend class Db;
606     Db *db;                        /* owner db */
607     zlock_t idxLk;
608     pgRef lastAccess, lastFind;    /* last operational access/find location */
609     pgRef lastInsert, lastDelete;  /* last operational insert/delete location */
610     pgRef lastNext;                /* last operational next location */
611     int kdSz;                      /* keySz + dataSz */
612     int lastOp;                    /* last operation, delete=-1/find=0/insert=1 */
613     int cInsCount;                 /* number of consecutive insertions */
614     int cFindCount;                /* number of consecutive finds */
615     int cDelCount;                 /* number of consecutive deletions */
616
617     void init(Db *zdb);
618     virtual int keyMap(pageId s, int(IndexBase::*fn)(pageId id)) = 0;
619     virtual int keyCopy(pageId s, IndexBase *ib) = 0;
620     int blockAllocate(pageId &pid, keyBlock *&bp);
621     int blockAllocate(pageId &pid, keyBlock *&bp, Page *&pp, char *&cp) {
622       pp = 0;  cp = 0;  if_err( blockAllocate(pid, bp) );
623       pp = db->get_page(pid);  cp = (char *)(bp + 1);
624       return 0;
625     }
626     int blockFree(pageId pid);
627     int blockRelease(pageId pid);
628     int blockLoad(pageId pid);
629     int deleteFreeBlocks();
630     void chkLastReset();
631     void chkLastInsert();
632     void chkLastDelete();
633     void chkLastFind(pgRef &last);
634   public:
635 #ifdef DEBUG
636     int _err_(int v,const char *fn,int ln) { return db->_err_(v,fn,ln); }
637     int _fail_(int v,const char *fn,int ln) { return db->_fail_(v,fn,ln); }
638 #else
639     int _err_(int v) { return db->_err_(v); }
640     int _fail_(int v) { return db->_fail_(v); }
641 #endif
642     virtual int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData) = 0;
643     virtual int Find(void *key,void *rtnData) = 0;
644     virtual int Insert(void *key,void *data) = 0;
645     virtual int Delete(void *key) = 0;
646     virtual int First(void *rtnKey,void *rtnData) = 0;
647     virtual int Last(void *rtnKey,void *rtnData) = 0;
648     virtual int Modify(void *key,void *recd) = 0;
649     virtual int Next(pgRef &loc,void *rtnKey,void *rtnData) = 0;
650     int First(pgRef &loc,void *rtnKey,void *rtnData) {
651       if_fail( First(rtnKey, rtnData) );
652       loc = lastNext;
653       return 0;
654     }
655     int Next(void *rtnKey,void *rtnData) {
656       if( lastNext.id < 0 ) Fail(errInvalid);
657       return Next(lastNext,rtnKey,rtnData);
658     }
659     long Count() { return st->count; }
660     int MakeRoot();
661     int UnmakeRoot();
662     int Clear();
663     int NextLoc(pgRef &loc) { loc = lastNext; return 0; }
664     IndexBase(Db *zdb, int typ, int zidx, int ksz, int dsz);
665     IndexBase(Db *zdb, IndexBaseStorage &d);
666     virtual ~IndexBase();
667   } **indecies;
668
669   int indeciesAllocated, indecies_sz;
670
671   class IndexBinaryStorage;
672   class IndexBinaryInfo {
673   public:
674     operator IndexBinaryStorage *() { return (IndexBinaryStorage *)this; }
675     int cmprId;
676   };
677
678   class IndexBinaryStorage : public IndexBinaryInfo {
679   public:
680     IndexBinaryStorage(int cmprId) { this->cmprId = cmprId; }
681     IndexBinaryStorage() {}
682     ~IndexBinaryStorage() {}
683   };
684
685   class IndexBinary : public IndexBase {
686     IndexBinaryStorage *bst;
687     friend class Db;
688     CmprFn compare;                /* the key compare function type */
689     char *akey;                    /* pointer to key argument */
690     int keyInterior;               /* last insert interior/exterior */
691     int idf;                       /* interior delete flag */
692     char *iky, *tky;               /* search/promoted temp key storage */
693
694     void init();
695     int keyMap(pageId s, int(IndexBase::*fn)(pageId id));
696     int keyCopy(pageId s, IndexBase *ib);
697     int keyBlockUnderflow(int &t,keyBlock *lbb,pageId p,keyBlock *pbb,int pi);
698     void makeKey(char *cp,char *key,int l,char *recd,int n);
699     void setLastKey(pageId s,pageId u,int k);
700     int keyLocate(pgRef &last,pageId s, int op,void *ky, CmprFn cmpr);
701     int chkNext(pgRef &loc, char *&kp);
702     int keyNext(pgRef &loc, char *kp);
703     int chkFind(pgRef &loc, char *key);
704     int keyFind(pgRef &loc,void *ky, pageId s);
705     int chkInsert(void *key,void *data);
706     int keyInsert(pageId s, pageId &t);
707     int chkDelete(pgRef &loc, void *kp);
708     int keyDelete(int &t,void *kp,pageId s,pageId p,keyBlock *pbb,int pi);
709     int keyFirst(pgRef &loc, pageId s);
710     int keyLast(pgRef &loc, pageId s);
711
712     int refLocate(pgRef &loc, int op,void *key, CmprFn cmpr);
713     int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData);
714     int refFind(pgRef &loc, void *key);
715     int Find(void *key,void *rtnData);
716     int Insert(void *key,void *data);
717     int Delete(void *key);
718     int First(void *rtnKey,void *rtnData);
719     int Last(void *rtnKey,void *rtnData);
720     int Modify(void *key,void *recd);
721     int Next(pgRef &loc,void *rtnKey,void *rtnData);
722     int Next(void *rtnKey,void *rtnData) {
723       return IndexBase::Next(rtnKey,rtnData);
724     }
725     void wr_key(void *kp, char *bp, int sz) {
726       switch( st->key_type ) {
727       case ktyBin: memcpy(bp,kp,sz); break;
728       case ktyDir:
729       case ktyInd: ((Key *)kp)->wr_key(bp); break;
730       }
731     }
732     char *ikey() { return iky; }
733     char *tkey() { return tky; }
734   public:
735     IndexBinary(Db *zdb, int zidx, int ksz, int dsz, CmprFn cmpr);
736     IndexBinary(Db *zdb, IndexBaseStorage *b, IndexBinaryStorage *d);
737     IndexBinary(IndexBase *ib, IndexBaseStorage *b, IndexBinaryStorage *d);
738     ~IndexBinary();
739   };
740   friend class IndexBinary;
741
742   class IndexStringStorage;
743   class IndexStringInfo {
744     char dummy; // compiler needs this for some reason
745   public:
746     operator IndexStringStorage *() { return (IndexStringStorage *)this; }
747   };
748
749   class IndexStringStorage : public IndexStringInfo {
750   public:
751     IndexStringStorage() {}
752     ~IndexStringStorage() {}
753   };
754
755   class IndexString : public IndexBase {
756     IndexStringStorage *sst;
757     friend class Db;
758     static int ustrcmp(unsigned char *a, unsigned char *b) {
759       return strncmp((char *)a,(char *)b,keysz);
760     }
761     static void ustrcpy(unsigned char *a, unsigned char *b) {
762       strncpy((char *)a,(char *)b,keysz);
763     }
764     static void umemmove(unsigned char *&a, unsigned char *b, int n) {
765       memmove(a,b,n);  a += n;
766     }
767     static int kpress(unsigned char *kp, unsigned char *lp, unsigned char *cp);
768     int split(int n, int i, pageId s, pageId &l, pageId r);
769     void init();
770     int keyMap(pageId s, int(IndexBase::*fn)(pageId id));
771     int keyCopy(pageId s, IndexBase *ib);
772     int chkInsert(void *key,void *data);
773     int keyInsert(pageId &t, pageId s);
774     int keyFirst(pageId s);
775     int keyLast(pageId s);
776     int keyLocate(pgRef &last,pageId s,int &t, int op,
777         unsigned char *ky,CmprFn cmpr, unsigned char *rky);
778     int chkFind(pgRef &loc, char *key, unsigned char *lkey, unsigned char *lky=0);
779     int keyFind(pgRef &loc, unsigned char *ky);
780     int keyNext(pgRef &loc, unsigned char *rky);
781     int keyUnderflow(pageId s, pageId &t, int k);
782     int keyOverflow(pageId s, pageId &t, int k, int o);
783     int keyRemap(pageId s, pageId &t, int k, int o);
784     int keyDelete(pageId s, pageId &t);
785
786     unsigned char lastAccKey[keysz], lastFndKey[keysz];
787     unsigned char lastInsKey[keysz], lastDelKey[keysz];
788     unsigned char lastNxtKey[keysz];
789     unsigned char *tky, *dky;   // dataSz+keysz+1
790     unsigned char *tbfr;        // 3*allocated
791     unsigned char akey[keysz];  // key in use
792     int idf;                    /* interior delete flag */
793
794     int refLocate(pgRef &loc, int op, void *key, CmprFn cmpr, unsigned char *rkey);
795     int Locate(int op,void *key,CmprFn cmpr,void *rtnKey,void *rtnData);
796     int refFind(pgRef &loc, void *key);
797     int Find(void *key,void *rtnData);
798     int Insert(void *key,void *data);
799     int Delete(void *key);
800     int First(void *rtnKey,void *rtnData);
801     int Last(void *rtnKey,void *rtnData);
802     int Modify(void *key,void *recd);
803     int Next(pgRef &loc,void *rtnKey,void *rtnData);
804     int Next(void *rtnKey,void *rtnData) {
805       return IndexBase::Next(rtnKey,rtnData);
806     }
807
808   public:
809     IndexString(Db *zdb, int zidx, int dsz);
810     IndexString(Db *zdb, IndexBaseStorage *b, IndexStringStorage *d);
811     IndexString(IndexBase *ib, IndexBaseStorage *b, IndexStringStorage *d);
812     ~IndexString();
813   };
814   friend class IndexString;
815
816   class IndexBinaryData : public IndexBaseInfo, public IndexBinaryInfo {};
817   class IndexStringData : public IndexBaseInfo, public IndexStringInfo {};
818
819   typedef union {
820     IndexBaseInfo base;
821     IndexBinaryData bin;
822     IndexStringData str;
823   } IndexInfo;
824   IndexInfo *index_info;        /* image for index storage */
825
826   class allocPrefix {
827   public:
828     unsigned short magic;
829     unsigned short type;
830     int size;
831   };
832
833   class freeStoreRecord {
834   public:
835     long size;
836     ioAddr io_addr;
837   };
838
839   class addrStoreRecord {
840   public:
841     ioAddr io_addr;
842     long size;
843   };
844
845   class freeSpaceRecord {
846   public:
847     long size;
848     pageId id;
849     int offset;
850   };
851
852   class addrSpaceRecord {
853   public:
854     pageId id;
855     int offset;
856     long size;
857   };
858
859   class AllocCache {
860     pgRef loc;
861     int avail;
862     friend class Db;
863   public:
864     int cacheFlush(Db *db);
865     int Get(Db *db,int &size, pgRef &ref);
866     int Load(Db *db, pageId id, int ofs, int sz);
867     void init() { loc.id = NIL; loc.offset = 0; avail = 0; }
868     void init(pageId id, int ofs, int sz) {
869       loc.id = id; loc.offset = ofs; avail = sz;
870     }
871     void dmp() {
872       printf("loc: %d/%d  avl: %d\n", loc.id,loc.offset,avail);
873     }
874     int freeIdx, addrIdx;
875     int init_idx(Db *db, const char *nm);
876   } alloc_cache;
877
878   int cacheFlush() { return alloc_cache.cacheFlush(this); }
879   void cacheDelete(AllocCache &cache);
880   int cache_all_flush();
881
882   class PageStorage {
883   public:
884     unsigned int used;
885     unsigned int allocated;
886     unsigned short flags;
887     unsigned short type;
888     int io_allocated;
889     int wr_allocated;
890     int shmid;
891     pageId link;
892     transId trans_id;
893     ioAddr io_addr;
894     ioAddr wr_io_addr;
895
896     void init();
897     PageStorage() { init(); }
898     ~PageStorage() {}
899     int chk_flags(int fl) { return flags & fl; }
900     int set_flags(int fl) { return flags |= fl; }
901     int clr_flags(int fl) { return flags &= ~fl; }
902   } *page_info;
903
904   class Page {
905     zlock_t pgLk;
906     PageStorage *st;
907     pagePrefix *addr;
908     int shm_id;
909     void init();
910   public:
911     // PageStorage access
912     int iused() { return st->used-sizeof(keyBlock); }
913     void iused(int v) { st->used = v+sizeof(keyBlock); }
914     int iallocated() { return st->allocated-sizeof(keyBlock); }
915     void iallocated(int v) { st->allocated = v+sizeof(keyBlock); }
916     PageStorage *operator ->() { return st; }
917     int release();
918     void reset_to(Page *pp);
919     Page(PageStorage &d) { st = &d; init(); }
920     ~Page() {}
921     friend class Db;
922   } **pageTable;
923   int pageTableAllocated, page_table_sz;
924
925   int entityPageSize;
926   int storeBlockSize;
927   int pageTableHunkSize;
928   int indexTableHunkSize;
929
930   class undoData {
931   public:
932     class cfnData {
933       public:
934       int cmprId;
935       CmprFn compare;
936     } *cfn;
937     int cfnAllocated, cfnUsed;
938     undoData() : cfn(0), cfnAllocated(0), cfnUsed(0) {}
939     ~undoData() { delete [] cfn; cfnAllocated = cfnUsed = 0; }
940     int save(Db *db);
941     int restore(Db *db);
942   } undata;
943
944   ioAddr file_position;
945
946   char *bfr, *lmt, *inp;
947   int open_bfr();
948   int close_bfr();
949   int flush_bfr();
950   int write_bfr(char *dp, int sz);
951
952 public:
953 #ifdef ZMEDIA
954
955   // count of on bits
956   inline static unsigned int on_bits(unsigned int n) {
957     n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
958     n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
959     n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
960     n += n >> 8;  n += n >> 16;  //ok, fldsz > 5 bits
961     return n & 0x1f;
962   }
963
964   // lowest on bit
965   inline static unsigned int low_bit(unsigned int n) {
966     return n & ~(n-1);
967   }
968
969   // bit number of lowest on bit
970   inline static unsigned int low_bit_no(unsigned int n) {
971     return on_bits(low_bit(n) - 1);
972   }
973
974   // highest on bit, and all lower bits set
975   inline static unsigned int high_bit_mask(unsigned int n) {
976     n |= n >> 1;   n |= n >> 2;
977     n |= n >> 4;   n |= n >> 8;
978     n |= n >> 16;
979     return n;
980   }
981
982   // highest on bit
983   inline static unsigned int high_bit(unsigned int n) {
984     unsigned m = high_bit_mask(n);
985     return m & ~(m>>1);
986   }
987
988   // bit number of highest on bit
989   inline static unsigned int high_bit_no(unsigned int n) {
990     return on_bits(high_bit_mask(n)) - 1;
991   }
992
993   class pack {
994     static inline int cpu_aligned() {
995       unsigned long flags;
996       asm volatile( "pushf\n" "pop %0\n" : "=rm" (flags) );
997       return (flags>>18) & 1;
998     }
999     static int aligned;
1000     int idx;
1001     uint8_t *bits;
1002     uint64_t vmx;
1003     uint64_t clip(int64_t v) { return v<0 ? 0 : (uint64_t)v>vmx ? vmx : v; }
1004   public:
1005     enum { alignBits = 8, };
1006
1007     static void init(int v=-1) { aligned = v >= 0 ? v : cpu_aligned(); }
1008     void put(uint64_t v, int n);
1009     void putc(uint64_t v, int n) { put(clip(v), n); }
1010     void iput(int v) { put(v, 8*sizeof(int)); }
1011     void lput(int64_t v) { put(v, 8*sizeof(int64_t)); }
1012     uint64_t get(int n);
1013     int iget() { return get(8*sizeof(int)); }
1014     int64_t lget() { return get(8*sizeof(int64_t)); }
1015     int pos() { return idx; }
1016     void seek(int i) { idx = i; }
1017     void init(uint8_t *bp) { bits = bp; idx = 0; vmx = 0; }
1018     uint8_t *bfr() { return this->bits; }
1019     void align() { idx = (idx+alignBits-1) & ~(alignBits-1); }
1020     void *addr() { return &bits[idx/8]; }
1021     void set_max(uint64_t v) { vmx = v; }
1022
1023     pack() : bits(0) { idx = 0; }
1024     pack(uint8_t *bp) { init(bp); }
1025     ~pack() {}
1026   };
1027
1028   class mediaKey {
1029     int w, len;
1030     int64_t cnt;
1031     uint8_t *bp;
1032
1033   public:
1034     static int64_t bit_size(int len, int w);
1035     static int64_t byte_size(int len, int w);
1036     static void build(uint8_t *kp, uint8_t *bp, int w, int len) {
1037       mediaKey key(kp, bp, w, len);
1038     }
1039     static int64_t count(void *kp) {
1040       mediaKey *mkp = (mediaKey *)kp;
1041       return be64toh(mkp->cnt);
1042     }
1043     static int64_t set_count(void *kp, int64_t v) {
1044       mediaKey *mkp = (mediaKey *)kp;
1045       return mkp->cnt = htobe64(v);
1046     }
1047     static int64_t incr_count(void *kp, int64_t dv) {
1048       return set_count(kp, count(kp) + dv);
1049     }
1050     static int64_t count1(uint8_t *kp);
1051     mediaKey(uint8_t *kp, uint8_t *bp, int w, int len);
1052     ~mediaKey();
1053   };
1054
1055   class mediaLoad {
1056     pack pb, pk;
1057     int w, len, dsz, psz, spos;
1058     int64_t cnt, *dat, **dp;
1059     void get_fields(int n, int k);
1060     int dsize(int n) { int m = (n+1)/2; return m>1 ? m+dsize(m) : 1; }
1061
1062   public:
1063     void load(uint8_t *kp);
1064
1065     mediaLoad(uint8_t *bp);
1066     ~mediaLoad();
1067   };
1068
1069   class mediaCmpr {
1070     pack pb, pk;
1071     int w, len, dsz, psz, spos;
1072     int64_t acnt, bcnt, *adat, *bdat, **adp, **bdp;
1073     uint64_t err, lmt;
1074     uint64_t sqr(int64_t v) { return v*v; }
1075     int dsize(int n) { int m = (n+1)/2; return m>1 ? m+dsize(m) : 1; }
1076     uint64_t chk_fields(int m, int k);
1077     int cmpr_fields(int m, int k);
1078
1079   public:
1080     uint64_t chk(uint8_t *kp, uint64_t lmt=~0);
1081     int cmpr(uint8_t *kp, uint64_t lmt=~0);
1082
1083     mediaCmpr(uint8_t *bp);
1084     ~mediaCmpr();
1085   };
1086 #endif
1087
1088   class Entity;
1089   class ObjectLoc;
1090   typedef IndexBase *Index;
1091   int new_entity(Entity &entity, const char *nm, int sz);
1092   int get_entity(Entity &entity, const char *nm);
1093   int del_entity(Entity &entity);
1094
1095   class Obj {                    /* per object storage base class */
1096   public:
1097     int id;
1098   };
1099
1100   class varObj {
1101   public:
1102     int len;  pgRef loc;
1103     int size() { return len; }
1104     void init() { len = -1;  loc.id = NIL;  loc.offset = 0; }
1105     void del(Entity *entity) { len = -1;  entity->deallocate(loc); }
1106   };
1107   typedef varObj Obj::*vRef;
1108
1109   class ObjectLoc {
1110   public:
1111     Entity *entity;
1112     pgRef obj;
1113     Obj *addr(pgRef &loc) { 
1114       char *op = 0;
1115       return loc.id < 0 || entity->db->addrRead(loc,op) ? 0 : (Obj *)op;
1116     }
1117     Obj *addr_wr(pgRef &loc) { 
1118       char *op = 0;
1119       return loc.id < 0 || entity->db->addrWrite(loc,op) ? 0 : (Obj *)op;
1120     }
1121     void _wr() { Page &pg = *entity->db->get_page(obj.id); pg->set_flags(fl_wr); }
1122     Obj *addr() { return addr(obj); }
1123     Obj *addr_wr() { return addr_wr(obj); }
1124     void *addr(varObj &vobj) { return addr(vobj.loc); }
1125     void *addr_wr(varObj &vobj) { return addr_wr(vobj.loc); }
1126     Obj *operator ->() { return (Obj *)addr(); }
1127     ObjectLoc(Entity *ep) : entity(ep) { obj.id = NIL;  obj.offset = 0; }
1128     ~ObjectLoc() {}
1129
1130     virtual int allocate(int sz=0) { return entity->allocate(*this,sz); }
1131     virtual int construct() { return entity->construct(*this); }
1132     virtual int destruct() { return entity->destruct(*this); }
1133     virtual int deallocate() { return entity->deallocate(*this); }
1134     virtual int insertCascade() { return 0; }
1135     virtual int insertProhibit() { return 0; }
1136     virtual int deleteCascade() { return 0; }
1137     virtual int deleteProhibit() { return 0; }
1138     virtual int modifyCascade() { return 0; }
1139     virtual int modifyProhibit() { return 0; }
1140     virtual int copy(ObjectLoc &dobj);
1141     int id() { ObjectLoc &oloc = *this; return oloc->id; }
1142     const int *_id() { ObjectLoc &oloc = *this; return &oloc->id; }
1143     int _id_size() { return sizeof(int); }
1144     int size(varObj &vobj) { return vobj.len; }
1145     int size(varObj &vobj, int sz);
1146     Index index(int i) { return entity->index(i); }
1147     void v_init();
1148     void v_del();
1149
1150     int FindId(int id) { return index(idxId)->Find(&id,&obj); }
1151     int LocateId(int op, int id) { return index(idxId)->Locate(op,&id,0,0,&obj); }
1152     int FirstId() { return index(idxId)->First(0,&obj); }
1153     int LastId() { return index(idxId)->Last(0,&obj); }
1154     int NextId() { return index(idxId)->Next(0,&obj); }
1155     int FirstId(pgRef &loc) { return index(idxId)->First(loc,0,&obj); }
1156     int NextId(pgRef &loc) { return index(idxId)->Next(loc,0,&obj); }
1157     int NextLocId(pgRef &loc) { return index(idxId)->NextLoc(loc); }
1158
1159     static int cmpr_char(const char *ap, int asz, const char *bp, int bsz);
1160     static int cmpr_uchar(const unsigned char *ap, int asz, const unsigned char *bp, int bsz);
1161     static int cmpr_short(const short *ap, int asz, const short *bp, int bsz);
1162     static int cmpr_ushort(const unsigned short *ap, int asz, const unsigned short *bp, int bsz);
1163     static int cmpr_int(const int *ap, int asz, const int *bp, int bsz);
1164     static int cmpr_uint(const unsigned int *ap, int asz, const unsigned int *bp, int bsz);
1165     static int cmpr_long(const long *ap, int asz, const long *bp, int bsz);
1166     static int cmpr_ulong(const unsigned long *ap, int asz, const unsigned long *bp, int bsz);
1167     static int cmpr_float(const float *ap, int asz, const float *bp, int bsz);
1168     static int cmpr_double(const double *ap, int asz, const double *bp, int bsz);
1169 #ifdef ZMEDIA
1170     static int cmpr_media(const unsigned char *ap, int asz, const unsigned char *bp, int bsz);
1171 #endif
1172
1173 #ifdef DEBUG
1174     int _err_(int v,const char *fn,int ln) { return entity->db->_err_(v,fn,ln); }
1175     int _fail_(int v,const char *fn,int ln) { return entity->db->_fail_(v,fn,ln); }
1176 #else
1177     int _err_(int v) { return entity->db->_err_(v); }
1178     int _fail_(int v) { return entity->db->_fail_(v); }
1179 #endif
1180
1181     int last(Index idx,ObjectLoc &last_loc);
1182     int last(const char *nm,int (ObjectLoc::*ip)());
1183     unsigned int last(const char *nm,unsigned int (ObjectLoc::*ip)());
1184   };
1185
1186   class Key {
1187   public:
1188     ObjectLoc &loc;
1189     Index idx;
1190     CmprFn cmpr;
1191     virtual int wr_key(char *cp) = 0;
1192     Key(Index i, ObjectLoc &l, CmprFn c) : loc(l), idx(i), cmpr(c) {}
1193     Key(const char *nm, ObjectLoc &l, CmprFn c) : loc(l), cmpr(c) {
1194       idx = loc.entity->index(nm);
1195     }
1196     operator void *() { return (void *)this; }
1197 #ifdef DEBUG
1198     int _err_(int v,const char *fn,int ln) { return loc._err_(v,fn,ln); }
1199     int _fail_(int v,const char *fn,int ln) { return loc._fail_(v,fn,ln); }
1200 #else
1201     int _err_(int v) { return loc._err_(v); }
1202     int _fail_(int v) { return loc._fail_(v); }
1203 #endif
1204   };
1205
1206   class rKey : public Key {
1207   public:
1208     rKey(Index i, ObjectLoc &l, CmprFn c) : Key(i,l,c) {}
1209     rKey(const char *nm, ObjectLoc &l, CmprFn c) : Key(nm,l,c) {}
1210     virtual int wr_key(char *cp=0) { return -1; }
1211     int NextLoc(pgRef &pos) { return idx->NextLoc(pos); }
1212     int First();  int First(pgRef &pos);
1213     int Next();   int Next(pgRef &pos);
1214     int Last();
1215     int Locate(int op=keyGE);
1216   };
1217
1218   class iKey : protected rKey {
1219   public:
1220     iKey(Index i, ObjectLoc &l, CmprFn c) : rKey(i,l,c) {}
1221     iKey(const char *nm, ObjectLoc &l, CmprFn c) : rKey(nm,l,c) {}
1222     int NextLoc(pgRef &pos) { return idx->NextLoc(pos); }
1223     int Find();
1224     int Locate(int op=keyGE);
1225   };
1226
1227 private:
1228   class EntityObj : public Obj { /* entity storage */
1229   public:
1230     char name[nmSz];             /* string identifier */
1231     AllocCache alloc_cache;      /* entity allocator cache */
1232     int maxId;                   /* highest ID value */
1233     int recdSz;                  /* record size in bytes */
1234     int count;                   /* number of records */
1235     int nidxs;                   /* index count */
1236     int indexs[1];               /* id/loc index */
1237     EntityObj(EntityObj &eobj, int eid);
1238   };
1239
1240   class EntityLoc : public ObjectLoc {
1241   public:
1242     EntityObj *operator ->() { return (EntityObj *)addr(); }
1243     EntityLoc(Entity *ep) : ObjectLoc(ep) {}
1244     ~EntityLoc() {}
1245     int cacheFlush() {
1246       EntityLoc &eloc = *this;  _wr();
1247       return eloc->alloc_cache.cacheFlush(entity->db);
1248     }
1249   };
1250
1251   class varObjRef;
1252   typedef varObjRef *varObjs;
1253   class varObjRef {
1254   public:
1255     varObjs next;
1256     vRef ref;
1257     varObjRef(varObjs &lp, vRef rp) : next(lp), ref(rp) {}
1258   };
1259    
1260   static int ioCmpr(const void *a, const void *b, void *c);
1261 public:
1262
1263   class Entity {
1264   public:
1265     Db *const db;
1266     EntityLoc ent;
1267     varObjs vobjs;
1268     zrwlock_t *rw_lock;
1269     operator zrwlock_t&() { return *rw_lock; }
1270
1271 #ifdef DEBUG
1272     int _err_(int v,const char *fn,int ln) { return db->_err_(v,fn,ln); }
1273     int _fail_(int v,const char *fn,int ln) { return db->_fail_(v,fn,ln); }
1274 #else
1275     int _err_(int v) { return db->_err_(v); }
1276     int _fail_(int v) { return db->_fail_(v); }
1277 #endif
1278     Entity(Db *const db) : db(db), ent(this), vobjs(0) {}
1279     ~Entity() {}
1280
1281     int allocate(ObjectLoc &loc,int sz=0);
1282     int construct_(ObjectLoc &loc, int id);
1283     int construct(ObjectLoc &loc) { return construct_(loc,ent->maxId); }
1284     int destruct_(ObjectLoc &loc, int id);
1285     int destruct(ObjectLoc &loc) { return destruct_(loc, loc->id); }
1286     int deallocate(pgRef &obj) { return db->deallocate(obj,ent->alloc_cache); }
1287     int deallocate(ObjectLoc &loc) { return deallocate(loc.obj); }
1288     int get_index(const char *nm, CmprFn cmpr=0);
1289     Index index(int i) { return db->indecies[ent->indexs[i]]; }
1290     Index index(const char *nm) {
1291       int idx = get_index(nm);
1292       return idx >= 0 ? index(idx) : 0;
1293     }
1294     int MaxId() { return ent->maxId; }
1295     int Count() { return ent->count; }
1296     int add_index(int idx, int kty=ktyBin);
1297     int add_bindex(const char *nm,int keySz,int dataSz) {
1298       int idx = db->new_binary_index(nm,keySz,dataSz);
1299       if_err( idx );  if_err( add_index(idx,ktyBin) );
1300       return idx;
1301     }
1302     int add_ind_index(const char *nm) {
1303       int idx = db->new_binary_index(nm,0,sizeof(int),Db::cmprKey);
1304       if_err( idx );  if_err( add_index(idx,ktyInd) );
1305       return idx;
1306     }
1307     int add_dir_index(const char *nm,int keySz) {
1308       int idx = db->new_binary_index(nm,keySz,sizeof(int),Db::cmprKey);
1309       if_err( idx );  if_err( add_index(idx,ktyDir) );
1310       return idx;
1311     }
1312     int add_str_index(const char *nm,int dataSz) {
1313       int idx = db->new_string_index(nm, dataSz);
1314       if_err( idx );  if_err( add_index(idx,ktyDir) );
1315       return idx;
1316     }
1317     int del_index_(int idx);
1318     int del_index(int idx);
1319     int del_index(const char *nm);
1320     int new_entity(const char *nm, int sz) { return db->new_entity(*this,nm,sz); }
1321     int get_entity(const char *nm) { return db->get_entity(*this,nm); }
1322     int del_entity() { return db->del_entity(*this); }
1323     void add_vref(vRef rp) { vobjs = new varObjRef(vobjs,rp); }
1324   };
1325
1326   class ObjectList;
1327   typedef ObjectList *Objects;
1328   static void finit(Objects objects);
1329
1330   class ObjectList {
1331   public:
1332     Objects next;
1333     ObjectLoc *obj;
1334     ObjectList(Objects op, ObjectLoc &o) : next(op), obj(&o) {}
1335   };
1336
1337 private:
1338   int new_entity_(Entity &entity, const char *nm, int sz);
1339
1340   int findCmprFn(CmprFn fn);
1341   int pageLoad(pageId id, Page &pg);
1342   int addrRead_(pgRef &loc, char *&vp, int mpsz=0) {
1343     Page &pg = *get_page(loc.id);  vp = 0;
1344     if( unlikely( !pg.addr || pg->chk_flags(fl_rd) ) ) {
1345       if_err( pageLoad(loc.id, pg) );
1346     }
1347     vp = (char *)pg.addr+loc.offset+mpsz;
1348     return 0;
1349   }
1350   int addrRead_(pgRef &loc, keyBlock *&vp, int mpsz=0) {
1351     return addrRead_(loc,*(char**)&vp, mpsz);
1352   }
1353   int addrRead_(pgRef &loc, allocPrefix *&vp, int mpsz=0) {
1354     return addrRead_(loc,*(char**)&vp, mpsz);
1355   }
1356   int addrRead_(pgRef &loc, pagePrefix *&vp, int mpsz=0) {
1357     return addrRead_(loc,*(char**)&vp, mpsz);
1358   }
1359   int addrWrite_(pgRef &loc, char *&vp, int mpsz=0) {
1360     Page &pg = *get_page(loc.id);  vp = 0;
1361     if( unlikely( !pg.addr || pg->chk_flags(fl_rd) ) ) {
1362       if_err( pageLoad(loc.id, pg) );
1363     }
1364     pg->set_flags(fl_wr);
1365     vp = (char *)pg.addr+loc.offset+mpsz;
1366     return 0;
1367   }
1368   int addrWrite_(pgRef &loc, keyBlock *&vp, int mpsz=0) {
1369     return addrWrite_(loc,*(char**)&vp, mpsz);
1370   }
1371   int addrWrite_(pgRef &loc, allocPrefix *&vp, int mpsz=0) {
1372     return addrWrite_(loc,*(char**)&vp, mpsz);
1373   }
1374   int addrWrite_(pgRef &loc, pagePrefix *&vp, int mpsz=0) {
1375     return addrWrite_(loc,*(char**)&vp, mpsz);
1376   }
1377   int addrRead(pgRef &loc, char *&vp) {
1378     return addrRead_(loc, vp, sizeof(allocPrefix));
1379   }
1380   int addrWrite(pgRef &loc, char *&vp) {
1381     return addrWrite_(loc, vp, sizeof(allocPrefix));
1382   }
1383
1384   int objectHeapInsert(int sz,int pg,int off,AllocCache &cache);
1385   int objectHeapDelete(int sz,int pg,int off,AllocCache &cache);
1386   int objectAllocate(int typ, int &size, pgRef &loc,AllocCache &cache);
1387   int objectFree(pgRef &loc,AllocCache &cache);
1388   int pgRefGet(int &size, pgRef &loc,AllocCache &cache);
1389   int pgRefNew(int &size, pgRef &lo,AllocCache &cache);
1390   int pgRefAllocate(int &size, pgRef &lo,AllocCache &cache);
1391
1392   int storeInsert(long size, ioAddr io_addr);
1393   int storeDelete(long size, ioAddr io_addr);
1394   int storeGet(int &size, ioAddr &io_addr);
1395   int storeNew(int &size, ioAddr &io_addr);
1396   int storeAllocate(int &size, ioAddr &io_addr);
1397   int storeFree(int size, ioAddr io_addr);
1398
1399   int icommit(int force);
1400   int iundo();
1401   int iclose();
1402   int ireopen();
1403   int iattach();
1404   int iopen(int undo_save=1);
1405
1406 protected:
1407
1408   pageId new_page();
1409   void del_page(int id);
1410   int alloc_pageTable(int sz);
1411   void free_page_(int pid);
1412   void free_page(int pid) { locked by(db_info->pgAlLk); free_page_(pid); }
1413   pageId lower_page(int mid);
1414   int alloc_indecies(int n);
1415   int new_index();
1416   void del_index(int idx);
1417   int new_index(IndexBase *&ibp, IndexBaseInfo *b, IndexBinaryInfo *d);
1418   int new_index(IndexBase *&ibp, IndexBaseInfo *b, IndexStringInfo *d);
1419   int indexRead(pageId pid, int df, keyBlock *&bp) {
1420     pgRef pg;  pg.id = pid;  pg.offset = 0;
1421     return !df ? addrRead_(pg,*(char**)&bp) : addrWrite_(pg,*(char**)&bp);
1422   }
1423   int indexRead(pageId pid,int df,keyBlock *&bp, Page *&pp, char *&cp) {
1424     pp = 0;  cp = 0;  if_err( indexRead(pid, df, bp) );
1425     pp = get_page(pid);  cp = (char *)(bp + 1);
1426     return 0;
1427   }
1428   void pageDealloc(Page &pg, int mode=1);
1429   int pageRead(ioAddr io_adr, uint8_t *bp, int len);
1430   int pageWrite(Page &pg);
1431   int seek_data(ioAddr io_addr);
1432   int size_data(char *dp, int sz);
1433   int read_data(char *dp, int sz);
1434   int write_data(char *dp, int sz);
1435   int write_zeros(ioAddr io_addr);
1436   int write_padding(ioAddr io_addr);
1437   int readRootInfo(int(Db::*fn)(char *dp,int sz));
1438   int writeRootInfo(int(Db::*fn)(char *dp,int sz));
1439   ioAddr storeBlocks(ioAddr sz) { return (sz+storeBlockSize-1)/storeBlockSize; }
1440   ioAddr entityPages(ioAddr sz) { return (sz+entityPageSize-1)/entityPageSize; }
1441   int indeciesHunks(int sz) { return (sz+indexTableHunkSize-1)/indexTableHunkSize; }
1442   int pageTableHunks(int sz) { return (sz+pageTableHunkSize-1)/pageTableHunkSize; }
1443   int pagePrefixHunks(int sz) { return (sz+sizeof(pagePrefix)-1)/sizeof(pagePrefix); }
1444   int init_idx();
1445   void init_shm();
1446   void init();
1447   void deinit();
1448   void reset();
1449   int start_transaction(int undo_save=1);
1450   void enter() { db_info->dbRwLk.enter(); }
1451   void leave() { db_info->dbRwLk.leave(); }
1452   void write_enter() { db_info->dbRwLk.write_enter(); }
1453   void write_leave() { db_info->dbRwLk.write_leave(); }
1454
1455 public:
1456   // 1:wr, 0:rd, -1:unlocked
1457   int is_locked() { return db_info->dbRwLk.locked(); }
1458   int is_blocked() { return db_info->dbRwLk.blocked(); }
1459
1460   int make(int zfd);
1461   int open(int zfd, int zkey=-1);
1462   int close();
1463
1464   int attach(int zrw, int zfd, int zkey);
1465   int attach(int zrw=0) { return attach(fd, key, zrw); }
1466   int detach();
1467
1468   int copy(Db *db, Objects objs);
1469   int new_binary_index(const char *nm, int ksz, int dsz, CmprFn cmpr=0);
1470   int new_string_index(const char *nm, int dsz);
1471   int get_index(const char *nm, CmprFn cmpr=0);
1472   long get_count(int r);
1473   int ins   (int r, void *key, void *data);
1474   int del   (int r, void *key);
1475   int find  (int r, void *key, void *rtnData=0);
1476   int locate(int r, int op, void *key, CmprFn cmpr, void *rtnKey, void *rtnData=0);
1477   int locate(int r, int op, void *key, void *rtnKey, void *rtnData=0) {
1478     return locate(r,op,key,0,rtnKey,rtnData);
1479   }
1480   int first (int r, void *key, void *rtnData=0);
1481   int last  (int r, void *key, void *rtnData=0);
1482   int next  (int r, void *key, void *rtnData=0);
1483   int nextloc(int r, pgRef &loc);
1484   int allocate(int typ, int size, pgRef &loc, AllocCache &cache);
1485   int reallocate(int size, pgRef &loc, AllocCache &cache);
1486   int deallocate(pgRef &loc, AllocCache &cache);
1487   int commit(int force=0);
1488   int flush ();
1489   int undo  ();
1490
1491   int transaction() { return !root_info ? -1 : root_info->transaction_id; }
1492   int64_t filesize() { return !root_info ? -1 : root_info->file_size; }
1493   int opened() { return fd>=0 ? 1 : 0; }
1494   void use_shm(int v) { no_shm = v ? 0 : 1; }
1495   int error() { return err_no; }
1496   void error(int v);
1497   void Error(int v,const char *msg);
1498   int load();
1499   int load_indecies();
1500
1501   Db();
1502   ~Db();
1503
1504 #ifdef DEBUG
1505   void dmp();
1506   void tdmp();
1507   void pdmp();
1508   void fdmp();
1509   void admp(); void achk(); void fchk();
1510   void edmp(AllocCache &cache);
1511   void bdmp(AllocCache &cache);
1512   void cdmp();
1513   void stats();
1514 #endif
1515
1516 };
1517
1518 #endif
1519 #endif // linux
1520 #endif /* x86 */