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
->setFirstPageAsUsed();
284 chunk
->setChunkID(id
);
285 chunk
->setAllocType(type
);
286 printDebug(DM_Database
, "Creating System Database Chunk:%d Size:%d",id
, chunk
->allocSize_
);
287 if (chunk
->allocSize_
> PAGE_SIZE
)
289 int multiple
= os::floor(chunk
->allocSize_
/ PAGE_SIZE
);
290 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
291 firstPageInfo
->nextPageAfterMerge_
= ((char*)firstPageInfo
)+ offset
;
296 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)firstPageInfo
) + sizeof(PageInfo
));
297 varInfo
->isUsed_
= 0;
298 varInfo
->size_
= PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
);
301 //releaseDatabaseMutex();
305 //This is never called currently. If situation arises will be coded later.
306 DbRetVal
Database::deleteSystemDatabaseChunk(int id
)
308 Chunk
*chunk
= getSystemDatabaseChunk(id
);
309 chunk
->setChunkID(-1);
311 chunk
->setAllocType(UnknownAllocator
);
314 //walk though the pageList ptr and get all the page pointers
315 //then free all the pages used to store this by setting the
316 //start of page to notused
317 chunk
->firstPage_
= NULL
;
318 chunk
->curPage_
= NULL
;
323 void Database::createAllCatalogTables()
325 //These are special chunks which hold catalog tables and other information
327 // chunk id 0 ->userChunkTable
328 // chunk id 1 ->lockBucketHash
329 // chunk id 2 ->lockTable
331 // chunk id 10->DATABASE
333 // chunk id 12->TABLE
334 // chunk id 13->FIELD
335 // chunk id 14->ACCESS
337 createSystemTables();
338 createMetaDataTables();
340 void Database::createSystemTables()
342 createSystemDatabaseChunk(FixedSizeAllocator
,
343 sizeof(Chunk
), UserChunkTableId
);
344 createSystemDatabaseChunk(FixedSizeAllocator
,
345 sizeof(Bucket
) * LOCK_BUCKET_SIZE
,
346 LockTableHashBucketId
);
347 createSystemDatabaseChunk(FixedSizeAllocator
,
348 sizeof(Mutex
)* LOCK_BUCKET_SIZE
,
350 createSystemDatabaseChunk(FixedSizeAllocator
,
351 sizeof(LockHashNode
), LockTableId
);
352 createSystemDatabaseChunk(FixedSizeAllocator
,
353 sizeof(TransHasNode
), TransHasTableId
);
355 createSystemDatabaseChunk(VariableSizeAllocator
,
358 void Database::createMetaDataTables()
360 createSystemDatabaseChunk(FixedSizeAllocator
,
361 sizeof(DATABASEFILE
), DatabaseTableId
);
362 createSystemDatabaseChunk(FixedSizeAllocator
,
363 sizeof(USER
), UserTableId
);
364 createSystemDatabaseChunk(FixedSizeAllocator
,
365 sizeof(TABLE
), TableTableId
);
366 createSystemDatabaseChunk(FixedSizeAllocator
,
367 sizeof(FIELD
), FieldTableId
);
368 createSystemDatabaseChunk(FixedSizeAllocator
,
369 sizeof(ACCESS
), AccessTableId
);
370 createSystemDatabaseChunk(FixedSizeAllocator
,
371 sizeof(INDEX
), IndexTableId
);
372 createSystemDatabaseChunk(FixedSizeAllocator
,
373 sizeof(INDEXFIELD
), IndexFieldTableId
);
376 //used in case of system database
377 Chunk
* Database::getSystemDatabaseChunk(int id
)
379 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
)) +
381 return (Chunk
*)(((char*) metaData_
) + offset
);
385 //used in case of system database
386 Transaction
* Database::getSystemDatabaseTrans(int slot
)
388 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
)) +
389 os::alignLong(MAX_CHUNKS
* sizeof (Chunk
)) +
390 slot
* sizeof (Transaction
);
391 return (Transaction
*)(((char*) metaData_
) + offset
);
394 //used in case of system database
395 ThreadInfo
* Database::getThreadInfo(int slot
)
397 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
));
398 offset
= offset
+ os::alignLong( MAX_CHUNKS
* sizeof (Chunk
));
399 offset
= offset
+ os::alignLong( Conf::config
.getMaxTrans() * sizeof(Transaction
));
400 offset
= offset
+ slot
* sizeof (ThreadInfo
);
401 return (ThreadInfo
*)(((char*) metaData_
) + offset
);
404 bool Database::isValidAddress(void* addr
)
406 if ((char*) addr
> ((char*)getMetaDataPtr()) + getMaxSize())
412 //should be called only on system database
413 void* Database::allocLockHashBuckets()
415 Chunk
*chunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
416 void *ptr
= chunk
->allocate(this);
419 printError(ErrNoMemory
, "Chunk Allocation failed for lock hash bucket catalog table");
424 Bucket
* Database::getLockHashBuckets()
426 Chunk
*tChunk
= getSystemDatabaseChunk(LockTableHashBucketId
);
427 ChunkIterator iter
= tChunk
->getIterator();
428 return (Bucket
*)iter
.nextElement();