1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
18 #include<CatalogTables.h>
19 #include<Transaction.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();
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();
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();
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();
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
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
);
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);
200 if (!isValidAddress(((char*) pageInfo
) + PAGE_SIZE
))
202 printError(ErrSysInternal
, "Invalid address %x",((char*) pageInfo
) + PAGE_SIZE
);
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
);
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
);
230 pageInfo
= (PageInfo
*)pageInfo
->nextPageAfterMerge_
;
231 printDebug(DM_Alloc
,"Merged Page:Moving to page:%x",pageInfo
);
235 PageInfo
*pInfo
= pageInfo
;
236 if (!isValidAddress(((char*)pInfo
) + offset
))
238 printError(ErrSysInternal
,"Invalid address %x",((char*)pInfo
) + offset
);
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
257 DbRetVal
Database::createSystemDatabaseChunk(AllocType type
, size_t size
, int id
)
263 printError(ErrSysFatal
, "Database ID corrupted");
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_
);
273 chunk
->curPage_
= getFreePage();
274 if ( chunk
->curPage_
== NULL
)
276 //releaseDatabaseMutex();
277 printError(ErrNoMemory
, "No free pages in database: Database full");
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
;
299 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)firstPageInfo
) + sizeof(PageInfo
));
300 varInfo
->isUsed_
= 0;
301 varInfo
->size_
= PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
);
304 //releaseDatabaseMutex();
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);
314 chunk
->setAllocType(UnknownAllocator
);
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
;
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
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
,
355 createSystemDatabaseChunk(FixedSizeAllocator
,
356 sizeof(LockHashNode
), LockTableId
);
357 createSystemDatabaseChunk(FixedSizeAllocator
,
358 sizeof(TransHasNode
), TransHasTableId
);
360 createSystemDatabaseChunk(VariableSizeAllocator
,
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
)) +
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();
424 printError(rv, "Unable to get process table mutex from Database::isLastThread()");
429 ThreadInfo *tInfo = getThreadInfo(pid, 0);
431 for (int i=0; i < Conf::config.getMaxThreads(); i++)
433 if (0 != tInfo->thrid_) regThr++;
436 releaseProcessTableMutex();
437 if (regThr < 1) return true;
442 bool Database::isValidAddress(void* addr
)
444 if ((char*) addr
> ((char*)getMetaDataPtr()) + getMaxSize())
450 //should be called only on system database
451 void* Database::allocLockHashBuckets()
453 Chunk
*chunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
454 void *ptr
= chunk
->allocate(this);
457 printError(ErrNoMemory
, "Chunk Allocation failed for lock hash bucket catalog table");
462 Bucket
* Database::getLockHashBuckets()
464 Chunk
*tChunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
465 ChunkIterator iter
= tChunk
->getIterator();
466 return (Bucket
*)iter
.nextElement();