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>
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();
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();
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();
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();
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
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
);
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
);
201 if (!isValidAddress(((char*) pageInfo
) + PAGE_SIZE
))
203 printError(ErrSysInternal
, "Invalid address %x",((char*) pageInfo
) + PAGE_SIZE
);
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
);
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
);
231 pageInfo
= (PageInfo
*)pageInfo
->nextPageAfterMerge_
;
232 printDebug(DM_Alloc
,"Merged Page:Moving to page:%x",pageInfo
);
236 PageInfo
*pInfo
= pageInfo
;
237 if (!isValidAddress(((char*)pInfo
) + offset
))
239 printError(ErrSysInternal
,"Invalid address %x",((char*)pInfo
) + offset
);
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
258 DbRetVal
Database::createSystemDatabaseChunk(AllocType type
, size_t size
, int id
)
264 printError(ErrSysFatal
, "Database ID corrupted");
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_
);
274 chunk
->curPage_
= getFreePage();
275 if ( chunk
->curPage_
== NULL
)
277 //releaseDatabaseMutex();
278 printError(ErrNoMemory
, "No free pages in database: Database full");
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
;
300 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)firstPageInfo
) + sizeof(PageInfo
));
301 varInfo
->isUsed_
= 0;
302 varInfo
->size_
= PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
);
305 //releaseDatabaseMutex();
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);
315 chunk
->setAllocType(UnknownAllocator
);
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
;
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
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
,
356 createSystemDatabaseChunk(FixedSizeAllocator
,
357 sizeof(LockHashNode
), LockTableId
);
358 createSystemDatabaseChunk(FixedSizeAllocator
,
359 sizeof(TransHasNode
), TransHasTableId
);
361 createSystemDatabaseChunk(VariableSizeAllocator
,
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
)) +
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();
424 printError(rv
, "Unable to get process table mutex from Database::isLastThread()");
429 ThreadInfo
*tInfo
= getThreadInfo(pid
, 0);
431 for (int i
=0; i
< 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();