00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __DATABASE_H__
00012 #define __DATABASE_H__
00013
00014 #include "class.h"
00015 #include "reference.h"
00016 #include "file.h"
00017 #include "pagepool.h"
00018
00019 BEGIN_GIGABASE_NAMESPACE
00020
00021 #ifdef _WINCE
00022
00025 const size_t dbDefaultInitIndexSize = 10*1024;
00026
00030 const size_t dbDefaultExtensionQuantum = 1*512*1024;
00031 #else
00032
00035 const size_t dbDefaultInitIndexSize = 512*1024;
00036
00040 const size_t dbDefaultExtensionQuantum = 4*1024*1024;
00041 #endif
00042
00046 const unsigned dbMaxParallelSearchThreads = 64;
00047
00051 enum dbHandleFlags {
00052 dbPageObjectFlag = 0x1,
00053 dbModifiedFlag = 0x2,
00054 dbFreeHandleFlag = 0x4,
00055 dbFlagsMask = 0x7,
00056 dbFlagsBits = 3
00057 };
00058
00059 const size_t dbAllocationQuantumBits = 6;
00060 const size_t dbAllocationQuantum = 1 << dbAllocationQuantumBits;
00061 const size_t dbPageBits = 13;
00062 const size_t dbPageSize = 1 << dbPageBits;
00063 const size_t dbIdsPerPage = dbPageSize / sizeof(oid_t);
00064 const size_t dbHandlesPerPage = dbPageSize / sizeof(offs_t);
00065 const size_t dbHandleBits = 1 + sizeof(offs_t)/4;
00066 const size_t dbBitmapSegmentBits = dbPageBits + 3 + dbAllocationQuantumBits;
00067 const size_t dbBitmapSegmentSize = 1 << dbBitmapSegmentBits;
00068 const size_t dbBitmapPages = 1 << (dbDatabaseOffsetBits-dbBitmapSegmentBits);
00069 const size_t dbDirtyPageBitmapSize = 1 << (dbDatabaseOidBits-dbPageBits+dbHandleBits-3);
00070 const size_t dbDefaultSelectionLimit = 2000000000;
00075 const int dbBMsearchThreshold = 512;
00079 const size_t dbIndexedMergeThreshold = 100;
00080
00081
00082 const char_t dbMatchAnyOneChar = '_';
00083 const char_t dbMatchAnySubstring = '%';
00084
00085 const int dbMaxFileSegments = 64;
00086
00090 enum dbPredefinedIds {
00091 dbInvalidId,
00092 dbMetaTableId,
00093 dbBitmapId,
00094 dbFirstUserId = dbBitmapId + dbBitmapPages
00095 };
00096
00100 enum dbLockType {
00101 dbNoLock,
00102 dbSharedLock,
00103 dbUpdateLock,
00104 dbExclusiveLock
00105 };
00106
00110 class dbHeader {
00111 public:
00112 int4 curr;
00113 int4 dirty;
00114 int4 initialized;
00115 #if dbDatabaseOffsetBits > 32 && defined(ALIGN_HEADER)
00116 int4 pad1;
00117 #endif
00118 struct {
00119 offs_t size;
00120 offs_t index;
00121 offs_t shadowIndex;
00122 oid_t indexSize;
00123 oid_t shadowIndexSize;
00124 oid_t indexUsed;
00125 oid_t freeList;
00126 oid_t bitmapEnd;
00127 #if dbDatabaseOffsetBits > 32 && defined(ALIGN_HEADER)
00128 oid_t pad2;
00129 #endif
00130 } root[2];
00131
00132 int4 versionMagor;
00133 int4 versionMinor;
00134
00135 bool isInitialized() {
00136 return initialized == 1
00137 && (dirty == 1 || dirty == 0)
00138 && (curr == 1 || curr == 0)
00139 && root[curr].size > root[curr].index
00140 && root[curr].size > root[curr].shadowIndex
00141 && root[curr].size > root[curr].indexSize*sizeof(offs_t)
00142 + root[curr].shadowIndexSize*sizeof(offs_t)
00143 && root[curr].indexSize >= root[curr].indexUsed
00144 && root[curr].indexUsed >= dbFirstUserId
00145 && root[curr].bitmapEnd > dbBitmapId;
00146 }
00147 };
00148
00149 class dbSynthesizedAttribute;
00150 class dbInheritedAttribute;
00151 class dbDatabaseThreadContext;
00152
00153 class dbMonitor {
00154 public:
00155 dbLockType accLock;
00156
00157 dbDatabaseThreadContext* firstPending;
00158 dbDatabaseThreadContext* lastPending;
00159
00160 int nLockUpgrades;
00161
00162 int nReaders;
00163 int nWriters;
00164 int backupInProgress;
00165
00166 void wait(dbLockType type, dbMutex& mutex, dbDatabaseThreadContext* ctx);
00167
00168 dbMonitor() {
00169 firstPending = lastPending = NULL;
00170 accLock = dbNoLock;
00171 backupInProgress = 0;
00172 nReaders = nWriters = 0;
00173 nLockUpgrades = 0;
00174 }
00175 };
00176
00177
00178
00179 class dbAnyCursor;
00180 class dbQuery;
00181 class dbExprNode;
00182 class dbSearchContext;
00183
00184
00185 class dbVisitedObject {
00186 public:
00187 dbVisitedObject* next;
00188 oid_t oid;
00189
00190 dbVisitedObject(oid_t oid, dbVisitedObject* chain) {
00191 this->oid = oid;
00192 next = chain;
00193 }
00194 };
00195
00199 class GIGABASE_DLL_ENTRY dbDatabase {
00200 friend class dbSelection;
00201 friend class dbAnyCursor;
00202 friend class dbHashTable;
00203 friend class dbQuery;
00204 friend class dbRtree;
00205 friend class dbRtreePage;
00206 friend class dbBtree;
00207 friend class dbBtreePage;
00208 friend class dbThickBtreePage;
00209 friend class dbInheritedAttribute;
00210 friend class dbParallelQueryContext;
00211 friend class dbServer;
00212 friend class dbPagePool;
00213
00214 friend class dbBlob;
00215 friend class dbBlobIterator;
00216 friend class dbBlobReadIterator;
00217 friend class dbBlobWriteIterator;
00218 friend class dbAnyContainer;
00219
00220 friend class dbGetTie;
00221 friend class dbPutTie;
00222
00223 friend class dbUserFunctionArgument;
00224
00225 friend class dbCLI;
00226 friend class GiSTdb;
00227
00228 friend class dbBtreeIterator;
00229 friend class dbRtreeIterator;
00230 friend class dbTableIterator;
00231 public:
00239 bool open(char_t const* databaseName, time_t transactionCommitDelay = 0, int openAttr = dbFile::no_buffering);
00240
00248 bool open(dbFile* file, time_t transactionCommitDelay = 0, bool deleteFileOnClose = false);
00249
00250 enum dbAccessType {
00251 dbReadOnly = 0,
00252 dbAllAccess = 1
00253 };
00254
00258 struct OpenParameters {
00262 char_t const* databaseName;
00263
00267 int openAttr;
00268
00272 dbFile* file;
00273
00277 time_t transactionCommitDelay;
00278
00282 bool deleteFileOnClose;
00283
00287 dbAccessType accessType;
00288
00295 size_t poolSize;
00296
00300 size_t extensionQuantum;
00301
00305 size_t initIndexSize;
00306
00310 int nThreads;
00311
00312 OpenParameters() {
00313 databaseName = NULL;
00314 openAttr = 0;
00315 file = NULL;
00316 transactionCommitDelay = 0;
00317 deleteFileOnClose = false;
00318 accessType = dbAllAccess;
00319 poolSize = 0;
00320 extensionQuantum = dbDefaultExtensionQuantum;
00321 initIndexSize = dbDefaultInitIndexSize;
00322 nThreads = 1;
00323 }
00324 };
00325
00326
00332 bool open(OpenParameters& params);
00333
00334
00338 virtual void close();
00339
00343 void commit();
00344
00348 void executeBatch();
00349
00354 void precommit();
00355
00359 void rollback();
00360
00365 void attach();
00366
00367 enum DetachFlags {
00368 COMMIT = 1,
00369 DESTROY_CONTEXT = 2
00370 };
00375 void detach(int flags = COMMIT|DESTROY_CONTEXT);
00376
00381 void lock(dbLockType type = dbExclusiveLock) { beginTransaction(type); }
00382
00391 bool backup(char_t const* backupFileName, bool compactify);
00392
00402 bool backup(dbOSFile* file, bool compactify);
00403
00410 bool restore(char_t const* backupFileName, char_t const* databaseFileName);
00411
00415 int getVersion();
00416
00421 void assign(dbTableDescriptor& desc) {
00422 assert(((void)"Table is not yet assigned to the database",
00423 desc.tableId == 0));
00424 desc.db = this;
00425 desc.fixedDatabase = true;
00426 }
00427
00434 dbTableDescriptor* lookupTable(dbTableDescriptor* desc);
00435
00443 void setConcurrency(unsigned nThreads);
00444
00449 offs_t getAllocatedSize() { return allocatedSize; }
00450
00458 void allowColumnsDeletion(bool enabled = true) {
00459 confirmDeleteColumns = enabled;
00460 }
00461
00469 bool prepareQuery(dbAnyCursor* cursor, dbQuery& query);
00470
00474 enum dbErrorClass {
00475 NoError,
00476 QueryError,
00477 ArithmeticError,
00478 IndexOutOfRangeError,
00479 DatabaseOpenError,
00480 FileError,
00481 OutOfMemoryError,
00482 Deadlock,
00483 NullReferenceError,
00484 FileLimitExeeded,
00485 DatabaseReadOnly
00486 };
00487 typedef void (*dbErrorHandler)(int error, char const* msg, int msgarg, void* context);
00488
00495 dbErrorHandler setErrorHandler(dbErrorHandler newHandler, void* errorHandlerContext = NULL);
00496
00497
00504 virtual void scheduleBackup(char_t const* fileName, time_t periodSec);
00505
00506
00514 virtual void handleError(dbErrorClass error, char const* msg = NULL,
00515 int arg = 0);
00516
00517 dbAccessType accessType;
00518 size_t extensionQuantum;
00519 size_t initIndexSize;
00520
00521 static unsigned dbParallelScanThreshold;
00522
00531 void insertRecord(dbTableDescriptor* table, dbAnyReference* ref,
00532 void const* record, bool batch);
00537 offs_t used();
00538
00542 bool isOpen() const { return opened; }
00543
00550 offs_t getDatabaseSize() {
00551 return header->root[1-curr].size;
00552 }
00553
00560 void setFileExtensionQuantum(offs_t quantum) {
00561 dbFileExtensionQuantum = quantum;
00562 }
00563
00568 void setFileSizeLimit(offs_t limit) {
00569 dbFileSizeLimit = limit;
00570 }
00571
00572 #ifndef NO_MEMBER_TEMPLATES
00573
00578 template<class T>
00579 dbReference<T> insert(T const& record) {
00580 dbReference<T> ref;
00581 insertRecord(lookupTable(&T::dbDescriptor), &ref, &record, false);
00582 return ref;
00583 }
00590 template<class T>
00591 dbReference<T> batchInsert(T const& record) {
00592 dbReference<T> ref;
00593 insertRecord(lookupTable(&T::dbDescriptor), &ref, &record, true);
00594 return ref;
00595 }
00596 #endif
00597
00610 dbDatabase(dbAccessType type = dbAllAccess,
00611 size_t poolSize = 0,
00612 size_t dbExtensionQuantum = dbDefaultExtensionQuantum,
00613 size_t dbInitIndexSize = dbDefaultInitIndexSize,
00614 int nThreads = 1
00615
00616
00617
00618
00619 #ifdef NO_PTHREADS
00620 , bool usePthreads = false
00621 #endif
00622 );
00623
00627 virtual ~dbDatabase();
00628
00629 protected:
00630 dbThreadContext<dbDatabaseThreadContext> threadContext;
00631
00632 dbThreadPool threadPool;
00633
00634 dbHeader* header;
00635 int4* dirtyPagesMap;
00636 unsigned parThreads;
00637 bool modified;
00638
00639 int curr;
00640
00641
00642 bool uncommittedChanges;
00643
00644 offs_t dbFileExtensionQuantum;
00645 offs_t dbFileSizeLimit;
00646
00647
00648 volatile int commitInProgress;
00649 volatile int concurrentTransId;
00650
00651 size_t currRBitmapPage;
00652 size_t currRBitmapOffs;
00653
00654 size_t currPBitmapPage;
00655 size_t currPBitmapOffs;
00656
00657
00658 struct dbLocation {
00659 offs_t pos;
00660 offs_t size;
00661 dbLocation* next;
00662 };
00663 dbLocation* reservedChain;
00664
00665 size_t committedIndexSize;
00666 size_t currIndexSize;
00667
00668 oid_t updatedRecordId;
00669
00670 dbFile* file;
00671 dbMutex mutex;
00672 dbSemaphore writeSem;
00673 dbSemaphore readSem;
00674 dbSemaphore upgradeSem;
00675 dbEvent backupCompletedEvent;
00676 dbMonitor monitor;
00677 dbPagePool pool;
00678 dbTableDescriptor* tables;
00679
00680 int* bitmapPageAvailableSpace;
00681 bool opened;
00682
00683 offs_t allocatedSize;
00684
00685 int forceCommitCount;
00686 time_t commitDelay;
00687 time_t commitTimeout;
00688 time_t commitTimerStarted;
00689
00690 dbMutex commitThreadSyncMutex;
00691 dbMutex delayedCommitStartTimerMutex;
00692 dbMutex delayedCommitStopTimerMutex;
00693 dbEvent commitThreadSyncEvent;
00694
00695 dbEvent delayedCommitStartTimerEvent;
00696
00697 dbEvent delayedCommitStopTimerEvent;
00698 dbDatabaseThreadContext* delayedCommitContext;
00699
00700 dbMutex backupMutex;
00701 dbEvent backupInitEvent;
00702 char_t* backupFileName;
00703 time_t backupPeriod;
00704
00705 dbThread backupThread;
00706 dbThread commitThread;
00707
00708 dbTableDescriptor* batchList;
00709
00710 int accessCount;
00711
00712 dbL2List threadContextList;
00713 dbMutex threadContextListMutex;
00714
00715 dbErrorHandler errorHandler;
00716 void* errorHandlerContext;
00717
00718 bool confirmDeleteColumns;
00719 int schemeVersion;
00720 dbVisitedObject* visitedChain;
00721
00722 bool deleteFile;
00723
00729 dbTableDescriptor* loadMetaTable();
00730
00731 void releaseFile() {
00732 file->close();
00733 if (deleteFile) {
00734 delete file;
00735 }
00736 }
00737
00741 virtual void replicatePage(offs_t pageOffs, void* pageData);
00742
00746 void delayedCommit();
00747
00751 void backupScheduler();
00752
00753 static void thread_proc delayedCommitProc(void* arg) {
00754 ((dbDatabase*)arg)->delayedCommit();
00755 }
00756
00757 static void thread_proc backupSchedulerProc(void* arg) {
00758 ((dbDatabase*)arg)->backupScheduler();
00759 }
00760
00765 void commit(dbDatabaseThreadContext* ctx);
00766
00772 offs_t getPos(oid_t oid) {
00773 byte* p = pool.get(header->root[1-curr].index
00774 + (offs_t)(oid / dbHandlesPerPage) * dbPageSize);
00775 offs_t pos = *((offs_t*)p + oid % dbHandlesPerPage);
00776 pool.unfix(p);
00777 return pos;
00778 }
00779
00785 void setPos(oid_t oid, offs_t pos) {
00786 byte* p = pool.put(header->root[1-curr].index
00787 + (offs_t)(oid / dbHandlesPerPage) * dbPageSize);
00788 *((offs_t*)p + oid % dbHandlesPerPage) = pos;
00789 pool.unfix(p);
00790 }
00791
00798 dbRecord* getRow(dbGetTie& tie, oid_t oid) {
00799 offs_t pos = getPos(oid);
00800 assert(!(pos & (dbFreeHandleFlag|dbPageObjectFlag)));
00801 tie.set(pool, pos & ~dbFlagsMask);
00802 return (dbRecord*)tie.get();
00803 }
00804
00810 void getHeader(dbRecord& rec, oid_t oid) {
00811 offs_t pos = getPos(oid);
00812 int offs = (int)pos & (dbPageSize-1);
00813 byte* p = pool.get(pos - offs);
00814 rec = *(dbRecord*)(p + (offs & ~dbFlagsMask));
00815 pool.unfix(p);
00816 }
00817
00823 byte* put(oid_t oid) {
00824 offs_t pos = getPos(oid);
00825 int offs = (int)pos & (dbPageSize-1);
00826 return pool.put(pos-offs) + (offs & ~dbFlagsMask);
00827 }
00828
00834 byte* get(oid_t oid) {
00835 offs_t pos = getPos(oid);
00836 int offs = (int)pos & (dbPageSize-1);
00837 return pool.get(pos-offs) + (offs & ~dbFlagsMask);
00838 }
00839
00847 dbRecord* putRow(dbPutTie& tie, oid_t oid, size_t newSize);
00848
00855 dbRecord* putRow(dbPutTie& tie, oid_t oid);
00856
00863 byte* put(dbPutTie& tie, oid_t oid);
00864
00869 void restoreTablesConsistency();
00870
00876 void applyIndex(dbFieldDescriptor* field, dbSearchContext& sc);
00877
00894 bool isIndexApplicable(dbAnyCursor* cursor, dbExprNode* expr, dbQuery& query,
00895 dbFieldDescriptor* &indexedField, bool& truncate, bool ascent, bool forAll);
00896
00904 bool isIndexApplicableToExpr(dbSearchContext& sc, dbExprNode* expr);
00905
00909 bool followInverseReference(dbExprNode* expr, dbExprNode* andExpr,
00910 dbAnyCursor* cursor, oid_t iref);
00911
00919 bool existsInverseReference(dbExprNode* expr, int nExistsClauses);
00920
00927 static void _fastcall execute(dbExprNode* expr,
00928 dbInheritedAttribute& iattr,
00929 dbSynthesizedAttribute& sattr);
00938 bool evaluateBoolean(dbExprNode* expr, oid_t oid, dbTableDescriptor* table, dbAnyCursor* cursor);
00939
00949 size_t evaluateString(dbExprNode* expr, oid_t oid, dbTableDescriptor* table, char_t* buf, size_t bufSize);
00950
00958 void evaluate(dbExprNode* expr, oid_t oid, dbTableDescriptor* table, dbSynthesizedAttribute& result);
00959
00964 void select(dbAnyCursor* cursor);
00965
00971 void select(dbAnyCursor* cursor, dbQuery& query);
00972
00978 void traverse(dbAnyCursor* cursor, dbQuery& query);
00979
00986 void update(oid_t oid, dbTableDescriptor* table, void const* record);
00987
00993 void remove(dbTableDescriptor* table, oid_t oid);
00994
01002 offs_t allocate(offs_t size, oid_t oid = 0);
01003
01009 void free(offs_t pos, offs_t size);
01010
01015 void extend(offs_t size);
01016
01023 void cloneBitmap(offs_t pos, offs_t size);
01024
01029 oid_t allocateId();
01030
01035 void freeId(oid_t oid);
01036
01043 void updateCursors(oid_t oid, bool removed = false);
01044
01049 oid_t allocatePage() {
01050 oid_t oid = allocateId();
01051 setPos(oid, allocate(dbPageSize) | dbPageObjectFlag | dbModifiedFlag);
01052 return oid;
01053 }
01054
01059 void freePage(oid_t oid);
01060
01068 oid_t allocateRow(oid_t tableId, size_t size,
01069 dbTableDescriptor* desc = NULL)
01070 {
01071 oid_t oid = allocateId();
01072 allocateRow(tableId, oid, size, desc);
01073 return oid;
01074 }
01075
01084 void allocateRow(oid_t tableId, oid_t oid, size_t size, dbTableDescriptor* desc);
01085
01092 void freeRow(oid_t tableId, oid_t oid, dbTableDescriptor* desc = NULL);
01093
01098 static void deleteCompiledQuery(dbExprNode* tree);
01099
01104 void beginTransaction(dbLockType type);
01109 void endTransaction(dbDatabaseThreadContext* ctx);
01110
01114 void initializeMetaTable();
01115
01122 bool loadScheme();
01123
01129 bool completeDescriptorsInitialization();
01130
01136 void reformatTable(oid_t tableId, dbTableDescriptor* desc);
01137
01143 void addIndices(dbTableDescriptor* desc);
01144
01150 oid_t addNewTable(dbTableDescriptor* desc);
01151
01158 void updateTableDescriptor(dbTableDescriptor* desc,
01159 oid_t tableId, dbTable* table);
01160
01161
01167 void removeInverseReferences(dbTableDescriptor* desc, oid_t oid);
01168
01169
01178 void insertInverseReference(dbFieldDescriptor* desc, oid_t reverseId,
01179 oid_t targetId);
01180
01189 void removeInverseReference(dbFieldDescriptor* desc,
01190 oid_t reverseId, oid_t targetId);
01191
01192
01197 void deleteTable(dbTableDescriptor* desc);
01198
01203 void dropTable(dbTableDescriptor* desc);
01204
01209 void createIndex(dbFieldDescriptor* fd);
01210
01215 void createHashTable(dbFieldDescriptor* fd);
01216
01221 void dropIndex(dbFieldDescriptor* fd);
01222
01227 void dropHashTable(dbFieldDescriptor* fd);
01228
01234 void linkTable(dbTableDescriptor* table, oid_t tableId);
01235
01240 void unlinkTable(dbTableDescriptor* table);
01241
01242
01249 bool wasReserved(offs_t pos, offs_t size);
01250
01259 void reserveLocation(dbLocation& location, offs_t pos, offs_t size);
01260
01265 void commitLocation();
01266
01272 dbTableDescriptor* findTable(char_t const* name);
01273
01280 dbTableDescriptor* findTableByName(char_t const* name);
01281
01282
01287 dbTableDescriptor* getTables() {
01288 return tables;
01289 }
01290
01291
01296 void cleanupOnOpenError();
01297
01301 void setDirty();
01302 };
01303
01304 template<class T>
01305 dbReference<T> insert(T const& record) {
01306 dbReference<T> ref;
01307 T::dbDescriptor.getDatabase()->insertRecord(&T::dbDescriptor, &ref, &record, false);
01308 return ref;
01309 }
01310
01311 template<class T>
01312 dbReference<T> batchInsert(T const& record) {
01313 dbReference<T> ref;
01314 T::dbDescriptor.getDatabase()->insertRecord(&T::dbDescriptor, &ref, &record, true);
01315 return ref;
01316 }
01317
01318 #ifdef NO_MEMBER_TEMPLATES
01319 template<class T>
01320 dbReference<T> insert(dbDatabase& db, T const& record) {
01321 dbReference<T> ref;
01322 db.insertRecord(db.lookupTable(&T::dbDescriptor), &ref, &record, false);
01323 return ref;
01324 }
01325 template<class T>
01326 dbReference<T> batchInsert(dbDatabase& db, T const& record) {
01327 dbReference<T> ref;
01328 db.insertRecord(db.lookupTable(&T::dbDescriptor), &ref, &record, true);
01329 return ref;
01330 }
01331 #endif
01332
01333 class dbSearchContext {
01334 public:
01335 dbDatabase* db;
01336 dbExprNode* condition;
01337 dbAnyCursor* cursor;
01338 char_t* firstKey;
01339 int firstKeyInclusion;
01340 char_t* lastKey;
01341 int lastKeyInclusion;
01342 int prefixLength;
01343 int offs;
01344 int probes;
01345 bool ascent;
01346 bool tmpKeys;
01347 bool spatialSearch;
01348 bool arraySearch;
01349
01350 union {
01351 bool b;
01352 int1 i1;
01353 int2 i2;
01354 int4 i4;
01355 db_int8 i8;
01356 real4 f4;
01357 real8 f8;
01358 oid_t oid;
01359 void* raw;
01360 rectangle* rect;
01361 char_t* s;
01362 dbAnyArray* a;
01363 } literal[2];
01364 };
01365
01366 END_GIGABASE_NAMESPACE
01367
01368 #endif
01369