src/server/Database.cxx

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007 by www.databasecache.com                           *
00003  *   Contact: praba_tuty@databasecache.com                                 *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015   ***************************************************************************/
00016 #include<Database.h>
00017 #include<os.h>
00018 #include<CatalogTables.h>
00019 #include<Transaction.h>
00020 #include<Lock.h>
00021 #include<Debug.h>
00022 #include<Config.h>
00023 #include<Process.h>
00024 
00025 const char* Database::getName()
00026 {
00027     return metaData_->dbName_;
00028 }
00029 
00030 int Database::getDatabaseID()
00031 {
00032     return metaData_->dbID_;
00033 }
00034 
00035 long Database::getMaxSize()
00036 {
00037     return metaData_->maxSize_;
00038 }
00039 
00040 long Database::getCurrentSize()
00041 {
00042     return metaData_->curSize_;
00043 
00044 }
00045 Page* Database::getCurrentPage()
00046 {
00047     return metaData_->curPage_;
00048 
00049 }
00050 Page* Database::getFirstPage()
00051 {
00052     return metaData_->firstPage_;
00053 
00054 }
00055 int Database::getNoOfChunks()
00056 {
00057     return metaData_->noOfChunks_;
00058 }
00059 Chunk* Database::getHashIndexChunk()
00060 {
00061     return metaData_->hashIndexChunk_;
00062 }
00063 
00064 void Database::setDatabaseID(int id)
00065 {
00066     metaData_->dbID_ = id;
00067 }
00068 void Database::setName(const char *name)
00069 {
00070     strcpy(metaData_->dbName_ , name);
00071 }
00072 void Database::setCurrentSize(long size)
00073 {
00074     metaData_->curSize_ = size;
00075 }
00076 void Database::setCurrentPage(Page *page)
00077 {
00078     metaData_->curPage_ = page;
00079 }
00080 void Database::setFirstPage(Page *page)
00081 {
00082     metaData_->firstPage_ = page;
00083 }
00084 void Database::setMaxSize(long size)
00085 {
00086     metaData_->maxSize_ = size;
00087 }
00088 void Database::setNoOfChunks(int chunks)
00089 {
00090     metaData_->noOfChunks_ = chunks;
00091 }
00092 void Database::setHashIndexChunk(Chunk *ch)
00093 {
00094     metaData_->hashIndexChunk_ = ch;
00095 }
00096 
00097 
00098 int Database::initAllocDatabaseMutex()
00099 {
00100     return metaData_->dbAllocMutex_.init("allocdb");
00101 }
00102 DbRetVal Database::getAllocDatabaseMutex(bool procAccount) 
00103 {
00104     int ret= metaData_->dbAllocMutex_.getLock(procAccount);
00105     if (ret) return ErrLockTimeOut; else return OK;
00106 }
00107 DbRetVal Database::releaseAllocDatabaseMutex(bool procAccount)
00108 {
00109     metaData_->dbAllocMutex_.releaseLock(procAccount);
00110     return OK;
00111 }
00112 
00113 
00114 
00115 int Database::initTransTableMutex()
00116 {
00117     return metaData_->dbTransTableMutex_.init("transtable");
00118 }
00119 DbRetVal Database::getTransTableMutex()
00120 {
00121     int ret = metaData_->dbTransTableMutex_.getLock(procSlot);
00122     if (ret) return ErrLockTimeOut; else return OK;
00123 }
00124 DbRetVal Database::releaseTransTableMutex()
00125 {
00126     metaData_->dbTransTableMutex_.releaseLock(procSlot);
00127     return OK;
00128 }
00129 
00130 
00131 
00132 int Database::initProcessTableMutex()
00133 {
00134     return metaData_->dbProcTableMutex_.init("proctable");
00135 }
00136 DbRetVal Database::getProcessTableMutex(bool procAccount)
00137 {
00138     int ret = metaData_->dbProcTableMutex_.getLock(-1, procAccount);
00139     if (ret) return ErrLockTimeOut; else return OK;
00140 }
00141 DbRetVal Database::releaseProcessTableMutex(bool procAccount)
00142 {
00143     metaData_->dbProcTableMutex_.releaseLock(-1, procAccount);
00144     return OK;
00145 }
00146 
00147 
00148 
00149 int Database::initDatabaseMutex()
00150 {
00151     return metaData_->dbMutex_.init("db");
00152 }
00153 DbRetVal Database::getDatabaseMutex(bool procAccount)
00154 {
00155     int ret = metaData_->dbMutex_.getLock(procSlot, procAccount);
00156     if (ret) return ErrLockTimeOut; else return OK;
00157 }
00158 DbRetVal Database::releaseDatabaseMutex(bool procAccount)
00159 {
00160     metaData_->dbMutex_.releaseLock(procSlot, procAccount);
00161     return OK;
00162 }
00163 
00164 // Gets the free page
00165 // Each page is segmented by PAGE_SIZE, so it checks the pageInfo
00166 // of each page to determine if the page is free
00167 // Algorithm is to scan through the pageInfo objects stored at
00168 // address (db start address + i * PAGE_SIZE) where i = 1..n till end
00169 // database
00170 // But in case of large tuples, pages are merged, so there wont be
00171 // PageInfo object on pages which are merged.
00172 // These pages are skipped by checking the nextPageAfterMerge_ of PageInfo
00173 
00174 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
00175 Page* Database::getFreePage()
00176 {
00177     //Page* page = getFirstPage();
00178     Page* page = getCurrentPage();
00179     //printDebug(DM_Alloc, "Database::getFreePage firstPage:%x",page);
00180     printDebug(DM_Alloc, "Database::getFreePage currentpage:%x",page);
00181     PageInfo* pageInfo = ((PageInfo*)page);
00182     char* endAddr = ((char*)getMetaDataPtr())  + getMaxSize();
00183     int pageSize = PAGE_SIZE;
00184     while( 1 == pageInfo->isUsed_)
00185     {
00186         //If any pages are merged to store data larger than PAGE_SIZE
00187         //move to the next page after the merge and check whether it is used
00188         if ( pageInfo->nextPageAfterMerge_ == NULL) {
00189             pageInfo = (PageInfo*)((char*)pageInfo + pageSize);
00190             printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
00191         }
00192         else {
00193             pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
00194             printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
00195         }
00196         if ((char*)pageInfo >= endAddr)
00197         {
00198             //printError(ErrSysInternal,"Invalid address %x",pageInfo);
00199             return NULL;
00200         }
00201 
00202     }
00203     if (!isValidAddress(((char*) pageInfo) + pageSize))
00204     {
00205         printError(ErrSysInternal, "Invalid address %x",((char*) pageInfo) + pageSize);
00206         return NULL;
00207     }
00208     setCurrentPage((Page*) pageInfo);
00209     printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
00210     return (Page*) pageInfo ;
00211 }
00212 
00213 //Used by tuples more than PAGE_SIZE
00214 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
00215 Page* Database::getFreePage(size_t size)
00216 {
00217     Page* page = getFirstPage();
00218     PageInfo* pageInfo = ((PageInfo*)page);
00219     int multiple = size / PAGE_SIZE;
00220     int offset = ((multiple + 1) * PAGE_SIZE);
00221     printDebug(DM_Alloc, "Database::getFreePage firstPage:%x size:%ld",page, size);
00222     char* endAddr = ((char*)getMetaDataPtr())  + getMaxSize();
00223     int pageSize = PAGE_SIZE;
00224     while(true){
00225         while( 1 == pageInfo->isUsed_)
00226         {
00227             //If any pages are merged to store data larger than PAGE_SIZE
00228             //move to the next page after the merge and check whether it is used
00229             if ( pageInfo->nextPageAfterMerge_ == NULL) {
00230                 pageInfo = (PageInfo*)((char*)pageInfo + pageSize);
00231                 printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
00232             }
00233             else {
00234                 pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
00235                 printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
00236             }
00237         }
00238         int i = 0;
00239         PageInfo *pInfo = pageInfo;
00240         if ((((char*)pInfo) + offset) >= endAddr)
00241         {
00242             printError(ErrSysInternal,"Invalid address %x",((char*)pInfo) + offset);
00243             return NULL;
00244         }
00245         for (i = 0; i< multiple + 1; i++)
00246         {
00247             if (1 == pInfo->isUsed_) break;
00248             pInfo = (PageInfo*)((char*)pInfo + pageSize);
00249         }
00250         if ( i == (multiple + 1))  break;
00251     }
00252 
00253     printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
00254     setCurrentPage((Page*) pageInfo);
00255     return (Page*) pageInfo ;
00256 }
00257 
00258 void Database::printStatistics()
00259 {
00260     Page* page = getFirstPage();
00261     PageInfo* pageInfo = ((PageInfo*)page);
00262     int usedPageCount =0, usedMergedPageCount =0, totalPages=0;
00263     printf("<DatabaseStatistics>\n");
00264     printf("  <Database Name>  %s </Database Name>\n", getName());
00265     printf("  <Max Size> %ld </Max Size>\n", getMaxSize());
00266     printf("  <First Page> %x </First Page>\n", getFirstPage());
00267     while(isValidAddress((char*) pageInfo))
00268     {
00269         if (pageInfo == NULL) break;
00270         if (1 == pageInfo->isUsed_) {
00271            if ( pageInfo->nextPageAfterMerge_ == NULL) {
00272               pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
00273               usedPageCount++; totalPages++;
00274               printDebug(DM_Alloc, "Normal Page:Moving to page:%x\n",pageInfo);
00275               continue;
00276            }
00277            else {
00278               pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
00279               usedMergedPageCount++; totalPages++;
00280               printDebug(DM_Alloc,"Merged Page:Moving to page:%x\n",pageInfo);
00281               continue;
00282            }
00283         }
00284         pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
00285         printDebug(DM_Alloc,"Normal Page not used:Moving to page:%x\n",pageInfo);
00286         totalPages++;
00287     }
00288     printf("  <Total Pages> %d </Total Pages>\n", totalPages);
00289     printf("  <Used Normal Pages> %d </Used Normal Pages>\n", usedPageCount);
00290     printf("  <Used Merged Pages> %d </Used Merged Pages>\n", usedMergedPageCount);
00291     printf("  <Chunks Used> %d </Chunks Used>\n", getNoOfChunks());
00292     printf("</DatabaseStatistics>\n");
00293 
00294     return ;
00295 }
00296 
00297 
00298 //called only in case of system database to create and initialize the chunk
00299 //information
00300 DbRetVal Database::createSystemDatabaseChunk(AllocType type, size_t size, int id)
00301 {
00302 
00303     Chunk *chunk;
00304     if (-1 == id )
00305     {
00306         printError(ErrSysFatal, "Database ID corrupted");
00307         return ErrSysFatal;
00308     }
00309     chunk = getSystemDatabaseChunk(id);
00310 
00311     if (FixedSizeAllocator == type) chunk->setSize(size);
00312     //getDatabaseMutex();
00313     if (chunk->allocSize_ > PAGE_SIZE)
00314         chunk->curPage_ = getFreePage(chunk->allocSize_);
00315     else
00316          chunk->curPage_ = getFreePage();
00317     if ( chunk->curPage_ == NULL)
00318     {
00319        //releaseDatabaseMutex();
00320        printError(ErrNoMemory, "No free pages in database: Database full");
00321        return ErrNoMemory;
00322     }
00323 
00324     chunk->firstPage_ = chunk->curPage_;
00325     PageInfo* firstPageInfo = ((PageInfo*)chunk->firstPage_);
00326     firstPageInfo->setFirstPageAsUsed();
00327     chunk->setChunkID(id);
00328     chunk->setAllocType(type);
00329     printDebug(DM_Database, "Creating System Database Chunk:%d Size:%d",id, chunk->allocSize_);
00330     if (chunk->allocSize_ > PAGE_SIZE)
00331     {
00332         int multiple = os::floor(chunk->allocSize_ / PAGE_SIZE);
00333         int offset = ((multiple + 1) * PAGE_SIZE);
00334         firstPageInfo->nextPageAfterMerge_ = ((char*)firstPageInfo)+ offset;
00335     }
00336 
00337     if (0 == size)
00338     {
00339         VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)firstPageInfo) + sizeof(PageInfo));
00340         varInfo->isUsed_ = 0;
00341         varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
00342 
00343     }
00344     incrementChunk();
00345     //releaseDatabaseMutex();
00346     return OK;
00347 }
00348 
00349 //This is never called currently. If situation arises will be coded later.
00350 DbRetVal Database::deleteSystemDatabaseChunk(int id)
00351 {
00352 
00353     Chunk *chunk = getSystemDatabaseChunk(id);
00354     chunk->setChunkID(-1);
00355     chunk->setSize(0);
00356     chunk->setAllocType(UnknownAllocator);
00357     //TODO::
00358     //chunk->pageList_
00359     //walk though the pageList ptr and get all the page pointers
00360     //then free all the pages used to store this by setting the
00361     //start of page to notused
00362     chunk->firstPage_ = NULL;
00363     chunk->curPage_ = NULL;
00364     decrementChunk();
00365     return OK;
00366 }
00367 
00368 
00369 void Database::createAllCatalogTables()
00370 {
00371     //These are special chunks which hold catalog tables and other information
00372     //
00373     // chunk id 0 ->userChunkTable
00374     // chunk id 1 ->lockBucketHash
00375     // chunk id 2 ->lockTable
00376     //
00377     // chunk id 10->DATABASE
00378     // chunk id 11->USER
00379     // chunk id 12->TABLE
00380     // chunk id 13->FIELD
00381     // chunk id 14->ACCESS
00382 
00383     createSystemTables();
00384     createMetaDataTables();
00385 }
00386 void Database::createSystemTables()
00387 {
00388     createSystemDatabaseChunk(FixedSizeAllocator,
00389                                   sizeof(Chunk), UserChunkTableId);
00390     createSystemDatabaseChunk(FixedSizeAllocator,
00391                                   sizeof(Bucket) * LOCK_BUCKET_SIZE,
00392                                   LockTableHashBucketId);
00393     createSystemDatabaseChunk(FixedSizeAllocator,
00394                                   sizeof(Mutex)* LOCK_BUCKET_SIZE,
00395                                   LockTableMutexId);
00396     createSystemDatabaseChunk(FixedSizeAllocator,
00397                                   sizeof(LockHashNode), LockTableId);
00398     createSystemDatabaseChunk(FixedSizeAllocator,
00399                                   sizeof(TransHasNode), TransHasTableId);
00400 
00401     createSystemDatabaseChunk(VariableSizeAllocator,
00402                                   0, UndoLogTableID);
00403 }
00404 void Database::createMetaDataTables()
00405 {
00406     createSystemDatabaseChunk(FixedSizeAllocator,
00407                                   sizeof(DATABASEFILE), DatabaseTableId);
00408     createSystemDatabaseChunk(FixedSizeAllocator,
00409                                   sizeof(USER), UserTableId);
00410     createSystemDatabaseChunk(FixedSizeAllocator,
00411                                   sizeof(TABLE), TableTableId);
00412     createSystemDatabaseChunk(FixedSizeAllocator,
00413                                   sizeof(FIELD), FieldTableId);
00414     createSystemDatabaseChunk(FixedSizeAllocator,
00415                                   sizeof(ACCESS), AccessTableId);
00416     createSystemDatabaseChunk(FixedSizeAllocator,
00417                                   sizeof(INDEX), IndexTableId);
00418     createSystemDatabaseChunk(FixedSizeAllocator,
00419                                   sizeof(INDEXFIELD), IndexFieldTableId);
00420 }
00421 
00422 //used in case of system database
00423 Chunk* Database::getSystemDatabaseChunk(int id)
00424 {
00425     size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
00426                         id * sizeof (Chunk);
00427     return (Chunk*)(((char*) metaData_) +  offset);
00428 }
00429 
00430 
00431 //used in case of system database
00432 Transaction* Database::getSystemDatabaseTrans(int slot)
00433 {
00434     size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
00435                     os::alignLong(MAX_CHUNKS * sizeof (Chunk)) +
00436                         slot  * sizeof (Transaction);
00437     return (Transaction*)(((char*) metaData_) +  offset);
00438 }
00439 
00440 //used in case of system database
00441 ThreadInfo* Database::getThreadInfo(int slot)
00442 {
00443 /*     size_t offset = os::alignLong(sizeof (DatabaseMetaData));
00444      offset = offset + os::alignLong( MAX_CHUNKS  * sizeof (Chunk));
00445      offset = offset + os::alignLong( Conf::config.getMaxProcs()   * sizeof(Transaction));
00446      offset = offset + slot * sizeof (ThreadInfo);
00447      return (ThreadInfo*)(((char*) metaData_) +  offset);
00448 */
00449 
00450     static size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
00451                            os::alignLong( MAX_CHUNKS  * sizeof (Chunk)) +
00452                os::alignLong( Conf::config.getMaxProcs()*sizeof(Transaction));
00453         
00454     size_t off = offset + slot * sizeof (ThreadInfo);
00455     return (ThreadInfo*)(((char*) metaData_) +  off);
00456 
00457 }
00458 
00459 bool Database::isValidAddress(void* addr)
00460 {
00461     if ((char*) addr >= ((char*)getMetaDataPtr())  + getMaxSize())
00462         return false;
00463     else
00464         return true;
00465 }
00466 
00467 //should be called only on system database
00468 void* Database::allocLockHashBuckets()
00469 {
00470     Chunk *chunk = getSystemDatabaseChunk(LockTableHashBucketId);
00471     void *ptr = chunk->allocate(this);
00472     if (NULL == ptr)
00473     {
00474         printError(ErrNoMemory, "Chunk Allocation failed for lock hash bucket catalog table");
00475     }
00476     return ptr;
00477 }
00478 
00479 Bucket* Database::getLockHashBuckets()
00480 {
00481     Chunk *tChunk = getSystemDatabaseChunk(LockTableHashBucketId);
00482     ChunkIterator iter = tChunk->getIterator();
00483     return (Bucket*)iter.nextElement();
00484 }
00485 

Generated on Mon Jun 9 22:37:15 2008 for csql by  doxygen 1.4.7