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 ***************************************************************************/
17 #include<DatabaseManager.h>
18 #include<DatabaseManagerImpl.h>
22 #include<Transaction.h>
23 #include<CatalogTables.h>
31 DatabaseManagerImpl::~DatabaseManagerImpl()
33 //Note:Databases are closed by the session interface
35 ListIterator iter
= tableHandleList
.getIterator();
36 //PRABA::commented below...gives core dump
37 //while ((tbl = (Table *)iter.nextElement()) != NULL) delete tbl;
38 tableHandleList
.reset();
43 void DatabaseManagerImpl::createLockManager()
45 lMgr_
= new LockManager(systemDatabase_
);
49 void DatabaseManagerImpl::createTransactionManager()
52 tMgr_
= new TransactionManager();
53 tMgr_
->setFirstTrans(systemDatabase_
->getSystemDatabaseTrans(0));
56 void DatabaseManagerImpl::setProcSlot()
58 systemDatabase_
->setProcSlot(procSlot
);
59 db_
->setProcSlot(procSlot
);
61 DbRetVal
DatabaseManagerImpl::openSystemDatabase()
63 DbRetVal rv
= openDatabase(SYSTEMDB
);
64 if (rv
!= OK
) return rv
;
65 systemDatabase_
= db_
;
67 printDebug(DM_Database
, "Opened system database");
68 logFinest(logger
, "Opened system database");
72 DbRetVal
DatabaseManagerImpl::closeSystemDatabase()
75 //make them to point to system database file descriptor
76 //and database pointer
77 db_
= systemDatabase_
;
80 printDebug(DM_Database
, "Closed system database");
81 logFinest(logger
, "Closed System database");
85 DbRetVal
DatabaseManagerImpl::createDatabase(const char *name
, size_t size
)
89 printError(ErrAlready
, "Database is already created");
92 caddr_t rtnAddr
= (caddr_t
) NULL
;
93 shared_memory_id shm_id
= 0;
95 char *startaddr
= (char*)Conf::config
.getMapAddress();
96 shared_memory_key key
= 0;
97 if (0 == strcmp(name
, SYSTEMDB
))
100 key
= Conf::config
.getSysDbKey();
104 startaddr
= startaddr
+ Conf::config
.getMaxSysDbSize();
105 key
= Conf::config
.getUserDbKey();
107 shm_id
= os::shm_create(key
, size
, 0666);
110 if (errno
== EEXIST
) {
111 printError(ErrOS
, "Shared Memory already exists");
113 printError(ErrOS
, "Shared memory create failed");
117 void *shm_ptr
= os::shm_attach(shm_id
, startaddr
, SHM_RND
);
118 rtnAddr
= (caddr_t
) shm_ptr
;
119 if (rtnAddr
< 0 || shm_ptr
== (char*)0xffffffff)
121 printError(ErrOS
, "Shared memory attach returned -ve value %d", rtnAddr
);
124 memset(shm_ptr
, 0, size
);
125 db_
= new Database();
126 printDebug(DM_Database
, "Creating database:%s",name
);
128 //TODO:for user database do not have transtable and processtable mutex
129 db_
->setMetaDataPtr((DatabaseMetaData
*)rtnAddr
);
130 db_
->setDatabaseID(1);
132 db_
->setMaxSize(size
);
133 db_
->setNoOfChunks(0);
134 db_
->initAllocDatabaseMutex();
135 db_
->initTransTableMutex();
136 db_
->initDatabaseMutex();
137 db_
->initProcessTableMutex();
138 db_
->setUniqueChunkID(100);
139 //compute the first page after book keeping information
140 size_t offset
= os::alignLong(sizeof (DatabaseMetaData
));
141 //Only for system db chunk array, trans array and proc array will be there
142 if (0 == strcmp(name
, SYSTEMDB
))
144 offset
= offset
+ os::alignLong( MAX_CHUNKS
* sizeof (Chunk
));
145 offset
= offset
+ os::alignLong( Conf::config
.getMaxProcs() * sizeof(Transaction
));
146 offset
= offset
+ os::alignLong( Conf::config
.getMaxProcs() * sizeof(ThreadInfo
));
148 int multiple
= os::floor(offset
/ PAGE_SIZE
);
149 char *curPage
= (((char*)rtnAddr
) + ((multiple
+ 1) * PAGE_SIZE
));
151 db_
->setCurrentPage(curPage
);
152 db_
->setFirstPage(curPage
);
154 if (0 == strcmp(name
, SYSTEMDB
)) return OK
;
156 /*Allocate new chunk to store hash index nodes
157 Chunk *chunkInfo = createUserChunk(sizeof(HashIndexNode));
158 if (NULL == chunkInfo)
160 printError(ErrSysInternal, "Failed to allocate hash index nodes chunk");
161 return ErrSysInternal;
163 printDebug(DM_Database, "Creating Chunk for storing Hash index nodes %x",
166 db_->setHashIndexChunk(chunkInfo);*/
167 logFinest(logger
, "Created database %s" , name
);
172 DbRetVal
DatabaseManagerImpl::deleteDatabase(const char *name
)
174 shared_memory_id shm_id
= 0;
175 if (0 == strcmp(name
, SYSTEMDB
))
177 shm_id
= os::shm_open(Conf::config
.getSysDbKey(), 100, 0666);
178 os::shmctl(shm_id
, IPC_RMID
);
179 delete systemDatabase_
;
180 systemDatabase_
= NULL
;
182 shm_id
= os::shm_open(Conf::config
.getUserDbKey(), 100, 0666);
183 os::shmctl(shm_id
, IPC_RMID
);
187 logFinest(logger
, "Deleted database %s" , name
);
191 DbRetVal
DatabaseManagerImpl::openDatabase(const char *name
)
193 long size
= Conf::config
.getMaxSysDbSize();
194 char *startaddr
= (char*)Conf::config
.getMapAddress();
195 if (0 == strcmp(name
, SYSTEMDB
))
197 if (NULL
!=systemDatabase_
)
199 printError(ErrAlready
, "System Database already open");
205 if (NULL
==systemDatabase_
)
207 printError(ErrNotOpen
, "System Database not open");
210 size
= Conf::config
.getMaxDbSize();
211 startaddr
= startaddr
+ Conf::config
.getMaxSysDbSize();
215 printError(ErrAlready
, "User Database already open");
218 //system db should be opened before user database files
219 caddr_t rtnAddr
= (caddr_t
) NULL
;
221 shared_memory_id shm_id
= 0;
222 shared_memory_key key
= 0;
224 if (0 == strcmp(name
, SYSTEMDB
))
225 key
= Conf::config
.getSysDbKey();
227 key
= Conf::config
.getUserDbKey();
230 int ret
= ProcessManager::mutex
.getLock(-1, false);
231 //If you are not getting lock ret !=0, it means somebody else is there.
232 //he will close the database.
235 printError(ErrSysInternal
, "Another thread calling open:Wait and then Retry\n");
236 return ErrSysInternal
;
238 void *shm_ptr
= NULL
;
239 bool firstThread
= false;
240 //printf("PRABA::DEBUG:: opendb %d %s\n", ProcessManager::noThreads, name);
241 if (ProcessManager::noThreads
== 0 && 0 == strcmp(name
, SYSTEMDB
)
242 || ProcessManager::noThreads
== 1 && 0 != strcmp(name
, SYSTEMDB
) ) {
243 shm_id
= os::shm_open(key
, size
, 0666);
246 printError(ErrOS
, "Shared memory open failed");
247 ProcessManager::mutex
.releaseLock(-1, false);
250 shm_ptr
= os::shm_attach(shm_id
, startaddr
, SHM_RND
);
251 if (0 == strcmp(name
, SYSTEMDB
))
254 ProcessManager::sysAddr
= (char*) shm_ptr
;
258 ProcessManager::usrAddr
= (char*) shm_ptr
;
261 if (0 == strcmp(name
, SYSTEMDB
))
262 shm_ptr
= ProcessManager::sysAddr
;
264 shm_ptr
= ProcessManager::usrAddr
;
266 ProcessManager::mutex
.releaseLock(-1, false);
269 rtnAddr
= (caddr_t
) shm_ptr
;
271 if (rtnAddr
< 0 || shm_ptr
== (char*)0xffffffff)
273 printError(ErrOS
, "Shared memory attach returned -ve value %x %d", shm_ptr
, errno
);
276 db_
= new Database();
277 db_
->setMetaDataPtr((DatabaseMetaData
*)rtnAddr
);
279 if (firstThread
) ProcessManager::systemDatabase
= db_
;
281 printDebug(DM_Database
, "Opening database: %s", name
);
282 logFinest(logger
, "Opened database %s" , name
);
286 DbRetVal
DatabaseManagerImpl::closeDatabase()
291 //Database is already closed
294 printDebug(DM_Database
, "Closing database: %s",(char*)db_
->getName());
295 //check if this is the last thread to be deregistered
296 int ret
= ProcessManager::mutex
.getLock(-1, false);
297 //If you are not getting lock ret !=0, it means somebody else is there.
298 //he will close the database.
300 //printf("PRABA::FOR DEBUG closedb %d %s\n", ProcessManager::noThreads, (char*)db_->getName());
301 if (ProcessManager::noThreads
== 0 && 0 == strcmp((char*)db_
->getName(), SYSTEMDB
)
302 || ProcessManager::noThreads
== 1 && 0 != strcmp((char*)db_
->getName(), SYSTEMDB
) ) {
303 os::shm_detach((char*)db_
->getMetaDataPtr());
306 ProcessManager::mutex
.releaseLock(-1, false);
307 logFinest(logger
, "Closed database");
312 //Assumes that system database mutex is taken before calling this.
313 Chunk
* DatabaseManagerImpl::createUserChunk(size_t size
)
315 //Allocate new node in system database to store
316 Chunk
*chunk
= getSystemTableChunk(UserChunkTableId
);
318 void *ptr
= chunk
->allocate(systemDatabase_
, &rv
);
321 printError(rv
, "Allocation failed for User chunk catalog table");
324 Chunk
*chunkInfo
= (Chunk
*)ptr
;
325 chunkInfo
->initMutex();
326 if (0 != size
) chunkInfo
->setSize(size
);
327 if (chunkInfo
->allocSize_
> PAGE_SIZE
)
328 chunkInfo
->curPage_
= db_
->getFreePage(chunkInfo
->allocSize_
);
330 chunkInfo
->curPage_
= db_
->getFreePage();
331 if ( NULL
== chunkInfo
->curPage_
)
333 chunkInfo
->destroyMutex();
334 chunk
->free(db_
, ptr
);
335 printError(ErrNoMemory
, "Database full: No space to allocate from database");
338 PageInfo
* firstPageInfo
= ((PageInfo
*)chunkInfo
->curPage_
);
339 if (chunkInfo
->allocSize_
> PAGE_SIZE
)
341 int multiple
= os::floor(chunkInfo
->allocSize_
/ PAGE_SIZE
);
342 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
343 firstPageInfo
->setPageAsUsed(offset
);
347 firstPageInfo
->setPageAsUsed(chunkInfo
->allocSize_
);
348 char *data
= ((char*)firstPageInfo
) + sizeof(PageInfo
);
353 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)firstPageInfo
) + sizeof(PageInfo
));
354 varInfo
->isUsed_
= 0;
355 varInfo
->size_
= PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
);
358 chunkInfo
->firstPage_
= chunkInfo
->curPage_
;
361 chunkInfo
->setAllocType(VariableSizeAllocator
);
363 chunkInfo
->setAllocType(FixedSizeAllocator
);
365 //TODO::Generate chunkid::use tableid
366 chunkInfo
->setChunkID(db_
->getUniqueIDForChunk());
367 db_
->incrementChunk();
368 printDebug(DM_Database
, "Creating new User chunk chunkID:%d size: %d firstPage:%x",
369 -1, chunkInfo
->allocSize_
, firstPageInfo
);
374 //Assumes that system database mutex is taken before calling this.
375 DbRetVal
DatabaseManagerImpl::deleteUserChunk(Chunk
*chunk
)
377 //Go to the pages and set them to notUsed
378 Page
*page
= chunk
->firstPage_
;
379 PageInfo
* pageInfo
= ((PageInfo
*)page
);
380 //Here...sure that atleast one page will be there even no tuples
381 //are inserted.so not checking if pageInfo == NULL
382 while( pageInfo
->nextPage_
!= NULL
)
384 PageInfo
*prev
= pageInfo
;
385 pageInfo
= (PageInfo
*)(pageInfo
->nextPage_
);
386 //sets pageInfo->isUsed_ = 0 and pageInfo->hasFreeSpace_ = 0
387 //and initializes the page content to zero
388 if(NULL
== pageInfo
->nextPageAfterMerge_
)
389 os::memset(prev
, 0, PAGE_SIZE
);
392 int size
= (char*) pageInfo
->nextPageAfterMerge_
- (char*) pageInfo
;
393 os::memset(prev
, 0, size
);
395 printDebug(DM_Database
,"deleting user chunk:%x clearing page %x",chunk
, prev
);
397 //The above loop wont execute for the last page
398 //and for the case where table has only one page
399 if(NULL
== pageInfo
->nextPageAfterMerge_
)
400 os::memset(pageInfo
, 0, PAGE_SIZE
);
403 int size
= (char*) pageInfo
->nextPageAfterMerge_
- (char*) pageInfo
;
404 os::memset(pageInfo
, 0, size
);
406 printDebug(DM_Database
,"deleting user chunk:%x clearing page %x",chunk
, pageInfo
);
407 chunk
->chunkID_
= -1;
408 chunk
->allocSize_
= 0;
409 chunk
->curPage_
= NULL
;
410 chunk
->firstPage_
= NULL
;
411 chunk
->destroyMutex();
412 db_
->decrementChunk();
413 Chunk
*userChunk
= getSystemTableChunk(UserChunkTableId
);
414 userChunk
->free(systemDatabase_
,chunk
);
415 printDebug(DM_Database
,"deleting user chunk:%x",chunk
);
419 //-1 -> Unable to create chunk. No memory
420 //-2 -> Unable to update the catalog tables
421 DbRetVal
DatabaseManagerImpl::createTable(const char *name
, TableDef
&def
)
424 int fldCount
= def
.getFieldCount();
427 printError(ErrNotExists
,"Table can't be created without Field");
430 //If total field count is less than 32, then 1 integer is used to store all null
431 //information, if it is more then 1 char is used to store null information
433 //This is to done to reduce cpu cycles for small tables
435 if (fldCount
< 31) addSize
= 4; else addSize
= os::align(fldCount
);
436 size_t sizeofTuple
= os::align(def
.getTupleSize())+addSize
;
438 rv
= systemDatabase_
->getDatabaseMutex();
440 printError(rv
, "Unable to get Database mutex");
447 //check whether table already exists
448 CatalogTableTABLE
cTable(systemDatabase_
);
449 cTable
.getChunkAndTblPtr(name
, chunk
, tptr
);
452 systemDatabase_
->releaseDatabaseMutex();
453 printError(ErrAlready
, "Table %s already exists", name
);
457 //create a chunk to store the tuples
458 Chunk
*ptr
= createUserChunk(sizeofTuple
);
461 systemDatabase_
->releaseDatabaseMutex();
462 printError(ErrNoResource
, "Unable to create user chunk");
463 return ErrNoResource
;
465 printDebug(DM_Database
,"Created UserChunk:%x", ptr
);
466 ptr
->setChunkName(name
);
468 int tblID
= ((Chunk
*)ptr
)->getChunkID();
469 rv
= cTable
.insert(name
, tblID
, sizeofTuple
,
470 def
.getFieldCount(), ptr
, tptr
);
473 deleteUserChunk(ptr
);
474 systemDatabase_
->releaseDatabaseMutex();
475 printError(ErrSysInternal
, "Unable to update catalog table TABLE");
476 return ErrSysInternal
;
478 printDebug(DM_Database
,"Inserted into TABLE:%s",name
);
480 FieldIterator iter
= def
.getFieldIterator();
481 CatalogTableFIELD
cField(systemDatabase_
);
482 rv
= cField
.insert(iter
, tblID
,tptr
);
485 deleteUserChunk(ptr
);
486 void *cptr
, *ttptr
;//Dummy as remove below needs both these OUT params
487 cTable
.remove(name
, cptr
, ttptr
);
488 systemDatabase_
->releaseDatabaseMutex();
489 printError(ErrSysInternal
, "Unable to update catalog table FIELD");
490 return ErrSysInternal
;
492 printDebug(DM_Database
,"Inserted into FIELD:%s",name
);
493 systemDatabase_
->releaseDatabaseMutex();
494 printDebug(DM_Database
,"Table Created:%s",name
);
495 logFinest(logger
, "Table Created %s" , name
);
499 //TODO::If any operation fails in between, then we may have some
500 //dangling tuples, say we have have rows in INDEX table
501 //which will not have any corresponding entries in TABLE
502 //CHANGE the sequence so that it deletes from the bottom as
503 //opposed to start from top as is written now
504 DbRetVal
DatabaseManagerImpl::dropTable(const char *name
)
508 DbRetVal rv
= systemDatabase_
->getDatabaseMutex();
510 printError(ErrSysInternal
, "Unable to get database mutex");
511 return ErrSysInternal
;
514 //remove the entry in TABLE
515 CatalogTableTABLE
cTable(systemDatabase_
);
516 rv
= cTable
.getChunkAndTblPtr(name
, chunk
, tptr
);
518 systemDatabase_
->releaseDatabaseMutex();
519 printError(ErrSysInternal
, "Table %s does not exist", name
);
520 return ErrSysInternal
;
522 rv
= lMgr_
->getExclusiveLock(chunk
, NULL
);
525 systemDatabase_
->releaseDatabaseMutex();
526 printError(ErrLockTimeOut
, "Unable to acquire exclusive lock on the table\n");
530 rv
= cTable
.remove(name
, chunk
, tptr
);
532 systemDatabase_
->releaseDatabaseMutex();
533 printError(ErrSysInternal
, "Unable to update catalog table TABLE");
534 return ErrSysInternal
;
536 printDebug(DM_Database
,"Deleted from TABLE:%s",name
);
538 //remove the entries in the FIELD table
539 CatalogTableFIELD
cField(systemDatabase_
);
540 rv
= cField
.remove(tptr
);
542 systemDatabase_
->releaseDatabaseMutex();
543 printError(ErrSysInternal
, "Unable to update catalog table FIELD");
544 return ErrSysInternal
;
546 printDebug(DM_Database
,"Deleted from FIELD:%s",name
);
548 rv
= deleteUserChunk((Chunk
*)chunk
);
550 systemDatabase_
->releaseDatabaseMutex();
551 printError(rv
, "Unable to delete the chunk");
554 printDebug(DM_Database
,"Deleted UserChunk:%x", chunk
);
556 //TODO::check whether indexes are available and drop that also.
557 CatalogTableINDEX
cIndex(systemDatabase_
);
558 int noIndexes
= cIndex
.getNumIndexes(tptr
);
559 for (int i
=1 ; i
<= noIndexes
; i
++) {
560 char *idxName
= cIndex
.getIndexName(tptr
, 1);
561 dropIndexInt(idxName
, false);
563 Chunk
*chunkNode
= systemDatabase_
->getSystemDatabaseChunk(UserChunkTableId
);
564 chunkNode
->free(systemDatabase_
, (Chunk
*) chunk
);
565 systemDatabase_
->releaseDatabaseMutex();
566 printDebug(DM_Database
, "Deleted Table %s" , name
);
567 logFinest(logger
, "Deleted Table %s" , name
);
568 rv
= lMgr_
->releaseLock(chunk
);
571 printError(ErrLockTimeOut
, "Unable to release exclusive lock on the table\n");
577 //Return values: NULL for table not found
578 Table
* DatabaseManagerImpl::openTable(const char *name
)
581 //TODO::store table handles in list so that if it is
582 //not closed by the application. destructor shall close it.
583 TableImpl
*table
= new TableImpl();
585 table
->setSystemDB(systemDatabase_
);
586 table
->setLockManager(lMgr_
);
587 table
->setTrans(ProcessManager::getThreadTransAddr(systemDatabase_
->procSlot
));
589 //to store the chunk pointer of table
592 //to store the tuple pointer of the table
595 //TODO::need to take shared lock on the table so that
596 //all ddl operation will be denied on that table
597 //which includes index creation, alter table
599 DbRetVal rv
= systemDatabase_
->getDatabaseMutex();
601 printError(ErrSysInternal
, "Unable to get database mutex");
605 CatalogTableTABLE
cTable(systemDatabase_
);
606 ret
= cTable
.getChunkAndTblPtr(name
, chunk
, tptr
);
609 systemDatabase_
->releaseDatabaseMutex();
611 printError(ErrNotExists
, "Table not exists %s", name
);
614 CTABLE
*tTuple
= (CTABLE
*)tptr
;
615 table
->setTableInfo(tTuple
->tblName_
, tTuple
->tblID_
, tTuple
->length_
,
616 tTuple
->numFlds_
, tTuple
->numIndexes_
, tTuple
->chunkPtr_
);
617 /*rv = table->lock(true); //take shared lock
620 printError(ErrLockTimeOut, "Unable to acquire shared lock on the table\n");
621 systemDatabase_->releaseDatabaseMutex();
627 if (tTuple
->numFlds_
< 31)
629 table
->isIntUsedForNULL
= true;
630 table
->iNullInfo
= 0;
631 table
->iNotNullInfo
=0;
635 table
->isIntUsedForNULL
= false;
636 int noFields
= os::align(tTuple
->numFlds_
);
637 table
->cNullInfo
= (char*) malloc(noFields
);
638 table
->cNotNullInfo
= (char*) malloc(noFields
);
639 for (int i
=0 ; i
< noFields
; i
++) table
->cNullInfo
[i
] =0;
640 for (int i
=0 ; i
< noFields
; i
++) table
->cNotNullInfo
[i
] =0;
644 //get field information from FIELD table
645 CatalogTableFIELD
cField(systemDatabase_
);
646 cField
.getFieldInfo(tptr
, table
->fldList_
);
648 //populate the notnull info
649 FieldIterator fIter
= table
->fldList_
.getIterator();
651 while (fIter
.hasElement())
653 FieldDef def
= fIter
.nextElement();
654 if (table
->isIntUsedForNULL
) {
655 if (def
.isNull_
) SETBIT(table
->iNotNullInfo
, fldpos
);
658 if (def
.isNull_
) table
->cNotNullInfo
[fldpos
-1] = 1;
663 //get the number of indexes on this table
664 //and populate the indexPtr array
665 CatalogTableINDEX
cIndex(systemDatabase_
);
666 table
->numIndexes_
= cIndex
.getNumIndexes(tptr
);
667 if (table
->numIndexes_
) {
668 table
->indexPtr_
= new char*[table
->numIndexes_
];
669 table
->idxInfo
= new IndexInfo
*[table
->numIndexes_
];
673 table
->indexPtr_
= NULL
;
675 cIndex
.getIndexPtrs(tptr
, table
->indexPtr_
);
676 for (int i
=0 ; i
< table
->numIndexes_
; i
++ )
678 HashIndexInfo
*hIdxInfo
= new HashIndexInfo();
679 CatalogTableINDEXFIELD
cIndexField(systemDatabase_
);
680 cIndexField
.getFieldInfo(table
->indexPtr_
[i
], hIdxInfo
->idxFldList
);
681 ChunkIterator citer
= CatalogTableINDEX::getIterator(table
->indexPtr_
[i
]);
682 hIdxInfo
->indexPtr
= table
->indexPtr_
[i
];
683 hIdxInfo
->indType
= ((CINDEX
*)hIdxInfo
->indexPtr
)->indexType_
;
684 hIdxInfo
->noOfBuckets
= CatalogTableINDEX::getNoOfBuckets(table
->indexPtr_
[i
]);
685 FieldIterator fIter
= hIdxInfo
->idxFldList
.getIterator();
686 bool firstFld
= true;
687 while (fIter
.hasElement())
689 FieldDef def
= fIter
.nextElement();
692 hIdxInfo
->fldOffset
= table
->fldList_
.getFieldOffset(def
.fldName_
);
693 hIdxInfo
->type
= table
->fldList_
.getFieldType(def
.fldName_
);
694 hIdxInfo
->compLength
= table
->fldList_
.getFieldLength(def
.fldName_
);
697 hIdxInfo
->type
= typeComposite
;
698 hIdxInfo
->compLength
= hIdxInfo
->compLength
+
699 table
->fldList_
.getFieldLength(def
.fldName_
);
703 hIdxInfo
->isUnique
= CatalogTableINDEX::getUnique(table
->indexPtr_
[i
]);
704 hIdxInfo
->buckets
= (Bucket
*)citer
.nextElement();
705 table
->idxInfo
[i
] = (IndexInfo
*) hIdxInfo
;
707 systemDatabase_
->releaseDatabaseMutex();
708 // lMgr-> tTuple->chunkPtr_
709 printDebug(DM_Database
,"Opening table handle name:%s chunk:%x numIndex:%d",
710 name
, chunk
, table
->numIndexes_
);
711 logFinest(logger
, "Opening Table %s" , name
);
713 tableHandleList
.append(table
);
720 List
DatabaseManagerImpl::getAllTableNames()
723 //to store the tuple pointer of the table
726 DbRetVal rv
= systemDatabase_
->getDatabaseMutex();
728 printError(ErrSysInternal
, "Unable to get database mutex");
732 CatalogTableTABLE
cTable(systemDatabase_
);
733 List tableList
= cTable
.getTableList();
734 systemDatabase_
->releaseDatabaseMutex();
741 //Return values: -1 for table not found
742 void DatabaseManagerImpl::closeTable(Table
*table
)
744 printDebug(DM_Database
,"Closing table handle: %x", table
);
745 if (NULL
== table
) return;
747 tableHandleList
.remove(table
, false);
748 logFinest(logger
, "Closing Table");
751 DbRetVal
DatabaseManagerImpl::createIndex(const char *indName
, IndexInitInfo
*info
)
754 if (!info
->isUnique
&& info
->isPrimary
)
756 printError(ErrBadCall
, "Primary key cannot be non unique\n");
759 if (info
->indType
== hashIndex
)
761 //Assumes info is of type HashIndexInitInfo
762 HashIndexInitInfo
*hInfo
= (HashIndexInitInfo
*) info
;
763 rv
= createHashIndex(indName
, info
->tableName
, info
->list
, hInfo
->bucketSize
,
764 info
->isUnique
, info
->isPrimary
);
766 else if (info
->indType
== treeIndex
)
768 HashIndexInitInfo
*hInfo
= (HashIndexInitInfo
*) info
;
769 rv
= createTreeIndex(indName
, info
->tableName
, info
->list
,
770 hInfo
->bucketSize
, info
->isUnique
, info
->isPrimary
);
773 printError(ErrBadCall
, "Index type not supported\n");
780 //-1 -> Table does not exists
781 //-2 -> Field does not exists
782 //-3 -> bucketSize is not valid
783 DbRetVal
DatabaseManagerImpl::createHashIndex(const char *indName
, const char *tblName
,
784 FieldNameList
&fldList
, int bucketSize
, bool isUnique
, bool isPrimary
)
786 //validate the bucket size
787 if (bucketSize
< 100 || bucketSize
> 200000)
789 printError(ErrBadRange
, "Index Bucket size %d not in range 100-200000",
793 int totFlds
= fldList
.size();
796 printError(ErrBadCall
, "No Field name specified");
801 DbRetVal rv
= systemDatabase_
->getDatabaseMutex();
804 printError(ErrSysInternal
, "Unable to get database mutex");
805 return ErrSysInternal
;
808 //check whether table exists
809 CatalogTableTABLE
cTable(systemDatabase_
);
810 cTable
.getChunkAndTblPtr(tblName
, chunk
, tptr
);
813 systemDatabase_
->releaseDatabaseMutex();
814 printError(ErrNotExists
, "Table does not exist %s", tblName
);
818 //check whether field exists
819 char **fptr
= new char* [totFlds
];
820 CatalogTableFIELD
cField(systemDatabase_
);
821 rv
= cField
.getFieldPtrs(fldList
, tptr
, fptr
);
825 systemDatabase_
->releaseDatabaseMutex();
826 //TODO::check test cases of dbapi/Index, they give wrong results
827 //if (rv == ErrBadCall) {
828 //// if (isPrimary) printError(ErrBadCall, "Field can have NULL values");
830 //printError(ErrNotExists, "Field does not exist");
833 if (rv
!= ErrBadCall
) {
834 printError(ErrNotExists
, "Field does not exist");
838 for (int i
=0; i
<totFlds
; i
++)
840 CFIELD
* fInfo
= (CFIELD
*)fptr
[i
];
841 if (fInfo
->type_
== typeFloat
|| fInfo
->type_
== typeDouble
|| fInfo
->type_
== typeTimeStamp
)
843 printError(ErrBadArg
, "HashIndex cannot be created for float or double or timestamp type");
845 systemDatabase_
->releaseDatabaseMutex();
848 if (!fInfo
->isNull_
&& isPrimary
)
850 printError(ErrBadArg
, "Primary Index cannot be created on field without NOTNULL constraint");
852 systemDatabase_
->releaseDatabaseMutex();
855 if(isPrimary
){fInfo
->isPrimary_
=true;fInfo
->isUnique_
=true;}
856 if(isUnique
){fInfo
->isUnique_
=true;}
858 //create chunk to store the meta data of the index created
859 //for latches and bucket pointers
860 printDebug(DM_HashIndex
, "Creating chunk for storing hash buckets of size %d\n",
861 bucketSize
* sizeof(Bucket
));
862 Chunk
* chunkInfo
= createUserChunk(bucketSize
* sizeof(Bucket
));
863 if (NULL
== chunkInfo
)
866 systemDatabase_
->releaseDatabaseMutex();
867 printError(ErrSysInternal
, "Unable to create chunk");
868 return ErrSysInternal
;
870 chunkInfo
->setChunkName(indName
);
871 //create memory for holding the bucket pointers
872 void *buckets
= chunkInfo
->allocate(db_
, &rv
);
876 deleteUserChunk(chunkInfo
);
877 systemDatabase_
->releaseDatabaseMutex();
878 printError(rv
, "Unable to allocate memory for bucket");
881 Bucket
*buck
= (Bucket
*) buckets
;
882 initHashBuckets(buck
, bucketSize
);
884 //create chunk to store the hash index nodes
885 Chunk
* hChunk
= createUserChunk(sizeof(HashIndexNode
));
889 deleteUserChunk(chunkInfo
);
890 systemDatabase_
->releaseDatabaseMutex();
891 printError(ErrSysInternal
, "Unable to create chunk for storing hash index nodes");
892 return ErrSysInternal
;
894 hChunk
->setChunkName(indName
);
896 void *tupleptr
= NULL
;
897 CatalogTableINDEX
cIndex(systemDatabase_
);
898 rv
= cIndex
.insert(indName
, tptr
, fldList
.size(), isUnique
,
899 chunkInfo
, bucketSize
, hChunk
, tupleptr
);
903 deleteUserChunk(hChunk
);
904 deleteUserChunk(chunkInfo
);
905 systemDatabase_
->releaseDatabaseMutex();
906 printError(ErrSysInternal
, "Catalog table updation failed in INDEX table");
907 return ErrSysInternal
;
909 //add rows to INDEXFIELD
910 CatalogTableINDEXFIELD
cIndexField(systemDatabase_
);
911 rv
= cIndexField
.insert(fldList
, tupleptr
, tptr
, fptr
);
916 cIndex
.remove(indName
, (void *&)chunkInfo
, (void *&)hChunk
, (void *&)tupleptr
);
917 deleteUserChunk(hChunk
);
918 deleteUserChunk(chunkInfo
);
919 systemDatabase_
->releaseDatabaseMutex();
920 printError(ErrSysInternal
, "Catalog table updation failed in INDEXFIELD table");
921 return ErrSysInternal
;
924 systemDatabase_
->releaseDatabaseMutex();
926 //TODO:: Take table lock
928 // Following code is written by Kishor Amballi
929 TableImpl
*tbl
= (TableImpl
*) openTable(tblName
);
930 if (! tbl
->numTuples()) {
931 printDebug(DM_Database
, "Creating Hash Index Name:%s tblname:%s buckets:%x", indName
, tblName
, buckets
);
932 logFinest(logger
, "Creating HashIndex %s on %s with bucket size %d", indName
, tblName
, buckets
);
936 HashIndexInfo
*indxInfo
= NULL
;
938 for (i
= 0; i
< tbl
->numIndexes_
; i
++) {
939 if(((HashIndexInfo
*)tbl
->idxInfo
[i
])->indexPtr
== tupleptr
) {
940 indxInfo
= (HashIndexInfo
*) tbl
->idxInfo
[i
];
945 ChunkIterator chIter
= ((Chunk
*)chunk
)->getIterator();
946 while ((recPtr
= chIter
.nextElement()) != NULL
) {
947 rv
= tbl
->insertIndexNode(*tbl
->trans
, tupleptr
, indxInfo
, recPtr
);
948 if (rv
== ErrUnique
) {
955 printDebug(DM_Database
, "Creating Hash Index Name:%s tblname:%s buckets:%x", indName
, tblName
, buckets
);
956 logFinest(logger
, "Creating HashIndex %s on %s with bucket size %d", indName
, tblName
, buckets
);
961 DbRetVal
DatabaseManagerImpl::createTreeIndex(const char *indName
, const char *tblName
,
962 FieldNameList
&fldList
, int nodeSize
, bool isUnique
, bool isPrimary
)
964 if (nodeSize
< 20 || nodeSize
> 20000)
966 printError(ErrBadRange
,"Tree Index Node size %d not in range 20-20000",
970 int totFlds
= fldList
.size();
973 printError(ErrBadCall
, "No Field name specified");
978 DbRetVal rv
= systemDatabase_
->getDatabaseMutex();
981 printError(ErrSysInternal
, "Unable to get database mutex");
982 return ErrSysInternal
;
984 //check whether table exists
986 CatalogTableTABLE
cTable(systemDatabase_
);
987 cTable
.getChunkAndTblPtr(tblName
, chunk
, tptr
);
990 systemDatabase_
->releaseDatabaseMutex();
991 printError(ErrNotExists
, "Table does not exist %s", tblName
);
994 char **fptr
= new char* [totFlds
];
995 CatalogTableFIELD
cField(systemDatabase_
);
996 rv
= cField
.getFieldPtrs(fldList
, tptr
, fptr
);
1000 systemDatabase_
->releaseDatabaseMutex();
1001 if (rv
!= ErrBadCall
) {
1002 printError(ErrNotExists
, "Field does not exist");
1003 return ErrNotExists
;
1006 for (int i
=0; i
<totFlds
; i
++)
1008 CFIELD
* fInfo
= (CFIELD
*)fptr
[i
];
1009 if (!fInfo
->isNull_
&& isPrimary
)
1011 printError(ErrBadArg
, "Primary Index cannot be created on field without NOTNULL constraint");
1013 systemDatabase_
->releaseDatabaseMutex();
1017 int chunkSize
= sizeof(TreeNode
)+(nodeSize
* sizeof(void*));
1018 printDebug(DM_HashIndex
, "Creating chunk for storing tree nodes of size %d\n", chunkSize
);
1020 Chunk
* chunkInfo
= createUserChunk(chunkSize
);
1021 if (NULL
== chunkInfo
)
1024 systemDatabase_
->releaseDatabaseMutex();
1025 printError(ErrSysInternal
, "Unable to create chunk");
1026 return ErrSysInternal
;
1030 void *tupleptr
= NULL
;
1032 CatalogTableINDEX
cIndex(systemDatabase_
);
1033 rv
= cIndex
.insert(indName
, tptr
, fldList
.size(), isUnique
,
1034 chunkInfo
, nodeSize
, NULL
, tupleptr
);
1038 deleteUserChunk(chunkInfo
);
1039 systemDatabase_
->releaseDatabaseMutex();
1040 printError(ErrSysInternal
, "Catalog table updation failed in INDEX table");
1041 return ErrSysInternal
;
1043 CatalogTableINDEXFIELD
cIndexField(systemDatabase_
);
1044 rv
= cIndexField
.insert(fldList
, tupleptr
, tptr
, fptr
);
1049 void *hChunk
= NULL
;
1050 cIndex
.remove(indName
, (void *&)chunkInfo
, (void *&)hChunk
, (void *&)tupleptr
);
1051 deleteUserChunk(chunkInfo
);
1052 systemDatabase_
->releaseDatabaseMutex();
1053 printError(ErrSysInternal
, "Catalog table updation failed in INDEXFIELD table");
1054 return ErrSysInternal
;
1057 systemDatabase_
->releaseDatabaseMutex();
1058 //TODO::if tuples already present in this table, then create tree index '
1060 TableImpl
*tbl
= (TableImpl
*) openTable(tblName
);
1061 if (! tbl
->numTuples()) {
1062 printDebug(DM_Database
, "Creating Tree Index Name:%s tblname:%s node size:%x",indName
, tblName
, nodeSize
);
1063 logFinest(logger
, "Creating TreeIndex %s on %s with node size %d",indName
, tblName
, nodeSize
);
1066 HashIndexInfo
*indxInfo
= NULL
;
1068 for (i
= 0; i
< tbl
->numIndexes_
; i
++) {
1069 if(((HashIndexInfo
*)tbl
->idxInfo
[i
])->indexPtr
== tupleptr
) {
1070 indxInfo
= (HashIndexInfo
*) tbl
->idxInfo
[i
];
1074 void *recPtr
= NULL
;
1075 ChunkIterator chIter
= ((Chunk
*)chunk
)->getIterator();
1076 while ((recPtr
= chIter
.nextElement()) != NULL
) {
1077 rv
= tbl
->insertIndexNode(*tbl
->trans
, tupleptr
, indxInfo
, recPtr
);
1078 if (rv
== ErrUnique
) {
1086 printDebug(DM_Database
, "Creating Tree Index Name:%s tblname:%s node size:%x",
1087 indName
, tblName
, nodeSize
);
1088 logFinest(logger
, "Creating TreeIndex %s on %s with node size %d",
1089 indName
, tblName
, nodeSize
);
1095 void DatabaseManagerImpl::initHashBuckets(Bucket
*buck
, int bucketSize
)
1097 os::memset((void*)buck
, 0, bucketSize
* sizeof(Bucket
));
1099 for (int i
=0; i
< bucketSize
; i
++)
1101 buck
[i
].mutex_
.init("Bucket");
1106 DbRetVal
DatabaseManagerImpl::dropIndex(const char *name
)
1108 return dropIndexInt(name
, true);
1111 DbRetVal
DatabaseManagerImpl::dropIndexInt(const char *name
, bool takeLock
)
1114 void *chunk
= NULL
, *hchunk
= NULL
;
1118 rv
= systemDatabase_
->getDatabaseMutex();
1121 printError(ErrSysInternal
, "Unable to get database mutex");
1122 return ErrSysInternal
;
1126 //remove the entry in INDEX
1127 CatalogTableINDEX
cIndex(systemDatabase_
);
1128 rv
= cIndex
.remove(name
, chunk
, hchunk
, tptr
);
1131 if (takeLock
) systemDatabase_
->releaseDatabaseMutex();
1132 printError(ErrSysInternal
, "Catalog table updation failed for INDEX table");
1133 return ErrSysInternal
;
1135 printDebug(DM_Database
, "Removing from INDEX %s",name
);
1136 //remove the entries in the INDEXFIELD table
1137 CatalogTableINDEXFIELD
cIndexField(systemDatabase_
);
1138 rv
= cIndexField
.remove(tptr
);
1141 if (takeLock
) systemDatabase_
->releaseDatabaseMutex();
1142 printError(ErrSysInternal
, "Catalog table updation failed for INDEX table");
1143 return ErrSysInternal
;
1145 printDebug(DM_Database
, "Removing from INDEXFIELD %s",name
);
1147 //delete the index chunk
1148 CINDEX
*iptr
= (CINDEX
*)tptr
;
1149 rv
= deleteUserChunk((Chunk
*)chunk
);
1152 if (takeLock
) systemDatabase_
->releaseDatabaseMutex();
1153 printError(ErrSysInternal
, "Unable to delete the index chunk");
1154 return ErrSysInternal
;
1156 //delete the index hash node chunk
1157 if (iptr
->indexType_
== hashIndex
) {
1158 rv
= deleteUserChunk((Chunk
*)hchunk
);
1161 if (takeLock
) systemDatabase_
->releaseDatabaseMutex();
1162 printError(ErrSysInternal
, "Unable to delete the index hash node chunk");
1163 return ErrSysInternal
;
1166 if (takeLock
) systemDatabase_
->releaseDatabaseMutex();
1167 Chunk
*chunkNode
= systemDatabase_
->getSystemDatabaseChunk(UserChunkTableId
);
1168 chunkNode
->free(systemDatabase_
, (Chunk
*) chunk
);
1169 if (iptr
->indexType_
== hashIndex
) {
1170 chunkNode
->free(systemDatabase_
, (Chunk
*) hchunk
);
1173 //TODO::If tuples present in this table, then
1174 //free all hash index nodes for this table.
1175 //free all nodes in list of all buckets
1178 printDebug(DM_Database
, "Dropped hash index %s",name
);
1179 logFinest(logger
, "Deleted Index %s", name
);
1182 DbRetVal
DatabaseManagerImpl::printIndexInfo(char *name
)
1184 CatalogTableINDEX
cIndex(systemDatabase_
);
1186 void *chunk
= NULL
, *hchunk
= NULL
;
1188 rv
= cIndex
.get(name
, chunk
, hchunk
, tptr
);
1189 if (OK
!= rv
) return rv
;
1190 printf("<IndexName> %s </IndexName>\n", name
);
1191 printf("<Unique> %d </Unique>\n", CatalogTableINDEX::getUnique(tptr
));
1192 Chunk
*ch
= (Chunk
*) chunk
;
1193 printf("<HashBucket>\n");
1194 printf(" <TotalPages> %d </TotalPages>\n", ch
->totalPages());
1195 printf(" <TotalBuckets> %d </TotalBuckets> \n", CatalogTableINDEX::getNoOfBuckets(tptr
));
1196 printf("</HashBucket>\n");
1198 ch
= (Chunk
*) hchunk
;
1199 printf("<IndexNodes>\n");
1200 printf(" <TotalPages> %d </TotalPages>\n", ch
->totalPages());
1201 printf(" <TotalNodes> %d </TotalNodes>\n", ch
->getTotalDataNodes());
1202 printf("<IndexNodes>\n");
1206 DbRetVal
DatabaseManagerImpl::registerThread()
1211 printError(ErrAlready
, "Process already registered\n");
1214 pMgr_
= new ProcessManager();
1215 rv
= pMgr_
->registerThread();
1216 if (rv
==OK
) { procSlot
= pMgr_
->getProcSlot();
1217 printDebug(DM_Process
, "Process registed with slot %d\n", procSlot
);
1222 DbRetVal
DatabaseManagerImpl::deregisterThread()
1227 rv
= pMgr_
->deregisterThread(procSlot
);
1234 bool DatabaseManagerImpl::isAnyOneRegistered()
1236 if (pMgr_
!= NULL
) return pMgr_
->isAnyOneRegistered();
1241 void DatabaseManagerImpl::printUsageStatistics()
1243 pMgr_
->printUsageStatistics();
1244 tMgr_
->printUsageStatistics();
1245 lMgr_
->printUsageStatistics();
1248 void DatabaseManagerImpl::printDebugLockInfo()
1250 lMgr_
->printDebugInfo();
1253 void DatabaseManagerImpl::printDebugTransInfo()
1255 tMgr_
->printDebugInfo(systemDatabase_
);
1257 void DatabaseManagerImpl::printDebugProcInfo()
1259 pMgr_
->printDebugInfo();
1261 void DatabaseManagerImpl::printDebugChunkInfo()
1263 printf("<NotYetImplemented> </NotYetImplemented>\n");
1265 ChunkIterator
DatabaseManagerImpl::getSystemTableIterator(CatalogTableID id
)
1267 Chunk
*fChunk
= systemDatabase_
->getSystemDatabaseChunk(id
);
1268 return fChunk
->getIterator();
1271 Chunk
* DatabaseManagerImpl::getSystemTableChunk(CatalogTableID id
)
1273 return systemDatabase_
->getSystemDatabaseChunk(id
);