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 long Database::getMaxSize()
37 return metaData_
->maxSize_
;
40 long 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::getNoOfChunks()
57 return metaData_
->noOfChunks_
;
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(long 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(long size
)
86 metaData_
->maxSize_
= size
;
88 void Database::setNoOfChunks(int chunks
)
90 metaData_
->noOfChunks_
= chunks
;
92 void Database::setHashIndexChunk(Chunk
*ch
)
94 metaData_
->hashIndexChunk_
= ch
;
98 int Database::initAllocDatabaseMutex()
100 return metaData_
->dbAllocMutex_
.init("allocdb");
102 DbRetVal
Database::getAllocDatabaseMutex(bool procAccount
)
104 int ret
= metaData_
->dbAllocMutex_
.getLock(procAccount
);
105 if (ret
) return ErrLockTimeOut
; else return OK
;
107 DbRetVal
Database::releaseAllocDatabaseMutex(bool procAccount
)
109 metaData_
->dbAllocMutex_
.releaseLock(procAccount
);
115 int Database::initTransTableMutex()
117 return metaData_
->dbTransTableMutex_
.init("transtable");
119 DbRetVal
Database::getTransTableMutex()
121 int ret
= metaData_
->dbTransTableMutex_
.getLock(procSlot
);
122 if (ret
) return ErrLockTimeOut
; else return OK
;
124 DbRetVal
Database::releaseTransTableMutex()
126 metaData_
->dbTransTableMutex_
.releaseLock(procSlot
);
132 int Database::initProcessTableMutex()
134 return metaData_
->dbProcTableMutex_
.init("proctable");
136 DbRetVal
Database::getProcessTableMutex(bool procAccount
)
138 int ret
= metaData_
->dbProcTableMutex_
.getLock(-1, procAccount
);
139 if (ret
) return ErrLockTimeOut
; else return OK
;
141 DbRetVal
Database::releaseProcessTableMutex(bool procAccount
)
143 metaData_
->dbProcTableMutex_
.releaseLock(-1, procAccount
);
149 int Database::initDatabaseMutex()
151 return metaData_
->dbMutex_
.init("db");
153 DbRetVal
Database::getDatabaseMutex(bool procAccount
)
155 int ret
= metaData_
->dbMutex_
.getLock(procSlot
, procAccount
);
156 if (ret
) return ErrLockTimeOut
; else return OK
;
158 DbRetVal
Database::releaseDatabaseMutex(bool procAccount
)
160 metaData_
->dbMutex_
.releaseLock(procSlot
, procAccount
);
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 Page
* page
= getCurrentPage();
179 //printDebug(DM_Alloc, "Database::getFreePage firstPage:%x",page);
180 printDebug(DM_Alloc
, "Database::getFreePage currentpage:%x",page
);
181 PageInfo
* pageInfo
= ((PageInfo
*)page
);
182 char* endAddr
= ((char*)getMetaDataPtr()) + getMaxSize();
183 int pageSize
= PAGE_SIZE
;
184 while( 1 == pageInfo
->isUsed_
)
186 //If any pages are merged to store data larger than PAGE_SIZE
187 //move to the next page after the merge and check whether it is used
188 if ( pageInfo
->nextPageAfterMerge_
== NULL
) {
189 pageInfo
= (PageInfo
*)((char*)pageInfo
+ pageSize
);
190 printDebug(DM_Alloc
,"Normal Page:Moving to page:%x",pageInfo
);
193 pageInfo
= (PageInfo
*)pageInfo
->nextPageAfterMerge_
;
194 printDebug(DM_Alloc
,"Merged Page:Moving to page:%x",pageInfo
);
196 if ((char*)pageInfo
>= endAddr
)
198 //printError(ErrSysInternal,"Invalid address %x",pageInfo);
203 if (!isValidAddress(((char*) pageInfo
) + pageSize
))
205 printError(ErrSysInternal
, "Invalid address %x",((char*) pageInfo
) + pageSize
);
208 setCurrentPage((Page
*) pageInfo
);
209 printDebug(DM_Alloc
,"Database::getFreePage returning page:%x",pageInfo
);
210 return (Page
*) pageInfo
;
213 //Used by tuples more than PAGE_SIZE
214 //NOTE::IMPORTANT::assumes alloc database lock is taken before calling this
215 Page
* Database::getFreePage(size_t size
)
217 Page
* page
= getFirstPage();
218 PageInfo
* pageInfo
= ((PageInfo
*)page
);
219 int multiple
= size
/ PAGE_SIZE
;
220 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
221 printDebug(DM_Alloc
, "Database::getFreePage firstPage:%x size:%ld",page
, size
);
222 char* endAddr
= ((char*)getMetaDataPtr()) + getMaxSize();
223 int pageSize
= PAGE_SIZE
;
225 while( 1 == pageInfo
->isUsed_
)
227 //If any pages are merged to store data larger than PAGE_SIZE
228 //move to the next page after the merge and check whether it is used
229 if ( pageInfo
->nextPageAfterMerge_
== NULL
) {
230 pageInfo
= (PageInfo
*)((char*)pageInfo
+ pageSize
);
231 printDebug(DM_Alloc
,"Normal Page:Moving to page:%x",pageInfo
);
234 pageInfo
= (PageInfo
*)pageInfo
->nextPageAfterMerge_
;
235 printDebug(DM_Alloc
,"Merged Page:Moving to page:%x",pageInfo
);
239 PageInfo
*pInfo
= pageInfo
;
240 if ((((char*)pInfo
) + offset
) >= endAddr
)
242 printError(ErrSysInternal
,"Invalid address %x",((char*)pInfo
) + offset
);
245 for (i
= 0; i
< multiple
+ 1; i
++)
247 if (1 == pInfo
->isUsed_
) break;
248 pInfo
= (PageInfo
*)((char*)pInfo
+ pageSize
);
250 if ( i
== (multiple
+ 1)) break;
251 pageInfo
= (PageInfo
*)((char*)pInfo
+ pageSize
);
254 printDebug(DM_Alloc
,"Database::getFreePage returning page:%x",pageInfo
);
255 setCurrentPage((Page
*) pageInfo
);
256 return (Page
*) pageInfo
;
259 void Database::printStatistics()
261 Page
* page
= getFirstPage();
262 PageInfo
* pageInfo
= ((PageInfo
*)page
);
263 int usedPageCount
=0, usedMergedPageCount
=0, totalPages
=0;
264 printf("<DatabaseStatistics>\n");
265 printf(" <Database Name> %s </Database Name>\n", getName());
266 printf(" <Max Size> %ld </Max Size>\n", getMaxSize());
267 printf(" <First Page> %x </First Page>\n", getFirstPage());
268 while(isValidAddress((char*) pageInfo
))
270 if (pageInfo
== NULL
) break;
271 if (1 == pageInfo
->isUsed_
) {
272 if ( pageInfo
->nextPageAfterMerge_
== NULL
) {
273 pageInfo
= (PageInfo
*)((char*)pageInfo
+ PAGE_SIZE
);
274 usedPageCount
++; totalPages
++;
275 printDebug(DM_Alloc
, "Normal Page:Moving to page:%x\n",pageInfo
);
279 pageInfo
= (PageInfo
*)pageInfo
->nextPageAfterMerge_
;
280 usedMergedPageCount
++; totalPages
++;
281 printDebug(DM_Alloc
,"Merged Page:Moving to page:%x\n",pageInfo
);
285 pageInfo
= (PageInfo
*)((char*)pageInfo
+ PAGE_SIZE
);
286 printDebug(DM_Alloc
,"Normal Page not used:Moving to page:%x\n",pageInfo
);
289 printf(" <Total Pages> %d </Total Pages>\n", totalPages
);
290 printf(" <Used Normal Pages> %d </Used Normal Pages>\n", usedPageCount
);
291 printf(" <Used Merged Pages> %d </Used Merged Pages>\n", usedMergedPageCount
);
292 printf(" <Chunks Used> %d </Chunks Used>\n", getNoOfChunks());
293 printf("</DatabaseStatistics>\n");
299 //called only in case of system database to create and initialize the chunk
301 DbRetVal
Database::createSystemDatabaseChunk(AllocType type
, size_t size
, int id
)
307 printError(ErrSysFatal
, "Database ID corrupted");
310 chunk
= getSystemDatabaseChunk(id
);
312 chunk
->setChunkNameForSystemDB(id
);
314 if (FixedSizeAllocator
== type
) chunk
->setSize(size
);
315 //getDatabaseMutex();
316 if (chunk
->allocSize_
> PAGE_SIZE
)
317 chunk
->curPage_
= getFreePage(chunk
->allocSize_
);
319 chunk
->curPage_
= getFreePage();
320 if ( chunk
->curPage_
== NULL
)
322 //releaseDatabaseMutex();
323 printError(ErrNoMemory
, "No free pages in database: Database full");
327 chunk
->firstPage_
= chunk
->curPage_
;
328 PageInfo
* firstPageInfo
= ((PageInfo
*)chunk
->firstPage_
);
329 firstPageInfo
->setFirstPageAsUsed();
330 chunk
->setChunkID(id
);
331 chunk
->setAllocType(type
);
332 printDebug(DM_Database
, "Creating System Database Chunk:%d Size:%d",id
, chunk
->allocSize_
);
333 if (chunk
->allocSize_
> PAGE_SIZE
)
335 int multiple
= os::floor(chunk
->allocSize_
/ PAGE_SIZE
);
336 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
337 firstPageInfo
->nextPageAfterMerge_
= ((char*)firstPageInfo
)+ offset
;
342 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)firstPageInfo
) + sizeof(PageInfo
));
343 varInfo
->isUsed_
= 0;
344 varInfo
->size_
= PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
);
348 //releaseDatabaseMutex();
352 //This is never called currently. If situation arises will be coded later.
353 DbRetVal
Database::deleteSystemDatabaseChunk(int id
)
356 Chunk
*chunk
= getSystemDatabaseChunk(id
);
357 chunk
->setChunkID(-1);
359 chunk
->setAllocType(UnknownAllocator
);
362 //walk though the pageList ptr and get all the page pointers
363 //then free all the pages used to store this by setting the
364 //start of page to notused
365 chunk
->firstPage_
= NULL
;
366 chunk
->curPage_
= NULL
;
372 void Database::createAllCatalogTables()
374 //These are special chunks which hold catalog tables and other information
376 // chunk id 0 ->userChunkTable
377 // chunk id 1 ->lockBucketHash
378 // chunk id 2 ->lockTable
380 // chunk id 10->DATABASE
382 // chunk id 12->TABLE
383 // chunk id 13->FIELD
384 // chunk id 14->ACCESS
386 createSystemTables();
387 createMetaDataTables();
389 void Database::createSystemTables()
391 createSystemDatabaseChunk(FixedSizeAllocator
,
392 sizeof(Chunk
), UserChunkTableId
);
393 createSystemDatabaseChunk(FixedSizeAllocator
,
394 sizeof(Bucket
) * LOCK_BUCKET_SIZE
,
395 LockTableHashBucketId
);
396 createSystemDatabaseChunk(FixedSizeAllocator
,
397 sizeof(Mutex
)* LOCK_BUCKET_SIZE
,
399 createSystemDatabaseChunk(FixedSizeAllocator
,
400 sizeof(LockHashNode
), LockTableId
);
401 createSystemDatabaseChunk(FixedSizeAllocator
,
402 sizeof(TransHasNode
), TransHasTableId
);
404 createSystemDatabaseChunk(VariableSizeAllocator
,
407 void Database::createMetaDataTables()
409 createSystemDatabaseChunk(FixedSizeAllocator
,
410 sizeof(DATABASEFILE
), DatabaseTableId
);
411 createSystemDatabaseChunk(FixedSizeAllocator
,
412 sizeof(USER
), UserTableId
);
413 createSystemDatabaseChunk(FixedSizeAllocator
,
414 sizeof(TABLE
), TableTableId
);
415 createSystemDatabaseChunk(FixedSizeAllocator
,
416 sizeof(FIELD
), FieldTableId
);
417 createSystemDatabaseChunk(FixedSizeAllocator
,
418 sizeof(ACCESS
), AccessTableId
);
419 createSystemDatabaseChunk(FixedSizeAllocator
,
420 sizeof(INDEX
), IndexTableId
);
421 createSystemDatabaseChunk(FixedSizeAllocator
,
422 sizeof(INDEXFIELD
), IndexFieldTableId
);
425 //used in case of system database
426 Chunk
* Database::getSystemDatabaseChunk(int id
)
428 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
)) +
430 return (Chunk
*)(((char*) metaData_
) + offset
);
434 //used in case of system database
435 Transaction
* Database::getSystemDatabaseTrans(int slot
)
437 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
)) +
438 os::alignLong(MAX_CHUNKS
* sizeof (Chunk
)) +
439 slot
* sizeof (Transaction
);
440 return (Transaction
*)(((char*) metaData_
) + offset
);
443 //used in case of system database
444 ThreadInfo
* Database::getThreadInfo(int slot
)
446 /* size_t offset = os::alignLong(sizeof (DatabaseMetaData));
447 offset = offset + os::alignLong( MAX_CHUNKS * sizeof (Chunk));
448 offset = offset + os::alignLong( Conf::config.getMaxProcs() * sizeof(Transaction));
449 offset = offset + slot * sizeof (ThreadInfo);
450 return (ThreadInfo*)(((char*) metaData_) + offset);
453 static size_t offset
= os::alignLong(sizeof (DatabaseMetaData
)) +
454 os::alignLong( MAX_CHUNKS
* sizeof (Chunk
)) +
455 os::alignLong( Conf::config
.getMaxProcs()*sizeof(Transaction
));
457 size_t off
= offset
+ slot
* sizeof (ThreadInfo
);
458 return (ThreadInfo
*)(((char*) metaData_
) + off
);
462 bool Database::isValidAddress(void* addr
)
464 if ((char*) addr
>= ((char*)getMetaDataPtr()) + getMaxSize())
470 //should be called only on system database
471 void* Database::allocLockHashBuckets()
473 Chunk
*chunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
474 void *ptr
= chunk
->allocate(this);
477 printError(ErrNoMemory
, "Chunk Allocation failed for lock hash bucket catalog table");
482 Bucket
* Database::getLockHashBuckets()
484 Chunk
*tChunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
485 ChunkIterator iter
= tChunk
->getIterator();
486 return (Bucket
*)iter
.nextElement();
488 void Database::setUniqueChunkID(int id
)
490 (metaData_
->chunkUniqueID_
).setID(id
);
493 int Database::getUniqueIDForChunk()
495 return ((metaData_
->chunkUniqueID_
).getID());