Feature: 1501518
[csql.git] / src / server / Database.cxx
blob0ec9fe7e68576d4bf383d848f552cac4f85ecab8
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>
24 extern pid_t appPid;
26 const char* Database::getName()
28 return metaData_->dbName_;
31 int Database::getDatabaseID()
33 return metaData_->dbID_;
36 size_t Database::getMaxSize()
38 return metaData_->maxSize_;
41 size_t Database::getCurrentSize()
43 return metaData_->curSize_;
46 Page* Database::getCurrentPage()
48 return metaData_->curPage_;
51 Page* Database::getFirstPage()
53 return metaData_->firstPage_;
56 int Database::getMaxChunks()
58 return metaData_->maxChunks_;
60 Chunk* Database::getHashIndexChunk()
62 return metaData_->hashIndexChunk_;
65 void Database::setDatabaseID(int id)
67 metaData_->dbID_ = id;
69 void Database::setName(const char *name)
71 strcpy(metaData_->dbName_ , name);
73 void Database::setCurrentSize(size_t size)
75 metaData_->curSize_ = size;
77 void Database::setCurrentPage(Page *page)
79 metaData_->curPage_ = page;
81 void Database::setFirstPage(Page *page)
83 metaData_->firstPage_ = page;
85 void Database::setMaxSize(size_t size)
87 metaData_->maxSize_ = size;
89 void Database::setMaxChunks(int chunks)
91 metaData_->maxChunks_ = chunks;
93 void Database::setHashIndexChunk(Chunk *ch)
95 metaData_->hashIndexChunk_ = ch;
99 int Database::initAllocDatabaseMutex()
101 return metaData_->dbAllocMutex_.init();
103 DbRetVal Database::getAllocDatabaseMutex()
105 int ret= metaData_->dbAllocMutex_.tryLock();
106 if (ret) return ErrSysInternal; else return OK;
108 DbRetVal Database::releaseAllocDatabaseMutex()
110 metaData_->dbAllocMutex_.releaseLock();
111 return OK;
116 int Database::initTransTableMutex()
118 return metaData_->dbTransTableMutex_.init();
120 DbRetVal Database::getTransTableMutex()
122 int ret = metaData_->dbTransTableMutex_.tryLock();
123 if (ret) return ErrSysInternal; else return OK;
125 DbRetVal Database::releaseTransTableMutex()
127 metaData_->dbTransTableMutex_.releaseLock();
128 return OK;
133 int Database::initProcessTableMutex()
135 return metaData_->dbProcTableMutex_.init();
137 DbRetVal Database::getProcessTableMutex()
139 int ret = metaData_->dbProcTableMutex_.tryLock();
140 if (ret) return ErrSysInternal; else return OK;
142 DbRetVal Database::releaseProcessTableMutex()
144 metaData_->dbProcTableMutex_.releaseLock();
145 return OK;
150 int Database::initDatabaseMutex()
152 return metaData_->dbMutex_.init();
154 DbRetVal Database::getDatabaseMutex()
156 int ret = metaData_->dbMutex_.tryLock();
157 if (ret) return ErrSysInternal; else return OK;
159 DbRetVal Database::releaseDatabaseMutex()
161 metaData_->dbMutex_.releaseLock();
162 return OK;
165 // Gets the free page
166 // Each page is segmented by PAGE_SIZE, so it checks the pageInfo
167 // of each page to determine if the page is free
168 // Algorithm is to scan through the pageInfo objects stored at
169 // address (db start address + i * PAGE_SIZE) where i = 1..n till end
170 // database
171 // But in case of large tuples, pages are merged, so there wont be
172 // PageInfo object on pages which are merged.
173 // These pages are skipped by checking the nextPageAfterMerge_ of PageInfo
175 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
176 Page* Database::getFreePage()
178 Page* page = getFirstPage();
179 printDebug(DM_Alloc, "Database::getFreePage firstPage:%x",page);
180 PageInfo* pageInfo = ((PageInfo*)page);
182 while( 1 == pageInfo->isUsed_)
184 //If any pages are merged to store data larger than PAGE_SIZE
185 //move to the next page after the merge and check whether it is used
186 if ( pageInfo->nextPageAfterMerge_ == NULL) {
187 pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
188 printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
190 else {
191 pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
192 printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
194 if (!isValidAddress((char*) pageInfo))
196 printError(ErrSysInternal,"Invalid address %x",pageInfo);
197 return NULL;
201 if (!isValidAddress(((char*) pageInfo) + PAGE_SIZE))
203 printError(ErrSysInternal, "Invalid address %x",((char*) pageInfo) + PAGE_SIZE);
204 return NULL;
206 setCurrentPage((Page*) pageInfo);
207 printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
208 return (Page*) pageInfo ;
211 //Used by tuples more than PAGE_SIZE
212 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
213 Page* Database::getFreePage(size_t size)
215 Page* page = getFirstPage();
216 PageInfo* pageInfo = ((PageInfo*)page);
217 int multiple = size / PAGE_SIZE;
218 int offset = ((multiple + 1) * PAGE_SIZE);
219 printDebug(DM_Alloc, "Database::getFreePage firstPage:%x size:%d",page, size);
221 while(true){
222 while( 1 == pageInfo->isUsed_)
224 //If any pages are merged to store data larger than PAGE_SIZE
225 //move to the next page after the merge and check whether it is used
226 if ( pageInfo->nextPageAfterMerge_ == NULL) {
227 pageInfo = (PageInfo*)((char*)pageInfo + PAGE_SIZE);
228 printDebug(DM_Alloc,"Normal Page:Moving to page:%x",pageInfo);
230 else {
231 pageInfo = (PageInfo*)pageInfo->nextPageAfterMerge_;
232 printDebug(DM_Alloc,"Merged Page:Moving to page:%x",pageInfo);
235 int i = 0;
236 PageInfo *pInfo = pageInfo;
237 if (!isValidAddress(((char*)pInfo) + offset))
239 printError(ErrSysInternal,"Invalid address %x",((char*)pInfo) + offset);
240 return NULL;
242 for (i = 0; i< multiple + 1; i++)
244 if (1 == pInfo->isUsed_) break;
245 pInfo = (PageInfo*)((char*)pInfo + PAGE_SIZE);
247 if ( i == (multiple + 1)) break;
250 printDebug(DM_Alloc,"Database::getFreePage returning page:%x",pageInfo);
251 setCurrentPage((Page*) pageInfo);
252 return (Page*) pageInfo ;
256 //called only in case of system database to create and initialize the chunk
257 //information
258 DbRetVal Database::createSystemDatabaseChunk(AllocType type, size_t size, int id)
261 Chunk *chunk;
262 if (-1 == id )
264 printError(ErrSysFatal, "Database ID corrupted");
265 return ErrSysFatal;
267 chunk = getSystemDatabaseChunk(id);
269 if (FixedSizeAllocator == type) chunk->setSize(size);
270 //getDatabaseMutex();
271 if (chunk->allocSize_ > PAGE_SIZE)
272 chunk->curPage_ = getFreePage(chunk->allocSize_);
273 else
274 chunk->curPage_ = getFreePage();
275 if ( chunk->curPage_ == NULL)
277 //releaseDatabaseMutex();
278 printError(ErrNoMemory, "No free pages in database: Database full");
279 return ErrNoMemory;
282 chunk->firstPage_ = chunk->curPage_;
283 PageInfo* firstPageInfo = ((PageInfo*)chunk->firstPage_);
284 firstPageInfo->isUsed_ = 1;
285 firstPageInfo->hasFreeSpace_ = 1;
286 firstPageInfo->nextPageAfterMerge_ = NULL;
287 firstPageInfo->nextPage_ = NULL;
288 chunk->setChunkID(id);
289 chunk->setAllocType(type);
290 printDebug(DM_Database, "Creating System Database Chunk:%d Size:%d",id, chunk->allocSize_);
291 if (chunk->allocSize_ > PAGE_SIZE)
293 int multiple = os::floor(chunk->allocSize_ / PAGE_SIZE);
294 int offset = ((multiple + 1) * PAGE_SIZE);
295 firstPageInfo->nextPageAfterMerge_ = ((char*)firstPageInfo)+ offset;
298 if (0 == size)
300 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)firstPageInfo) + sizeof(PageInfo));
301 varInfo->isUsed_ = 0;
302 varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
305 //releaseDatabaseMutex();
306 return OK;
309 //This will never be called. If situation arises will be coded later.
310 DbRetVal Database::deleteSystemDatabaseChunk(int id)
312 Chunk *chunk = getSystemDatabaseChunk(id);
313 chunk->setChunkID(-1);
314 chunk->setSize(0);
315 chunk->setAllocType(UnknownAllocator);
316 //TODO::
317 //chunk->pageList_
318 //walk though the pageList ptr and get all the page pointers
319 //then free all the pages used to store this by setting the
320 //start of page to notused
321 chunk->firstPage_ = NULL;
322 chunk->curPage_ = NULL;
323 return OK;
327 void Database::createAllCatalogTables()
329 //These are special chunks which hold catalog tables and other information
331 // chunk id 0 ->userChunkTable
332 // chunk id 1 ->lockBucketHash
333 // chunk id 2 ->lockTable
335 // chunk id 10->DATABASE
336 // chunk id 11->USER
337 // chunk id 12->TABLE
338 // chunk id 13->FIELD
339 // chunk id 14->ACCESS
341 // chunk id 30->hash index on tblName_ of TABLE
342 // chunk id 31->hash index on fldName_ of FIELD
343 // chunk id 32->hash index on userName_ of ACCESS
344 // chunk id 33->hash index on userName_ of USER
345 // chunk id 34->hash index on dbName_ of DATABASE
346 // chunk id 35->hash index on tblID_ of FIELD
348 createSystemDatabaseChunk(FixedSizeAllocator,
349 sizeof(Chunk), UserChunkTableId);
350 createSystemDatabaseChunk(FixedSizeAllocator,
351 sizeof(Bucket) * LOCK_BUCKET_SIZE,
352 LockTableHashBucketId);
353 createSystemDatabaseChunk(FixedSizeAllocator,
354 sizeof(Mutex)* LOCK_BUCKET_SIZE,
355 LockTableMutexId);
356 createSystemDatabaseChunk(FixedSizeAllocator,
357 sizeof(LockHashNode), LockTableId);
358 createSystemDatabaseChunk(FixedSizeAllocator,
359 sizeof(TransHasNode), TransHasTableId);
361 createSystemDatabaseChunk(VariableSizeAllocator,
362 0, UndoLogTableID);
364 createSystemDatabaseChunk(FixedSizeAllocator,
365 sizeof(DATABASEFILE), DatabaseTableId);
366 createSystemDatabaseChunk(FixedSizeAllocator,
367 sizeof(USER), UserTableId);
368 createSystemDatabaseChunk(FixedSizeAllocator,
369 sizeof(TABLE), TableTableId);
370 createSystemDatabaseChunk(FixedSizeAllocator,
371 sizeof(FIELD), FieldTableId);
372 createSystemDatabaseChunk(FixedSizeAllocator,
373 sizeof(ACCESS), AccessTableId);
374 createSystemDatabaseChunk(FixedSizeAllocator,
375 sizeof(INDEX), IndexTableId);
376 createSystemDatabaseChunk(FixedSizeAllocator,
377 sizeof(INDEXFIELD), IndexFieldTableId);
381 //used in case of system database
382 Chunk* Database::getSystemDatabaseChunk(int id)
384 size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
385 id * sizeof (Chunk);
386 return (Chunk*)(((char*) metaData_) + offset);
390 //used in case of system database
391 Transaction* Database::getSystemDatabaseTrans(int slot)
393 size_t offset = os::alignLong(sizeof (DatabaseMetaData)) +
394 os::alignLong(MAX_CHUNKS * sizeof (Chunk)) +
395 slot * sizeof (Transaction);
396 return (Transaction*)(((char*) metaData_) + offset);
399 //used in case of system database
400 ProcInfo* Database::getProcInfo(int pidSlot)
402 size_t offset = os::alignLong(sizeof (DatabaseMetaData));
403 offset = offset + os::alignLong( MAX_CHUNKS * sizeof (Chunk));
404 offset = offset + os::alignLong( config.getMaxTrans() * sizeof(Transaction));
405 offset = offset + pidSlot * sizeof (ProcInfo);
406 return (ProcInfo*)(((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( config.getMaxTrans() * sizeof(Transaction));
414 offset = offset + os::alignLong( 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 < 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();