Procmgmt second patch:
[csql.git] / src / server / Database.cxx
blob6d015c02005b24a55422b6684b28d1852be8b098
1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 ***************************************************************************/
16 #include<Database.h>
17 #include<os.h>
18 #include<CatalogTables.h>
19 #include<Transaction.h>
20 #include<Lock.h>
21 #include<Debug.h>
22 #include<Config.h>
23 #include<Process.h>
25 const char* Database::getName()
27 return metaData_->dbName_;
30 int Database::getDatabaseID()
32 return metaData_->dbID_;
35 size_t Database::getMaxSize()
37 return metaData_->maxSize_;
40 size_t Database::getCurrentSize()
42 return metaData_->curSize_;
45 Page* Database::getCurrentPage()
47 return metaData_->curPage_;
50 Page* Database::getFirstPage()
52 return metaData_->firstPage_;
55 int Database::getMaxChunks()
57 return metaData_->maxChunks_;
59 Chunk* Database::getHashIndexChunk()
61 return metaData_->hashIndexChunk_;
64 void Database::setDatabaseID(int id)
66 metaData_->dbID_ = id;
68 void Database::setName(const char *name)
70 strcpy(metaData_->dbName_ , name);
72 void Database::setCurrentSize(size_t size)
74 metaData_->curSize_ = size;
76 void Database::setCurrentPage(Page *page)
78 metaData_->curPage_ = page;
80 void Database::setFirstPage(Page *page)
82 metaData_->firstPage_ = page;
84 void Database::setMaxSize(size_t size)
86 metaData_->maxSize_ = size;
88 void Database::setMaxChunks(int chunks)
90 metaData_->maxChunks_ = chunks;
92 void Database::setHashIndexChunk(Chunk *ch)
94 metaData_->hashIndexChunk_ = ch;
98 int Database::initAllocDatabaseMutex()
100 return metaData_->dbAllocMutex_.init();
102 DbRetVal Database::getAllocDatabaseMutex()
104 int ret= metaData_->dbAllocMutex_.tryLock();
105 if (ret) return ErrSysInternal; else return OK;
107 DbRetVal Database::releaseAllocDatabaseMutex()
109 metaData_->dbAllocMutex_.releaseLock();
110 return OK;
115 int Database::initTransTableMutex()
117 return metaData_->dbTransTableMutex_.init();
119 DbRetVal Database::getTransTableMutex()
121 int ret = metaData_->dbTransTableMutex_.tryLock();
122 if (ret) return ErrSysInternal; else return OK;
124 DbRetVal Database::releaseTransTableMutex()
126 metaData_->dbTransTableMutex_.releaseLock();
127 return OK;
132 int Database::initProcessTableMutex()
134 return metaData_->dbProcTableMutex_.init();
136 DbRetVal Database::getProcessTableMutex()
138 int ret = metaData_->dbProcTableMutex_.tryLock();
139 if (ret) return ErrSysInternal; else return OK;
141 DbRetVal Database::releaseProcessTableMutex()
143 metaData_->dbProcTableMutex_.releaseLock();
144 return OK;
149 int Database::initDatabaseMutex()
151 return metaData_->dbMutex_.init();
153 DbRetVal Database::getDatabaseMutex()
155 int ret = metaData_->dbMutex_.tryLock();
156 if (ret) return ErrSysInternal; else return OK;
158 DbRetVal Database::releaseDatabaseMutex()
160 metaData_->dbMutex_.releaseLock();
161 return OK;
164 // Gets the free page
165 // Each page is segmented by PAGE_SIZE, so it checks the pageInfo
166 // of each page to determine if the page is free
167 // Algorithm is to scan through the pageInfo objects stored at
168 // address (db start address + i * PAGE_SIZE) where i = 1..n till end
169 // database
170 // But in case of large tuples, pages are merged, so there wont be
171 // PageInfo object on pages which are merged.
172 // These pages are skipped by checking the nextPageAfterMerge_ of PageInfo
174 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
175 Page* Database::getFreePage()
177 Page* page = getFirstPage();
178 printDebug(DM_Alloc, "Database::getFreePage firstPage:%x",page);
179 PageInfo* pageInfo = ((PageInfo*)page);
181 while( 1 == pageInfo->isUsed_)
183 //If any pages are merged to store data larger than PAGE_SIZE
184 //move to the next page after the merge and check whether it is used
185 if ( pageInfo->nextPageAfterMerge_ == NULL) {
186 pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
187 printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
189 else {
190 pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
191 printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
193 if (!isValidAddress((char*) pageInfo))
195 //printError(ErrSysInternal,"Invalid address %x",pageInfo);
196 return NULL;
200 if (!isValidAddress(((char*) pageInfo) + PAGE_SIZE))
202 printError(ErrSysInternal, "Invalid address %x",((char*) pageInfo) + PAGE_SIZE);
203 return NULL;
205 setCurrentPage((Page*) pageInfo);
206 printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
207 return (Page*) pageInfo ;
210 //Used by tuples more than PAGE_SIZE
211 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
212 Page* Database::getFreePage(size_t size)
214 Page* page = getFirstPage();
215 PageInfo* pageInfo = ((PageInfo*)page);
216 int multiple = size / PAGE_SIZE;
217 int offset = ((multiple + 1) * PAGE_SIZE);
218 printDebug(DM_Alloc, "Database::getFreePage firstPage:%x size:%d",page, size);
220 while(true){
221 while( 1 == pageInfo->isUsed_)
223 //If any pages are merged to store data larger than PAGE_SIZE
224 //move to the next page after the merge and check whether it is used
225 if ( pageInfo->nextPageAfterMerge_ == NULL) {
226 pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
227 printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
229 else {
230 pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
231 printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
234 int i = 0;
235 PageInfo *pInfo = pageInfo;
236 if (!isValidAddress(((char*)pInfo) + offset))
238 printError(ErrSysInternal,"Invalid address %x",((char*)pInfo) + offset);
239 return NULL;
241 for (i = 0; i< multiple + 1; i++)
243 if (1 == pInfo->isUsed_) break;
244 pInfo = (PageInfo*)((char*)pInfo + PAGE_SIZE);
246 if ( i == (multiple + 1)) break;
249 printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
250 setCurrentPage((Page*) pageInfo);
251 return (Page*) pageInfo ;
255 //called only in case of system database to create and initialize the chunk
256 //information
257 DbRetVal Database::createSystemDatabaseChunk(AllocType type, size_t size, int id)
260 Chunk *chunk;
261 if (-1 == id )
263 printError(ErrSysFatal, "Database ID corrupted");
264 return ErrSysFatal;
266 chunk = getSystemDatabaseChunk(id);
268 if (FixedSizeAllocator == type) chunk->setSize(size);
269 //getDatabaseMutex();
270 if (chunk->allocSize_ > PAGE_SIZE)
271 chunk->curPage_ = getFreePage(chunk->allocSize_);
272 else
273 chunk->curPage_ = getFreePage();
274 if ( chunk->curPage_ == NULL)
276 //releaseDatabaseMutex();
277 printError(ErrNoMemory, "No free pages in database: Database full");
278 return ErrNoMemory;
281 chunk->firstPage_ = chunk->curPage_;
282 PageInfo* firstPageInfo = ((PageInfo*)chunk->firstPage_);
283 firstPageInfo->isUsed_ = 1;
284 firstPageInfo->hasFreeSpace_ = 1;
285 firstPageInfo->nextPageAfterMerge_ = NULL;
286 firstPageInfo->nextPage_ = NULL;
287 chunk->setChunkID(id);
288 chunk->setAllocType(type);
289 printDebug(DM_Database, "Creating System Database Chunk:%d Size:%d",id, chunk->allocSize_);
290 if (chunk->allocSize_ > PAGE_SIZE)
292 int multiple = os::floor(chunk->allocSize_ / PAGE_SIZE);
293 int offset = ((multiple + 1) * PAGE_SIZE);
294 firstPageInfo->nextPageAfterMerge_ = ((char*)firstPageInfo)+ offset;
297 if (0 == size)
299 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)firstPageInfo) + sizeof(PageInfo));
300 varInfo->isUsed_ = 0;
301 varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
304 //releaseDatabaseMutex();
305 return OK;
308 //This will never be called. If situation arises will be coded later.
309 DbRetVal Database::deleteSystemDatabaseChunk(int id)
311 Chunk *chunk = getSystemDatabaseChunk(id);
312 chunk->setChunkID(-1);
313 chunk->setSize(0);
314 chunk->setAllocType(UnknownAllocator);
315 //TODO::
316 //chunk->pageList_
317 //walk though the pageList ptr and get all the page pointers
318 //then free all the pages used to store this by setting the
319 //start of page to notused
320 chunk->firstPage_ = NULL;
321 chunk->curPage_ = NULL;
322 return OK;
326 void Database::createAllCatalogTables()
328 //These are special chunks which hold catalog tables and other information
330 // chunk id 0 ->userChunkTable
331 // chunk id 1 ->lockBucketHash
332 // chunk id 2 ->lockTable
334 // chunk id 10->DATABASE
335 // chunk id 11->USER
336 // chunk id 12->TABLE
337 // chunk id 13->FIELD
338 // chunk id 14->ACCESS
340 // chunk id 30->hash index on tblName_ of TABLE
341 // chunk id 31->hash index on fldName_ of FIELD
342 // chunk id 32->hash index on userName_ of ACCESS
343 // chunk id 33->hash index on userName_ of USER
344 // chunk id 34->hash index on dbName_ of DATABASE
345 // chunk id 35->hash index on tblID_ of FIELD
347 createSystemDatabaseChunk(FixedSizeAllocator,
348 sizeof(Chunk), UserChunkTableId);
349 createSystemDatabaseChunk(FixedSizeAllocator,
350 sizeof(Bucket) * LOCK_BUCKET_SIZE,
351 LockTableHashBucketId);
352 createSystemDatabaseChunk(FixedSizeAllocator,
353 sizeof(Mutex)* LOCK_BUCKET_SIZE,
354 LockTableMutexId);
355 createSystemDatabaseChunk(FixedSizeAllocator,
356 sizeof(LockHashNode), LockTableId);
357 createSystemDatabaseChunk(FixedSizeAllocator,
358 sizeof(TransHasNode), TransHasTableId);
360 createSystemDatabaseChunk(VariableSizeAllocator,
361 0, UndoLogTableID);
363 createSystemDatabaseChunk(FixedSizeAllocator,
364 sizeof(DATABASEFILE), DatabaseTableId);
365 createSystemDatabaseChunk(FixedSizeAllocator,
366 sizeof(USER), UserTableId);
367 createSystemDatabaseChunk(FixedSizeAllocator,
368 sizeof(TABLE), TableTableId);
369 createSystemDatabaseChunk(FixedSizeAllocator,
370 sizeof(FIELD), FieldTableId);
371 createSystemDatabaseChunk(FixedSizeAllocator,
372 sizeof(ACCESS), AccessTableId);
373 createSystemDatabaseChunk(FixedSizeAllocator,
374 sizeof(INDEX), IndexTableId);
375 createSystemDatabaseChunk(FixedSizeAllocator,
376 sizeof(INDEXFIELD), IndexFieldTableId);
380 //used in case of system database
381 Chunk* Database::getSystemDatabaseChunk(int id)
383 size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
384 id * sizeof (Chunk);
385 return (Chunk*)(((char*) metaData_) + offset);
389 //used in case of system database
390 Transaction* Database::getSystemDatabaseTrans(int slot)
392 size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
393 os::alignLong(MAX_CHUNKS * sizeof (Chunk)) +
394 slot * sizeof (Transaction);
395 return (Transaction*)(((char*) metaData_) + offset);
398 //used in case of system database
399 ThreadInfo* Database::getThreadInfo(int slot)
401 size_t offset = os::alignLong(sizeof (DatabaseMetaData));
402 offset = offset + os::alignLong( MAX_CHUNKS * sizeof (Chunk));
403 offset = offset + os::alignLong( Conf::config.getMaxTrans() * sizeof(Transaction));
404 offset = offset + slot * sizeof (ThreadInfo);
405 return (ThreadInfo*)(((char*) metaData_) + offset);
408 //used in case of system database
409 ThreadInfo* Database::getThreadInfo(int pidSlot, int thrSlot)
411 size_t offset = os::alignLong(sizeof (DatabaseMetaData));
412 offset = offset + os::alignLong( MAX_CHUNKS * sizeof (Chunk));
413 offset = offset + os::alignLong( Conf::config.getMaxTrans() * sizeof(Transaction));
414 offset = offset + os::alignLong( Conf::config.getMaxProcs() * sizeof(ProcInfo));
415 offset = offset + pidSlot * thrSlot * sizeof (ThreadInfo);
416 return (ThreadInfo*)(((char*) metaData_) + offset);
419 bool Database::isLastThread()
421 DbRetVal rv = getProcessTableMutex();
422 if (OK != rv)
424 printError(rv, "Unable to get process table mutex from Database::isLastThread()");
425 return false;
427 pid_t pid = appPid;
429 ThreadInfo *tInfo = getThreadInfo(pid, 0);
430 int regThr = 0;
431 for (int i=0; i < Conf::config.getMaxThreads(); i++)
433 if (0 != tInfo->thrid_) regThr++;
434 tInfo++;
436 releaseProcessTableMutex();
437 if (regThr < 1) return true;
438 return false;
442 bool Database::isValidAddress(void* addr)
444 if ((char*) addr > ((char*)getMetaDataPtr()) + getMaxSize())
445 return false;
446 else
447 return true;
450 //should be called only on system database
451 void* Database::allocLockHashBuckets()
453 Chunk *chunk = getSystemDatabaseChunk(LockTableHashBucketId);
454 void *ptr = chunk->allocate(this);
455 if (NULL == ptr)
457 printError(ErrNoMemory, "Chunk Allocation failed for lock hash bucket catalog table");
459 return ptr;
462 Bucket* Database::getLockHashBuckets()
464 Chunk *tChunk = getSystemDatabaseChunk(LockTableHashBucketId);
465 ChunkIterator iter = tChunk->getIterator();
466 return (Bucket*)iter.nextElement();