From efef73016956c8ed7e24a0eb6c968fe8d91c9bee Mon Sep 17 00:00:00 2001 From: kishoramballi Date: Thu, 8 Oct 2009 07:04:47 +0000 Subject: [PATCH] Update in sync with enterprise version. --- src/network/Makefile.am | 6 +- src/network/NetworkPacket.cxx | 91 ++- src/network/NetworkTable.cxx | 1 + src/network/SqlNetworkHandler.cxx | 511 +++++++----- src/network/TCPClient.cxx | 87 ++- src/network/TCPServer.cxx | 147 +--- src/network/UDPClient.cxx | 4 +- src/network/UDPServer.cxx | 1 + src/sqllog/FileSend.cxx | 70 +- src/sqllog/Makefile.am | 2 +- src/sqllog/SqlLogConnection.cxx | 120 ++- src/sqllog/SqlLogStatement.cxx | 116 ++- src/sqlnetwork/Makefile.am | 2 +- src/sqlnetwork/SqlNwConnection.cxx | 48 +- src/sqlnetwork/SqlNwStatement.cxx | 344 +++++++-- src/storage/AggTableImpl.cxx | 585 ++++++++++---- src/storage/BucketIter.cxx | 3 +- src/storage/BucketList.cxx | 48 +- src/storage/CatalogTables.cxx | 378 ++++++++- src/storage/Chunk.cxx | 487 ++++++++---- src/storage/ChunkIterator.cxx | 73 +- src/storage/Config.cxx | 174 +---- src/storage/Connection.cxx | 13 +- src/storage/DataType.cxx | 602 ++++++++------- src/storage/Database.cxx | 121 ++- src/storage/DatabaseManagerImpl.cxx | 635 +++++++++++++-- src/storage/Debug.cxx | 68 +- src/storage/Expression.cxx | 2 +- src/storage/FieldList.cxx | 28 +- src/storage/FixedHeapAllocator.cxx | 118 +++ src/storage/HashIndex.cxx | 231 +++--- src/storage/HashMap.cxx | 65 ++ src/storage/JoinTableImpl.cxx | 259 +++++-- src/storage/LockManager.cxx | 604 +++++++++++---- src/storage/Logger.cxx | 12 +- src/storage/Makefile.am | 8 +- src/storage/Mutex.cxx | 182 ++++- src/storage/OrderByTree.cxx | 130 ++++ src/storage/OrderTableImpl.cxx | 452 +++++++++++ src/storage/PageInfo.cxx | 62 +- src/storage/PredicateImpl.cxx | 296 ++++++- src/storage/Process.cxx | 42 +- src/storage/SessionImpl.cxx | 31 +- src/storage/TableConfig.cxx | 1455 ++++++++++++----------------------- src/storage/TableDef.cxx | 16 +- src/storage/TableImpl.cxx | 888 ++++++++++++++++----- src/storage/Transaction.cxx | 88 ++- src/storage/TransactionManager.cxx | 98 ++- src/storage/TreeIndex.cxx | 1336 ++++++++++++++++++++++++-------- src/storage/TreeIter.cxx | 243 ++++-- src/storage/TupleIterator.cxx | 162 ++-- src/storage/UserManagerImpl.cxx | 22 +- src/storage/Util.cxx | 25 +- src/storage/VarHeapAllocator.cxx | 202 +++++ src/storage/os.cxx | 10 + 55 files changed, 8285 insertions(+), 3519 deletions(-) create mode 100644 src/storage/FixedHeapAllocator.cxx create mode 100644 src/storage/HashMap.cxx create mode 100644 src/storage/OrderByTree.cxx create mode 100644 src/storage/OrderTableImpl.cxx rewrite src/storage/TableConfig.cxx (76%) create mode 100644 src/storage/VarHeapAllocator.cxx diff --git a/src/network/Makefile.am b/src/network/Makefile.am index 0de5bce3..7f19fed9 100644 --- a/src/network/Makefile.am +++ b/src/network/Makefile.am @@ -1,9 +1,7 @@ INCLUDES = -I$(top_srcdir)/include $(all_includes) METASOURCES = AUTO -lib_LTLIBRARIES = libcsqlnw.la -libcsqlnw_la_LDFLAGS = -avoid-version -module +lib_LTLIBRARIES = libcsqlnw.la +libcsqlnw_la_LDFLAGS = -version-info 2:4:0 -module libcsqlnw_la_SOURCES = NetworkTable.cxx UDPClient.cxx TCPClient.cxx \ NetworkPacket.cxx SqlNetworkHandler.cxx UDPServer.cxx \ TCPServer.cxx - -libcsqlnw_a_LIBADD = $(top_builddir)/src/sql/libcsql.la diff --git a/src/network/NetworkPacket.cxx b/src/network/NetworkPacket.cxx index 1c93f4c2..bea718d4 100644 --- a/src/network/NetworkPacket.cxx +++ b/src/network/NetworkPacket.cxx @@ -107,11 +107,13 @@ SqlPacketExecute::SqlPacketExecute() { buffer=NULL; bufferSize =0; pktType = NW_PKT_EXECUTE; paramValues = NULL; nullInfo = NULL; + noParams=0; stmtID=0; + for (int i=0; i < 10; i++) localBuf[i] =0; } SqlPacketExecute::~SqlPacketExecute() { if(noParams >= 10) delete [] paramValues; - nullInfo = NULL; + if (nullInfo) { free(nullInfo); nullInfo = NULL; } free(buffer); bufferSize =0; buffer = NULL; @@ -262,6 +264,7 @@ DbRetVal PacketCommit::unmarshall() stmtBuffer[i] = bufIter; bufIter = bufIter + stmtBufSize[i]; } + return OK; } //call unmarshall before calling this void PacketCommit::getExecPacketList(List stmtList, List &list) @@ -280,23 +283,34 @@ void PacketCommit::getExecPacketList(List stmtList, List &list) DbRetVal SqlPacketConnect::marshall() { + printDebug(DM_Network, "SqlPacketConnect::marshall called"); char *ptr = buffer; // moves over buffer strncpy(ptr, userName, IDENTIFIER_LENGTH); + printDebug(DM_Network, "Username: %s", userName); ptr = buffer+IDENTIFIER_LENGTH-1; *ptr++ = '\0'; strncpy(ptr, passWord, IDENTIFIER_LENGTH); + printDebug(DM_Network, "Password: %s", passWord); ptr = ptr + IDENTIFIER_LENGTH-1; *ptr++ = '\0'; - *ptr = sqlApiImplType; + *ptr++ = sqlApiImplType; + printDebug(DM_Network, "SqlPacketConnect::marshall Ended"); return OK; } DbRetVal SqlPacketConnect::unmarshall() { + printDebug(DM_Network, "SqlPacketConnect::unmarshall called"); char *ptr = buffer; + strncpy(userName, ptr, IDENTIFIER_LENGTH); - strncpy(passWord, ptr + IDENTIFIER_LENGTH, IDENTIFIER_LENGTH); - sqlApiImplType = *(ptr + 2 * IDENTIFIER_LENGTH); + printDebug(DM_Network, "Username: %s", userName); + ptr += IDENTIFIER_LENGTH; + strncpy(passWord, ptr, IDENTIFIER_LENGTH); + printDebug(DM_Network, "Password: %s", passWord); + ptr += IDENTIFIER_LENGTH; + sqlApiImplType = *ptr++; + printDebug(DM_Network, "SqlPacketConnect::unmarshall Ended"); return OK; } @@ -390,7 +404,10 @@ DbRetVal SqlPacketExecute::unmarshall() if (stmt->stmtID == stmtID ) break; } if (noParams == 0) return OK; - paramValues = new char*[noParams]; + if (noParams <10 ) + paramValues = localBuf; + else + paramValues = new char*[noParams]; ListIterator paramIter = stmt->paramList.getIterator(); BindSqlField *bindField = NULL; for (int i=0; i isDefault = bindField->isDefault; fldInfo->isUnique = bindField->isUnique; strcpy(fldInfo->defaultValueBuf, bindField->defaultValueBuf); + fldInfo->aType = bindField->aType; *(FieldInfo *) bufIter = *fldInfo; bufIter += sizeof(FieldInfo); } @@ -529,6 +547,7 @@ DbRetVal SqlPacketFetch::marshall() DbRetVal SqlPacketFetch::unmarshall() { stmtID = *(int *)buffer; + return OK; } DbRetVal SqlPacketFree::marshall() @@ -542,6 +561,7 @@ DbRetVal SqlPacketFree::marshall() DbRetVal SqlPacketFree::unmarshall() { stmtID = *(int *)buffer; + return OK; } DbRetVal SqlPacketResultSet::marshall() @@ -607,3 +627,64 @@ DbRetVal SqlPacketShowTables::unmarshall() data = buffer; return OK; } + +DbRetVal SqlPacketIsTablePresent::marshall() +{ + bufferSize = IDENTIFIER_LENGTH + sizeof(int); + buffer = (char*) malloc(bufferSize); + char *ptr = buffer; + strncpy(ptr, tblName, IDENTIFIER_LENGTH); + ptr += IDENTIFIER_LENGTH; + return OK; +} + +DbRetVal SqlPacketIsTablePresent::unmarshall() +{ + char *ptr = buffer; + strncpy(tblName, buffer, IDENTIFIER_LENGTH); + ptr += IDENTIFIER_LENGTH; + return OK; +} + +DbRetVal SqlPacketGetRecords::marshall() +{ + printDebug(DM_Network, "SqlPacketGetRecords: marshall called"); + bufferSize = IDENTIFIER_LENGTH; + printDebug(DM_Network, "Buffer Size = %d", bufferSize); + buffer = (char *) malloc(bufferSize); + printDebug(DM_Network, "start of the buffer is %x", buffer); + strncpy(buffer, tblName, IDENTIFIER_LENGTH); + printDebug(DM_Network, "SqlPacketGetRecords: marshall Ended"); + return OK; +} + +DbRetVal SqlPacketGetRecords::unmarshall() +{ + printDebug(DM_Network, "SqlPacketGetRecords: unmarshall called"); + strncpy(tblName, buffer, IDENTIFIER_LENGTH); + printDebug(DM_Network, "TableName %s", buffer); + printDebug(DM_Network, "SqlPacketGetRecords: unmarshall Ended"); + return OK; +} + +DbRetVal SqlPacketLoadRecords::marshall() +{ + printDebug(DM_Network, "SqlPacketLoadRecords:marshall called"); + bufferSize = sizeof (int) + PAGE_SIZE * pages; + printDebug(DM_Network, "Buffer Size = %d", bufferSize); + buffer = (char *) malloc(bufferSize); + printDebug(DM_Network, "start of the buffer is %x", buffer); + *(int *) buffer = pages; + printDebug(DM_Network, "SqlPacketLoadRecords: marshall Ended"); + return OK; +} + +DbRetVal SqlPacketLoadRecords::unmarshall() +{ + printDebug(DM_Network, "SqlPacketLoadRecords: unmarshall called"); + pages = *(int *) buffer; + printDebug(DM_Network, "No of pages to be loaded: %d", pages); + printDebug(DM_Network, "SqlPacketLoadRecords: unmarshall Ended"); + return OK; +} + diff --git a/src/network/NetworkTable.cxx b/src/network/NetworkTable.cxx index 12bbd069..cba8aed7 100644 --- a/src/network/NetworkTable.cxx +++ b/src/network/NetworkTable.cxx @@ -17,6 +17,7 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include #include #include diff --git a/src/network/SqlNetworkHandler.cxx b/src/network/SqlNetworkHandler.cxx index 08068704..bb11e5bc 100644 --- a/src/network/SqlNetworkHandler.cxx +++ b/src/network/SqlNetworkHandler.cxx @@ -18,6 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include +#include #include #include #include @@ -39,50 +40,67 @@ void *SqlNetworkHandler::process(PacketHeader &header, char *buffer) { DbRetVal rv = OK; char *ptr = NULL; - ResponsePacket *rpkt = NULL; + void *rpkt = NULL; switch(header.packetType) { - // case NW_PKT_PREPARE: - //return processPrepare(header, buffer); - // break; - //case NW_PKT_COMMIT: - //return processCommit(header, buffer); - // break; case SQL_NW_PKT_CONNECT: - return processSqlConnect(header, buffer); + rpkt = processSqlConnect(header, buffer); + break; + case SQL_NW_PKT_EXECDIRECT: + rpkt = processSqlExecuteDirect(header, buffer); break; case SQL_NW_PKT_PREPARE: - return processSqlPrepare(header, buffer); + rpkt = processSqlPrepare(header, buffer); break; case SQL_NW_PKT_EXECUTE: - return processSqlExecute(header, buffer); + rpkt = processSqlExecute(header, buffer); break; case SQL_NW_PKT_FETCH: - return processSqlFetch(header); + rpkt = processSqlFetch(header); break; case SQL_NW_PKT_COMMIT: - return processSqlCommit(header, buffer); + rpkt = processSqlCommit(header, buffer); break; case SQL_NW_PKT_ROLLBACK: - return processSqlRollback(header, buffer); + rpkt = processSqlRollback(header, buffer); break; case SQL_NW_PKT_DISCONNECT: - conn->rollback(); - rv = conn->disconnect(); - rpkt = new ResponsePacket(); - ptr = (char *) &rpkt->retVal; - *ptr = 1; - strcpy(rpkt->errorString, "Success"); - return rpkt; + rpkt = processSqlDisconnect(header); + break; case SQL_NW_PKT_FREE: - return processSqlFree(header, buffer); + rpkt = processSqlFree(header, buffer); break; case SQL_NW_PKT_SHOWTABLES: - return processSqlShowTables(header, buffer); - break; + rpkt = processSqlShowTables(header, buffer); + break; + case SQL_NW_PKT_ISTABLEPRESENT: + rpkt = processSqlIsTablePresent(header, buffer); + break; + case SQL_NW_PKT_GETRECORDS: + rpkt = processSqlLoadRecords(header, buffer); + break; } + if (rpkt != NULL) sendResponse(rpkt); + return rpkt; } - + +DbRetVal SqlNetworkHandler::sendResponse(void *rpkt) +{ + size_t numbytes = os::send(sockfd, rpkt, sizeof(ResponsePacket), 0); + if (numbytes == -1) { + printError(ErrOS, "Error writing to socket\n"); + closeConnection(); + exit(1); + } + return OK; +} + +DbRetVal SqlNetworkHandler::closeConnection() +{ + conn->rollback(); + return conn->disconnect(); +} + void * SqlNetworkHandler::processSqlConnect(PacketHeader &header, char *buffer) { ResponsePacket *rpkt = new ResponsePacket(); @@ -96,18 +114,67 @@ void * SqlNetworkHandler::processSqlConnect(PacketHeader &header, char *buffer) char *ptr = (char *) &rpkt->retVal; DbRetVal rv=conn->connect(pkt->userName, pkt->passWord); if (rv != OK) { - *ptr = 0; + //*ptr = 0; rpkt->errRetVal = rv; fillErrorString(rpkt); + delete pkt; return rpkt; } if (rv == OK) { - *ptr = 1; + //*ptr = 1; rv = conn->beginTrans(); + delete pkt; return rpkt; } } +void * SqlNetworkHandler::processSqlDisconnect(PacketHeader &header) +{ + DbRetVal rv = conn->rollback(); + rv = conn->disconnect(); + ResponsePacket *rpkt = new ResponsePacket(); + char *ptr = (char *) &rpkt->retVal; + //*ptr = 1; + strcpy(rpkt->errorString, "Success"); + return rpkt; +} + +void* SqlNetworkHandler::processSqlExecuteDirect(PacketHeader &header, char *buffer) +{ + ResponsePacket *rpkt = new ResponsePacket(); + rpkt->isSelect = false; + char *retval = (char *) &rpkt->retVal; + SqlPacketPrepare *pkt = new SqlPacketPrepare(); + pkt->setBuffer(buffer); + pkt->setBufferSize(header.packetLength); + pkt->unmarshall(); + printDebug(DM_Network, "EXECDIRECT %s\n", pkt->stmtString); + AbsSqlStatement *sqlstmt = createStatement(type); + sqlstmt->setConnection(conn); + NetworkStmt *nwStmt = new NetworkStmt(); + nwStmt->stmtID = ++stmtID; + printDebug(DM_Network, "Statement string %s\n", pkt->stmtString); + nwStmt->stmt = sqlstmt; + DbRetVal rv = sqlstmt->executeDirect(pkt->stmtString); + delete pkt; + if (rv != OK) + { + printError(ErrSysInit, "ExecuteDirect failed\n"); + rpkt->errRetVal = rv; + fillErrorString(rpkt); + if (rpkt->errorString[0] == '\0') + strcpy(rpkt->errorString, "Prepare failed."); + delete nwStmt; + delete sqlstmt; + return rpkt; + } + + stmtList.append(nwStmt); + rpkt->stmtID = nwStmt->stmtID; + strcpy(rpkt->errorString, "Success"); + return rpkt; +} + void* SqlNetworkHandler::processSqlPrepare(PacketHeader &header, char *buffer) { ResponsePacket *rpkt = new ResponsePacket(); @@ -125,14 +192,22 @@ void* SqlNetworkHandler::processSqlPrepare(PacketHeader &header, char *buffer) printDebug(DM_Network, "Statement string %s\n", pkt->stmtString); nwStmt->stmt = sqlstmt; DbRetVal rv = sqlstmt->prepare(pkt->stmtString); + delete pkt; if (rv != OK) { printError(ErrSysInit, "statement prepare failed\n"); - *retval = 0; rpkt->errRetVal = rv; fillErrorString(rpkt); + if (rpkt->errorString[0] == '\0') + strcpy(rpkt->errorString, "Prepare failed."); + delete nwStmt; + delete sqlstmt; return rpkt; } + //TODO: need to change retVal name + ResultSetPlan plan = sqlstmt->getResultSetPlan(); + *retval = plan; + int param = sqlstmt->noOfParamFields(); int proj = sqlstmt->noOfProjFields(); BindSqlField *bindField = NULL; @@ -151,7 +226,9 @@ void* SqlNetworkHandler::processSqlPrepare(PacketHeader &header, char *buffer) bindField->isPrimary = fInfo->isPrimary; bindField->isDefault = fInfo->isDefault; bindField->isUnique = fInfo->isUnique; - bindField->value = AllDataType::alloc(bindField->type, bindField->length); + bindField->isUnique = fInfo->isUnique; + //bindField->value = AllDataType::alloc(bindField->type, bindField->length); + bindField->value = NULL; nwStmt->paramList.append(bindField); } delete fInfo; @@ -164,16 +241,17 @@ void* SqlNetworkHandler::processSqlPrepare(PacketHeader &header, char *buffer) projField->length = fldInfo->length; projField->offset = fldInfo->offset; strcpy(projField->defaultValueBuf, fldInfo->defaultValueBuf); + projField->aType = fldInfo->aType; projField->isNull = fldInfo->isNull; projField->isPrimary = fldInfo->isPrimary; projField->isDefault = fldInfo->isDefault; projField->isUnique = fldInfo->isUnique; projField->value = AllDataType::alloc(projField->type, projField->length); + memset(projField->value, 0, projField->length); nwStmt->projList.append(projField); } delete fldInfo; stmtList.append(nwStmt); - *retval = 1; if(sqlstmt->isSelect()) rpkt->isSelect = true; if (param) *(retval+2) = 1; if (proj) *(retval+3) = 1; @@ -218,28 +296,20 @@ void * SqlNetworkHandler::processSqlExecute(PacketHeader &header, char *buffer) sqlstmt->bindField(i+1, prjFld->value); } } + delete pkt; DbRetVal rv = sqlstmt->execute(rows); if (rv != OK) { - *retval = 0; rpkt->errRetVal = rv; fillErrorString(rpkt); - // delete pkt; return rpkt; } - *retval = 1; rpkt->rows = rows; strcpy(rpkt->errorString, "Success"); - //delete pkt; return rpkt; } void * SqlNetworkHandler::processSqlFetch(PacketHeader &header) { - //ResponsePacket *rpkt = new ResponsePacket(); - //char *retval = (char *) &rpkt->retVal; - //SqlPacketFetch *pkt = new SqlPacketFetch(); - //pkt->setBuffer(buffer); - //pkt->unmarshall(); ListIterator stmtIter = stmtList.getIterator(); NetworkStmt *stmt; SqlPacketResultSet *rspkt = new SqlPacketResultSet(); @@ -283,16 +353,17 @@ void * SqlNetworkHandler::processSqlFetch(PacketHeader &header) if(len == 0) len = rspkt->getBufferSize(); int numbytes = os::send(sockfd, &len , 4, 0); - if (len == 1 || len == 2) { ::free (nullInfo); return NULL; } + if (len == 1 || len == 2) { delete rspkt; ::free (nullInfo); return NULL; } int dummy =0; - numbytes = os::recv(sockfd, &dummy, 4, 0); + //numbytes = os::recv(sockfd, &dummy, 4, 0); numbytes = os::send(sockfd,rspkt->getMarshalledBuffer(), rspkt->getBufferSize(), 0); + delete rspkt; if (numbytes == -1) { printf("Error in sending the row to the client\n"); ::free (nullInfo); sqlstmt->free(); - delete sqlstmt; + delete sqlstmt; sqlstmt= NULL; conn->disconnect(); exit(1); } @@ -309,28 +380,42 @@ void * SqlNetworkHandler::processSqlFree(PacketHeader &header, char *buffer) pkt->unmarshall(); rpkt->stmtID = pkt->stmtID; ListIterator stmtIter = stmtList.getIterator(); - NetworkStmt *stmt; + NetworkStmt *stmt = NULL; while (stmtIter.hasElement()) { stmt = (NetworkStmt*) stmtIter.nextElement(); //TODO::Also check teh srcNetworkID if (stmt->stmtID == pkt->stmtID ) break; } + if (stmt == NULL) + { + printError(ErrWarning, "Statement already freed."); + delete pkt; + rpkt->errRetVal = ErrAlready; + return rpkt; + } AbsSqlStatement *sqlstmt = stmt->stmt; - sqlstmt->free(); + if (sqlstmt) sqlstmt->free(); ListIterator itprm = stmt->paramList.getIterator(); BindSqlField *fld = NULL; - while((fld = (BindSqlField *) itprm.nextElement()) != NULL) delete fld; + while((fld = (BindSqlField *) itprm.nextElement()) != NULL) { + //if (fld->value) free(fld->value); memory never allocated for this + delete fld; + } stmt->paramList.reset(); ListIterator itprj = stmt->projList.getIterator(); BindSqlProjectField *pfld = NULL; - while((pfld = (BindSqlProjectField *) itprj.nextElement()) != NULL) delete pfld; + while((pfld = (BindSqlProjectField *) itprj.nextElement()) != NULL) { + if (pfld->value) free(pfld->value); + delete pfld; + } stmt->projList.reset(); delete stmt->stmt; + stmt->stmt = NULL; stmtList.remove(stmt); delete stmt; + stmt= NULL; delete pkt; - *retval = 1; strcpy(rpkt->errorString, "Success"); return rpkt; } @@ -342,12 +427,11 @@ void * SqlNetworkHandler::processSqlCommit(PacketHeader &header, char *buffer) char *retval = (char *) &rpkt->retVal; DbRetVal rv = conn->commit(); if (rv != OK) { - *retval = 0; + rpkt->errRetVal = rv; strcpy(rpkt->errorString, "Commit failure\n"); return rpkt; } rv = conn->beginTrans(); - *retval = 1; strcpy(rpkt->errorString, "Success"); return rpkt; } @@ -356,153 +440,17 @@ void *SqlNetworkHandler::processSqlRollback(PacketHeader &header, char *buffer) { ResponsePacket *rpkt = new ResponsePacket(); char *retval = (char *) &rpkt->retVal; - DbRetVal rv = conn->rollback(); if (rv != OK) { - *retval = 0; + rpkt->errRetVal = rv; strcpy(rpkt->errorString, "Rollback failure\n"); return rpkt; } rv = conn->beginTrans(); - *retval = 1; strcpy(rpkt->errorString, "Success"); return rpkt; } -/* -void *SqlNetworkHandler::processCommit(PacketHeader &header, char *buffer) -{ - printDebug(DM_Network, "Processing COMMIT"); - PacketCommit *pkt = new PacketCommit(); - pkt->setBuffer(buffer); - pkt->setBufferSize(header.packetLength); - pkt->unmarshall(); - List pktList; - pkt->getExecPacketList(stmtList, pktList); - DbRetVal rv = applyExecPackets(stmtList, pktList); - int response = 1; - if (rv != OK) - { - printError(ErrSysFatal, "Unable to apply the exec packets\n"); - response =0; - } - return response; - -} -void * SqlNetworkHandler::processFree(PacketHeader &header, char *buffer) -{ - PacketFree *pkt = new PacketFree(); - pkt->setBuffer(buffer); - pkt->setBufferSize(header.packetLength); - pkt->unmarshall(); - //printf("FREE %d \n", pkt->stmtID); - int response =1; - //This wont work for two statement executed in same transaction using same SqlStatement object using free. - //so do not delete now and put a flag 'readyfordelete' in NetworkStmt object and delete it during execute -// - ListIterator iter = stmtList.getIterator(); - NetworkStmt *stmt, *removeStmt = NULL; - while (iter.hasElement()) - { - stmt = (NetworkStmt*)iter.nextElement(); - if (stmt->srcNetworkID == header.srcNetworkID - && stmt->stmtID == pkt->stmtID) - { - removeStmt = stmt; - break; - } - } - if (removeStmt) stmtList.remove(removeStmt); - else printf("Statement id %d not found in list \n", pkt->stmtID); - - return response; -} -void * SqlNetworkHandler::processPrepare(PacketHeader &header, char *buffer) -{ - PacketPrepare *pkt = new PacketPrepare(); - pkt->setBuffer(buffer); - pkt->setBufferSize(header.packetLength); - pkt->unmarshall(); - printDebug(DM_Network, "PREPARE %d %s\n", pkt->stmtID, pkt->stmtString); - //for (int i =0 ; i < pkt->noParams; i++) - //printf("PREPARE type %d length %d \n", pkt->type[i], pkt->length[i]); - int response =1; - //TODO::add it to the SqlStatement list - AbsSqlStatement *sqlstmt = SqlFactory::createStatement(type); - sqlstmt->setConnection(conn); - NetworkStmt *nwStmt = new NetworkStmt(); - printDebug(DM_Network, "Statement string %s\n", pkt->stmtString); - nwStmt->srcNetworkID = header.srcNetworkID; - nwStmt->stmtID = pkt->stmtID; - nwStmt->stmt = sqlstmt; - DbRetVal rv = sqlstmt->prepare(pkt->stmtString); - if (rv != OK) - { - printError(ErrSysInit, "statement prepare failed\n"); - response = 0; - return response; - } - BindSqlField *bindField = NULL; - //populate paramList - for (int i = 0; i < pkt->noParams; i++) - { - bindField = new BindSqlField(); - bindField->type = (DataType) pkt->type[i]; - bindField->length = pkt->length[i]; - bindField->value = AllDataType::alloc(bindField->type, - bindField->length); - nwStmt->paramList.append(bindField); - } - stmtList.append(nwStmt); - return response; - -} -DbRetVal SqlNetworkHandler::applyExecPackets(List sList, List pList) -{ - ListIterator stmtIter = sList.getIterator(); - NetworkStmt *nwstmt; - DbRetVal rv = conn->beginTrans(); - if (rv != OK) return rv; - ListIterator pktIter = pList.getIterator(); - PacketExecute *pkt; - int i = 0; - BindSqlField *bindField; - while (pktIter.hasElement()) - { - pkt = (PacketExecute*) pktIter.nextElement(); - stmtIter.reset(); - bool found = false; - while (stmtIter.hasElement()) - { - nwstmt = (NetworkStmt*) stmtIter.nextElement(); - if (nwstmt->stmtID == pkt->stmtID) {found = true ; break;} - } - if (!found) { - printf("stmt not found in list. Negleting unreplicated table...\n"); - continue; - } - ListIterator paramIter = nwstmt->paramList.getIterator(); - i = 0; - while (paramIter.hasElement()) { - bindField = (BindSqlField*) paramIter.nextElement(); - setParamValues(nwstmt->stmt, i+1, bindField->type, bindField->length, pkt->paramValues[i]); - i++; - } - int rows= 0; - DbRetVal rv = nwstmt->stmt->execute(rows); - if (rv != OK ) - { - printError(ErrSysFatal, "sql execute failed with rv %d\n", rv); - //TODO::log all things like SQL statements to a file - SqlNetworkHandler::conn->rollback(); - printError(ErrPeerExecFailed, "Transaction Rolledback\n"); - return ErrPeerExecFailed; - } - } - SqlNetworkHandler::conn->commit(); - return OK; -} -*/ void SqlNetworkHandler::setParamValues(AbsSqlStatement *stmt, int parampos, DataType type, int length, char *value) { @@ -599,14 +547,75 @@ void * SqlNetworkHandler::processSqlShowTables(PacketHeader &header, char *buffe sqlstmt->setConnection(conn); DbRetVal rv = OK; tableNameList = sqlstmt->getAllTableNames(rv); - *retval = 1; - rpkt->stmtID = 0; + rpkt->errRetVal = rv; rpkt->rows = tableNameList.size(); strcpy(rpkt->errorString, "Success"); delete sqlstmt; return rpkt; } +//only csql connection asks for this with or without durability. +void *SqlNetworkHandler::processSqlIsTablePresent(PacketHeader &header, char *buffer) +{ + ResponsePacket *rpkt = new ResponsePacket(); + rpkt->isSelect = false; + SqlPacketIsTablePresent *pkt = new SqlPacketIsTablePresent(); + pkt->setBuffer(buffer); + pkt->unmarshall(); + SqlStatement *sqlstmt = new SqlStatement(); + SqlConnection *sqlcon = NULL; + if (Conf::config.useDurability()) + sqlcon = (SqlConnection *) conn->getInnerConnection(); + else sqlcon = (SqlConnection *) conn; + sqlstmt->setSqlConnection(sqlcon); + DbRetVal rv = OK; bool found = false; + tableNameList = sqlstmt->getAllTableNames(rv); + ListIterator it = tableNameList.getIterator(); + while (it.hasElement()) { + Identifier *elem = (Identifier *) it.nextElement(); + if (strcmp(elem->name, pkt->tblName) == 0) { + found = true; + break; + } + } + rpkt->errRetVal = rv; + if (!found) { + rpkt->errRetVal = ErrNotFound; + strcpy(rpkt->errorString, "Table Not found."); + } + ListIterator tblIter = SqlNetworkHandler::tableNameList.getIterator(); + while (tblIter.hasElement()) delete tblIter.nextElement(); + SqlNetworkHandler::tableNameList.reset(); + delete pkt; + delete sqlstmt; + return rpkt; +} + +//only csql connection asks for this with or without durability. +void *SqlNetworkHandler::processSqlLoadRecords(PacketHeader &header, char *buffer) +{ + ResponsePacket *rpkt = new ResponsePacket(); + rpkt->isSelect = false; + char *retval = (char *) &rpkt->retVal; + SqlPacketGetRecords *pkt = new SqlPacketGetRecords(); + pkt->setBuffer(buffer); + pkt->unmarshall(); + SqlStatement *sqlstmt = new SqlStatement(); + SqlConnection *sqlcon = NULL; + if (Conf::config.useDurability()) + sqlcon = (SqlConnection *) conn->getInnerConnection(); + else sqlcon = (SqlConnection *) conn; + sqlstmt->setSqlConnection(sqlcon); + DbRetVal rv = OK; + int pages = sqlstmt->getNoOfPagesForTable(pkt->tblName); + printDebug(DM_Network, "No of pages to be shipped: %d", pages); + rpkt->rows = pages; + strcpy(rpkt->errorString, pkt->tblName); + delete pkt; + delete sqlstmt; + return rpkt; +} + void SqlNetworkHandler::fillErrorString(ResponsePacket *rpkt) { switch(rpkt->errRetVal) { @@ -621,3 +630,131 @@ void SqlNetworkHandler::fillErrorString(ResponsePacket *rpkt) break; } } + +DbRetVal SqlNetworkHandler::servePacket(PacketHeader &header, void *respkt) +{ + ResponsePacket *rpkt = (ResponsePacket *) respkt; + DbRetVal rv = OK; + int params=0; + int proj=0; + NetworkStmt *stmt=NULL; + + if (header.packetType == SQL_NW_PKT_ISTABLEPRESENT || + header.packetType == SQL_NW_PKT_EXECDIRECT ) { + delete rpkt; + return OK; + } + char *ptr = (char *)&rpkt->retVal; + /*if (*ptr==0) { + delete rpkt; + return OK; + }*/ + if (rpkt->errRetVal) { + delete rpkt; + return OK; + } + params = *(ptr + 2); + proj = *(ptr + 3); + if ((header.packetType == SQL_NW_PKT_PREPARE && params != 0) || + (header.packetType == SQL_NW_PKT_PREPARE && proj != 0)) { + if (params) { + SqlPacketParamMetadata *prmpkt = new SqlPacketParamMetadata(); + prmpkt->stmtID = rpkt->stmtID; + ListIterator stmtIter = SqlNetworkHandler::stmtList.getIterator(); + while (stmtIter.hasElement()) { + stmt = (NetworkStmt*) stmtIter.nextElement(); + if (stmt->stmtID == prmpkt->stmtID) break; + } + prmpkt->noParams = stmt->paramList.size(); + rv = prmpkt->marshall(); + rv = send(SQL_NW_PKT_PARAM_METADATA, prmpkt->getMarshalledBuffer(), prmpkt->getBufferSize()); + delete prmpkt; + if (rv != OK) { + printf("Error in sending the metadata to the client\n"); + closeConnection(); + exit(1); + } + } + if (proj) { + //fill projection list and send it to client + SqlPacketProjMetadata *prjpkt = new SqlPacketProjMetadata(); + prjpkt->stmtID = rpkt->stmtID; + ListIterator stmtIter = SqlNetworkHandler::stmtList.getIterator(); + while (stmtIter.hasElement()) { + stmt = (NetworkStmt*) stmtIter.nextElement(); + if (stmt->stmtID == prjpkt->stmtID) break; + } + prjpkt->noProjs = stmt->projList.size(); + rv = prjpkt->marshall(); + rv = send(SQL_NW_PKT_PROJ_METADATA, prjpkt->getMarshalledBuffer(), prjpkt->getBufferSize()); + delete prjpkt; + if (rv != OK) { + printf("Error in sending the metadata to the client\n"); + closeConnection(); + exit(1); + } + } + } + else if (header.packetType == SQL_NW_PKT_SHOWTABLES) { + SqlPacketShowTables *shTblPkt = new SqlPacketShowTables(); + shTblPkt->numOfTables = rpkt->rows; + rv = shTblPkt->marshall(); + if (rv != OK) { printf("marshall failed\n"); } + ListIterator tblIter = SqlNetworkHandler::tableNameList.getIterator(); + while (tblIter.hasElement()) delete tblIter.nextElement(); + SqlNetworkHandler::tableNameList.reset(); + rv = send(SQL_NW_PKT_SHOWTABLES, shTblPkt->getMarshalledBuffer(), shTblPkt->getBufferSize()); + delete shTblPkt; + if (rv != OK) { + printError(ErrOS, "Error in sending the metadata to the client\n"); + closeConnection(); + exit(1); + } + } + else if (header.packetType == SQL_NW_PKT_GETRECORDS) { + if (!rpkt->rows) return OK; + SqlPacketLoadRecords *pkt = new SqlPacketLoadRecords(); + pkt->setPages(rpkt->rows); + pkt->marshall(); + SqlStatement *sqlstmt = new SqlStatement(); + SqlConnection *sqlcon = NULL; + if (Conf::config.useDurability()) + sqlcon = (SqlConnection *) conn->getInnerConnection(); + else sqlcon = (SqlConnection *) conn; + sqlstmt->setSqlConnection(sqlcon); + sqlstmt->loadRecords(&rpkt->errorString[0], pkt->getMarshalledBuffer()); + char *buf = pkt->getMarshalledBuffer(); + rv = send(SQL_NW_PKT_LOADRECORDS, pkt->getMarshalledBuffer(), pkt->getBufferSize()); + delete pkt; + delete sqlstmt; + if (rv != OK) { + printf("Error in sending the metadata to the client\n"); + closeConnection(); + exit(1); + } + } + else if (header.packetType == SQL_NW_PKT_DISCONNECT) exit(0); + if (rpkt) { delete rpkt; rpkt = NULL; } + return OK; +} + +DbRetVal SqlNetworkHandler::send(NetworkPacketType type, char *buf, int len) +{ + DbRetVal rv = OK; + PacketHeader *hdr= new PacketHeader(); + hdr->packetType = type; + hdr->packetLength = len; + hdr->srcNetworkID = 0;//networkid; + hdr->version = 1; + int numbytes=0; + if ((numbytes=os::send(sockfd, hdr, sizeof(PacketHeader), 0)) == -1) { + printError(ErrOS, "Unable to send the packet\n"); + return ErrOS; + } + if ((numbytes=os::send(sockfd, buf, len, 0)) == -1) { + printError(ErrOS, "Unable to send the packet\n"); + return ErrOS; + } + delete hdr; + return rv; +} diff --git a/src/network/TCPClient.cxx b/src/network/TCPClient.cxx index 53b11c85..51679152 100644 --- a/src/network/TCPClient.cxx +++ b/src/network/TCPClient.cxx @@ -21,10 +21,14 @@ #include #include #include +#if defined(SOLARIS) +#define MSG_NOSIGNAL 0 +#endif TCPClient::TCPClient() { isConnectedFlag =false; cacheClient = false; + sockfd = -1; respPkt = new ResponsePacket(); pktHdr = new PacketHeader(); } @@ -38,6 +42,10 @@ TCPClient::~TCPClient() DbRetVal TCPClient::send(NetworkPacketType type) { DbRetVal rv = OK; + if (sockfd == -1) { + printError(ErrNoConnection, "Connection lost with the peer."); + return ErrNoConnection; + } pktHdr->packetType = type; pktHdr->packetLength = 0; int numbytes=0; @@ -47,14 +55,22 @@ DbRetVal TCPClient::send(NetworkPacketType type) isConnectedFlag = false; return ErrNoConnection; } - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; + printError(ErrOS, "Unable to send the packet"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } return rv; } + DbRetVal TCPClient::send(NetworkPacketType type, int stmtid) { DbRetVal rv = OK; + if (sockfd == -1) { + printError(ErrNoConnection, "Connection lost with the peer."); + return ErrNoConnection; + } pktHdr->packetType = type; pktHdr->packetLength = 0; pktHdr->stmtID = stmtid; @@ -65,14 +81,21 @@ DbRetVal TCPClient::send(NetworkPacketType type, int stmtid) isConnectedFlag = false; return ErrNoConnection; } - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; + printError(ErrOS, "Unable to send the packet"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } return rv; } DbRetVal TCPClient::send(NetworkPacketType type, char *buf, int len) { DbRetVal rv = OK; + if (sockfd == -1) { + printError(ErrNoConnection, "Connection lost with the peer."); + return ErrNoConnection; + } // printf("NW:TCP Send\n"); //void* totalBuffer = malloc(sizeof(PacketHeader)+ len); //PacketHeader *hdr= new PacketHeader(); @@ -89,13 +112,11 @@ DbRetVal TCPClient::send(NetworkPacketType type, char *buf, int len) isConnectedFlag = false; return ErrNoConnection; } - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; - } - int dummy; - if ((numbytes=os::recv(sockfd, &dummy, sizeof(int), 0)) == -1) { - printError(ErrOS, "Unable to receive the packet\n"); - return ErrOS; + printError(ErrOS, "Unable to send the packet"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } // printf("Sent bytes %d\n", numbytes); if ((numbytes=os::send(sockfd, buf, len, MSG_NOSIGNAL)) == -1) { @@ -104,8 +125,11 @@ DbRetVal TCPClient::send(NetworkPacketType type, char *buf, int len) isConnectedFlag = false; return ErrNoConnection; } - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; + printError(ErrOS, "Unable to send the packet"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } // printf("Sent bytes %d\n", numbytes); //free(totalBuffer); @@ -124,20 +148,25 @@ DbRetVal TCPClient::receive() timeout.tv_usec = 0; int ret = os::select(sockfd+1, &fdset, 0, 0, &timeout); if (ret <= 0) { - printError(ErrPeerTimeOut,"Response timeout for peer site\n"); + printError(ErrPeerTimeOut,"Response timeout for peer site"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; return ErrPeerTimeOut; } socklen_t len = sizeof(struct sockaddr); int numbytes = os::recv(sockfd, respPkt, sizeof(ResponsePacket), 0); if (numbytes == -1) { - printf("Unable to receive response from peer\n"); - return ErrOS; + printError(ErrOS, "Unable to receive response from peer"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } - char *response = (char *) &respPkt->retVal; -// if (*response != 1) rv = ErrPeerResponse; - return rv; + return respPkt->errRetVal; } + DbRetVal TCPClient::connect() { //printf("NW:TCP connect %s %d %d\n", hostName, port, networkid); @@ -147,11 +176,11 @@ DbRetVal TCPClient::connect() struct hostent *he; int numbytes; if ((he=gethostbyname(hostName)) == NULL) { // get the host info - printError(ErrOS,"Unable to get the peer host name\n"); + printError(ErrOS,"Unable to get the peer host name"); return ErrOS; } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - printError(ErrOS,"Unable to create socket to peer host name\n"); + printError(ErrOS,"Unable to create socket to peer host name"); return ErrOS; } srvAddr.sin_family = AF_INET; // host byte order @@ -161,7 +190,7 @@ DbRetVal TCPClient::connect() if (::connect(sockfd, (struct sockaddr*) & srvAddr, sizeof(struct sockaddr)) == -1) { - printError(ErrOS, "Unable to connect to peer site\n"); + printError(ErrOS, "Unable to connect to peer site"); return ErrOS; } // printf("NW:TCP connecting\n"); @@ -173,7 +202,7 @@ DbRetVal TCPClient::connect() timeout.tv_usec = 0; int ret = os::select(sockfd+1, &fdset, 0, 0, &timeout); if (ret <= 0) { - printError(ErrPeerTimeOut,"Response timeout for peer site\n"); + printError(ErrPeerTimeOut,"Response timeout for peer site"); return ErrPeerTimeOut; } int response=0; @@ -181,7 +210,7 @@ DbRetVal TCPClient::connect() numbytes = os::recv(sockfd, &response, 4, 0); if (numbytes !=4) { - printf("Unable to receive response from peer\n"); + printError(ErrOS, "Unable to receive response from peer"); return ErrOS; } // printf("Response from peer site is %d\n", response); @@ -207,14 +236,18 @@ DbRetVal TCPClient::disconnect() isConnectedFlag = false; return ErrNoConnection; } - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; + printError(ErrOS, "Unable to send the packet"); + close(sockfd); + sockfd = -1; + isConnectedFlag = false; + return ErrNoConnection; } else { // printf("Sent bytes %d\n", numbytes); DbRetVal rv = receive(); + isConnectedFlag = false; close(sockfd); + sockfd = -1; } } - isConnectedFlag = false; return OK; } diff --git a/src/network/TCPServer.cxx b/src/network/TCPServer.cxx index 9e5dba4c..ef748271 100644 --- a/src/network/TCPServer.cxx +++ b/src/network/TCPServer.cxx @@ -39,9 +39,14 @@ DbRetVal TCPServer::start() my_addr.sin_port = htons(port); my_addr.sin_addr.s_addr = INADDR_ANY; memset(&(my_addr.sin_zero), '\0', 8); + int on = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on) ); + + if (bind(sockfd, (struct sockaddr *)&my_addr, - sizeof(struct sockaddr)) == -1) { - printError(ErrOS, "bind failed"); + sizeof(struct sockaddr)) == -1) { + printError(ErrOS, "bind failed for port %d",port); return ErrOS; } if (listen(sockfd, 10) == -1) { @@ -59,17 +64,20 @@ DbRetVal TCPServer::stop() } DbRetVal TCPServer::handleClient() { -// printf("PRABA::handling client \n"); + printf("DEBUG::handling client\n"); DbRetVal rv = OK; socklen_t addressLen = sizeof(struct sockaddr); clientfd = accept(sockfd, (struct sockaddr*) &clientAddress, &addressLen); int ret = os::fork(); if (ret) { //parent - os::signal(SIGCHLD, SIG_IGN); close(clientfd); return OK; }else if (ret == 0) { + int on = 1; + setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, + (char *)&on, sizeof(on) ); + //child int response = 1; int ret = os::send(clientfd, &response, 4, 0); @@ -93,10 +101,16 @@ DbRetVal TCPServer::handleClient() if (ret > 0) { // printf("something in fd\n"); int numbytes = os::recv(clientfd,&header,sizeof(PacketHeader),0); + if (!numbytes) { + close(clientfd); + handler.closeConnection(); + exit(1); + } if (numbytes == -1) { - printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + printError(ErrOS, "Error reading from socket"); + handler.closeConnection(); + exit(1); } // printf("HEADER says packet type is %d\n", header.packetType); char *buffer = NULL; @@ -106,128 +120,23 @@ DbRetVal TCPServer::handleClient() header.packetType != SQL_NW_PKT_FETCH && header.packetType != SQL_NW_PKT_SHOWTABLES ) { - int dummy=0; - numbytes = os::send(clientfd, &dummy , sizeof(int), 0); - if (numbytes == -1) { - printError(ErrOS, "Error writing to socket\n"); - return ErrOS; - } buffer = (char*) malloc(header.packetLength); numbytes = os::recv(clientfd,buffer,header.packetLength,0); if (numbytes == -1) { - printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + printError(ErrOS, "Error reading from socket"); + handler.closeConnection(); + exit(1); } } - ResponsePacket *rpkt = (ResponsePacket *) handler.process(header, buffer); - int params=0; - int proj=0; - NetworkStmt *stmt=NULL; - if (rpkt != NULL) { - numbytes = os::send(clientfd, rpkt, sizeof(ResponsePacket), 0); - if (numbytes == -1) - { - printError(ErrOS, "Error writing to socket\n"); - return ErrOS; - } - char *ptr = (char *)&rpkt->retVal; - if (*ptr==0) continue; - if (*(ptr + 1) == 1) continue; // for end of fetch - params = *(ptr + 2); - proj = *(ptr + 3); - }//new if added - if ((header.packetType == SQL_NW_PKT_PREPARE && params != 0) || - (header.packetType == SQL_NW_PKT_PREPARE && proj != 0)) { - if (params) { - SqlPacketParamMetadata *prmpkt = new SqlPacketParamMetadata(); - prmpkt->stmtID = rpkt->stmtID; - ListIterator stmtIter = SqlNetworkHandler::stmtList.getIterator(); - while (stmtIter.hasElement()) { - stmt = (NetworkStmt*) stmtIter.nextElement(); - if (stmt->stmtID == prmpkt->stmtID) break; - } - prmpkt->noParams = stmt->paramList.size(); - rv = prmpkt->marshall(); - if (rv != OK) { - printf("marshall failed\n"); - } - rv = send(SQL_NW_PKT_PARAM_METADATA, prmpkt->getMarshalledBuffer(), prmpkt->getBufferSize()); - if (rv != OK) { - printf("Error in sending the metadata to the client\n"); - exit(1); - } - } - if (proj) { - //fill projection list and send it to client - SqlPacketProjMetadata *prjpkt = new SqlPacketProjMetadata(); - prjpkt->stmtID = rpkt->stmtID; - ListIterator stmtIter = SqlNetworkHandler::stmtList.getIterator(); - while (stmtIter.hasElement()) { - stmt = (NetworkStmt*) stmtIter.nextElement(); - if (stmt->stmtID == prjpkt->stmtID) break; - } - prjpkt->noProjs = stmt->projList.size(); - rv = prjpkt->marshall(); - if (rv != OK) { - printf("marshall failed\n"); - } - rv = send(SQL_NW_PKT_PROJ_METADATA, prjpkt->getMarshalledBuffer(), prjpkt->getBufferSize()); - if (rv != OK) { - printf("Error in sending the metadata to the client\n"); - exit(1); - } - } - } - if (header.packetType == SQL_NW_PKT_SHOWTABLES) { - SqlPacketShowTables *shTblPkt = new SqlPacketShowTables(); - shTblPkt->numOfTables = rpkt->rows; - rv = shTblPkt->marshall(); - if (rv != OK) { printf("marshall failed\n"); } - ListIterator tblIter = - SqlNetworkHandler::tableNameList.getIterator(); - while (tblIter.hasElement()) delete tblIter.nextElement(); - SqlNetworkHandler::tableNameList.reset(); - - rv = send(SQL_NW_PKT_SHOWTABLES, shTblPkt->getMarshalledBuffer(), shTblPkt->getBufferSize()); - if (rv != OK) { - printf("Error in sending the metadata to the client\n"); - exit(1); - } - } - if (header.packetType == SQL_NW_PKT_DISCONNECT) { - exit(0); - } - } //else printf("Nothing in fd %d\n", ret); + ResponsePacket *rpkt = (ResponsePacket *) + handler.process(header, buffer); + if (rpkt != NULL) rv = handler.servePacket(header, rpkt); + } } - }else { + } else { printError(ErrOS, "Unable to fork new process"); return ErrOS; } return OK; } - -DbRetVal TCPServer::send(NetworkPacketType type, char *buf, int len) -{ - DbRetVal rv = OK; - //void* totalBuffer = malloc(sizeof(PacketHeader)+ len); - PacketHeader *hdr= new PacketHeader(); - hdr->packetType = type; - hdr->packetLength = len; - hdr->srcNetworkID = 0;//networkid; - hdr->version = 1; - //memcpy(((char*)totalBuffer) + sizeof(PacketHeader) , buf, len); - int numbytes=0; - if ((numbytes=os::send(clientfd, hdr, sizeof(PacketHeader), 0)) == -1) { - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; - } -// printf("Sent bytes %d\n", numbytes); - if ((numbytes=os::send(clientfd, buf, len, 0)) == -1) { - printError(ErrOS, "Unable to send the packet\n"); - return ErrOS; - } -// printf("Sent bytes %d\n", numbytes); - //free(totalBuffer); - return rv; -} diff --git a/src/network/UDPClient.cxx b/src/network/UDPClient.cxx index ed52648e..41c0e175 100644 --- a/src/network/UDPClient.cxx +++ b/src/network/UDPClient.cxx @@ -27,12 +27,12 @@ UDPClient::~UDPClient() } DbRetVal UDPClient::send(NetworkPacketType type) { - send(type, NULL, 0); + return send(type, NULL, 0); } DbRetVal UDPClient::send(NetworkPacketType type, int stmtid) { //TODO: - send(type, NULL, 0); + return send(type, NULL, 0); } DbRetVal UDPClient::send(NetworkPacketType type, char *buf, int len) { diff --git a/src/network/UDPServer.cxx b/src/network/UDPServer.cxx index d1f92147..73715a20 100644 --- a/src/network/UDPServer.cxx +++ b/src/network/UDPServer.cxx @@ -17,6 +17,7 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include #include #include #include diff --git a/src/sqllog/FileSend.cxx b/src/sqllog/FileSend.cxx index be52d018..52533c32 100644 --- a/src/sqllog/FileSend.cxx +++ b/src/sqllog/FileSend.cxx @@ -25,13 +25,37 @@ FileSend::FileSend() { char fileName[1024]; sprintf(fileName, "%s/csql.db.cur", Conf::config.getDbFile()); - fdRedoLog = open(fileName, O_WRONLY|O_CREAT| O_APPEND, 0644); + int durableMode = Conf::config.getDurableMode(); + switch(durableMode) { + case 1: + case 2: + fdRedoLog = os::openFileForAppend(fileName, O_CREAT); + break; + case 3: + fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_SYNC); + break; + case 4: +#ifdef SOLARIS + fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DSYNC); +#else + fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DIRECT); +#endif + break; + default: + fdRedoLog = os::openFileForAppend(fileName, O_CREAT); + break; + } } -DbRetVal FileSend::prepare(int txnId, int stmtId, int len, char *stmt) +FileSend::~FileSend() { if (fdRedoLog > 0) os::closeFile(fdRedoLog); fdRedoLog = -1; } + +DbRetVal FileSend::prepare(int txnId, int stmtId, int len, char *stmt, char *tblName) { if (fdRedoLog < 0) return ErrBadArg; - int datalen = 5 * sizeof(int) + os::align(len); // for len + txnId + msg type + stmtId + len + string + //The following structure needs strlen after stmt id for traversal in + //redolog file unlike msg queue structure where string is the last element + //and is not a continuous piece of memory. + int datalen = os::align(5 * sizeof(int) + len); // for len + txnId + msg type + stmtId + tableName + stmtstrlen + stmtstring char *buf = (char*) malloc(datalen); char *msg = buf; //Note:: msg type is taken as -ve as we need to differentiate between @@ -50,7 +74,19 @@ DbRetVal FileSend::prepare(int txnId, int stmtId, int len, char *stmt) msg = msg+ sizeof(int); msg[len-1] = '\0'; strcpy(msg, stmt); - int ret = os::write(fdRedoLog, buf, datalen); + int ret =0; + if (Conf::config.getDurableMode() != 1) { + ret = os::lockFile(fdRedoLog); + if (-1 == ret) { + ::free(buf); + printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file"); + return ErrLockTimeOut; + } + } + ret = os::write(fdRedoLog, buf, datalen); + if (Conf::config.getDurableMode() != 1) { + os::unlockFile(fdRedoLog); + } ::free(buf); //if (ret == datalen) { printf("log written successfully %d\n", ret); return OK; } if (ret == datalen) { return OK; } @@ -62,7 +98,17 @@ DbRetVal FileSend::commit(int len, void *data) if (fdRedoLog < 0) return ErrBadArg; char *dat=(char*)data - sizeof(int); *(int*)dat = -2; //type 2->commit - int ret = write(fdRedoLog, dat, len+sizeof(int)); + if (Conf::config.getDurableMode() != 1) { + int ret = os::lockFile(fdRedoLog); + if (-1 == ret) { + printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file"); + return ErrLockTimeOut; + } + } + int ret = os::write(fdRedoLog, dat, len+sizeof(int)); + if (Conf::config.getDurableMode() != 1) { + os::unlockFile(fdRedoLog); + } //if (ret == len+sizeof(int)) { printf("log written successfully %d\n", ret); return OK; } if (ret == len+sizeof(int)) { return OK; } return ErrOS; @@ -80,8 +126,20 @@ DbRetVal FileSend::free(int txnId, int stmtId) ptr += sizeof(int); *(int *)ptr = stmtId; printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *)ptr); - int ret = write(fdRedoLog, msg, buflen); + if (Conf::config.getDurableMode() != 1) { + int ret = os::lockFile(fdRedoLog); + if (-1 == ret) { + ::free(msg); + printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file"); + return ErrLockTimeOut; + } + } + int ret = os::write(fdRedoLog, msg, buflen); + if (Conf::config.getDurableMode() != 1) { + os::unlockFile(fdRedoLog); + } //if (ret == buflen) { printf("log written successfully %d\n", ret); return OK; } + ::free(msg); if (ret == buflen) { return OK; } return ErrOS; } diff --git a/src/sqllog/Makefile.am b/src/sqllog/Makefile.am index fe161f69..f7d2480c 100644 --- a/src/sqllog/Makefile.am +++ b/src/sqllog/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I$(top_srcdir)/include $(all_includes) METASOURCES = AUTO lib_LTLIBRARIES = libcsqlsqllog.la -libcsqlsqllog_la_LDFLAGS = -avoid-version -module +libcsqlsqllog_la_LDFLAGS = -version-info 2:4:0 -module libcsqlsqllog_la_SOURCES = SqlLogConnection.cxx SqlLogStatement.cxx FileSend.cxx libcsqlsqllog_a_LIBADD = $(top_builddir)/src/sql/libcsqlsql.la $(top_builddir)/src/network/libcsqlnw.la diff --git a/src/sqllog/SqlLogConnection.cxx b/src/sqllog/SqlLogConnection.cxx index ff7d27b0..dea7f55f 100644 --- a/src/sqllog/SqlLogConnection.cxx +++ b/src/sqllog/SqlLogConnection.cxx @@ -23,7 +23,6 @@ #include #include -GlobalUniqueID SqlLogConnection::txnUID; List SqlLogConnection::cacheList; DbRetVal SqlLogConnection::addPacket(BasePacket* pkt) @@ -58,19 +57,32 @@ DbRetVal SqlLogConnection::removePreparePacket(int stmtid) return OK; } +SqlLogConnection::~SqlLogConnection() +{ + if (msgQSend) { delete msgQSend; msgQSend = NULL; } + if (fileSend) { delete fileSend; fileSend = NULL; } + txnUID.close(); + ListIterator it = cacheList.getIterator(); + while(it.hasElement()) delete (CachedTable *) it.nextElement(); + cacheList.reset(); + it = execLogStore.getIterator(); + while(it.hasElement()) ::free ((ExecLogInfo *) it.nextElement()); + execLogStore.reset(); +} + DbRetVal SqlLogConnection::connect (char *user, char *pass) { DbRetVal rv = OK; //printf("LOG: connect\n"); if (innerConn) rv = innerConn->connect(user,pass); if (rv != OK) return rv; - if (!Conf::config.useDurability()) return OK; + if ( (!Conf::config.useCache() && Conf::config.getCacheMode() == SYNC_MODE) + && !Conf::config.useDurability()) return OK; + if (rv !=OK) { innerConn->disconnect(); return rv; } //populate cacheList if not populated by another thread in same process //TODO::cacheList requires mutex guard if (0 == cacheList.size()) rv = populateCachedTableList(); - rv = SqlLogStatement::stmtUID.open(); - rv = SqlLogConnection::txnUID.open(); return rv; } @@ -80,8 +92,7 @@ DbRetVal SqlLogConnection::disconnect() //printf("LOG: disconnect\n"); if (innerConn) rv =innerConn->disconnect(); if (rv != OK) return rv; - if (!Conf::config.useDurability()) return OK; - SqlLogStatement::stmtUID.close(); + if ( (!Conf::config.useCache() && Conf::config.getCacheMode() == SYNC_MODE) && !Conf::config.useDurability()) return OK; return rv; } DbRetVal SqlLogConnection::beginTrans(IsolationLevel isoLevel, TransSyncMode mode) @@ -99,7 +110,8 @@ DbRetVal SqlLogConnection::commit() //printf("LOG: commit %d\n", syncMode); //if (innerConn) rv = innerConn->commit(); if (innerConn) rv = innerConn->commit(); - if (!Conf::config.useDurability()) return OK; + if (( !Conf::config.useCache() && Conf::config.getCacheMode() == SYNC_MODE) + && !Conf::config.useDurability()) return OK; if (execLogStore.size() == 0) { //This means no execution for any non select statements in @@ -180,7 +192,10 @@ DbRetVal SqlLogConnection::commit() } } commitLogs(len, data); + ListIterator it = execLogStore.getIterator(); + while(it.hasElement()) ::free ((ExecLogInfo *) it.nextElement()); execLogStore.reset(); + ::free(buffer); execLogStoreSize =0; //if (innerConn) rv = innerConn->commit(); return rv; @@ -191,15 +206,16 @@ DbRetVal SqlLogConnection::rollback() //printf("LOG: rollback \n"); if (innerConn) rv = innerConn->rollback(); if (rv != OK) return rv; - ListIterator logStoreIter = logStore.getIterator(); - PacketExecute *execPkt = NULL; + if (( !Conf::config.useCache() && Conf::config.getCacheMode() == SYNC_MODE) + && !Conf::config.useDurability()) return OK; + + ListIterator logStoreIter = execLogStore.getIterator(); + ExecLogInfo *elInfo = NULL; while (logStoreIter.hasElement()) { - execPkt = (PacketExecute*)logStoreIter.nextElement(); - delete execPkt; + elInfo = (ExecLogInfo *)logStoreIter.nextElement(); + delete elInfo; } - logStore.reset(); - execLogStore.reset(); execLogStoreSize =0; return rv; @@ -217,11 +233,17 @@ DbRetVal SqlLogConnection::populateCachedTableList() char fieldname[IDENTIFIER_LENGTH]; char condition[IDENTIFIER_LENGTH]; char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + tablename[0] = '\0'; + fieldname[0] = '\0'; + condition[0] = '\0'; + field[0] = '\0'; + dsnName[0] = '\0'; int cmode; - CachedTable *node; + CachedTable *node=NULL; while(!feof(fp)) { - fscanf(fp, "%d:%s %s %s %s\n", &cmode, tablename,fieldname,condition,field); + fscanf(fp, "%d %s %s %s %s %s\n", &cmode, tablename,fieldname,condition,field,dsnName); node = new CachedTable(); strcpy(node->tableName, tablename); cacheList.append(node); @@ -248,3 +270,71 @@ bool SqlLogConnection::isTableCached(char *tblName) } return false; } + +DbRetVal MsgQueueSend::prepare(int txnId, int stmtId, int len, char *stmt, + char *tblName) +{ + //strlen is not included string is the last element in the following + //structure + int datalen = 3 * sizeof(int) + IDENTIFIER_LENGTH + os::align(len); // for len + txnId + stmtId + tblName + string + + int buffer = sizeof(Message) - 1 + datalen; + Message *msg = (Message *) malloc(buffer); + msg->mtype = 1; + *(int *)&msg->data = datalen; + char *ptr = (char *) &msg->data + sizeof(int); + *(int *)ptr = txnId; + ptr += sizeof(int); + *(int *)ptr = stmtId; + ptr += sizeof(int); + strncpy(ptr, tblName, IDENTIFIER_LENGTH); + ptr[IDENTIFIER_LENGTH-1] ='\0'; + ptr +=IDENTIFIER_LENGTH; + strncpy(ptr, stmt, len); + printDebug(DM_SqlLog, "stmtstr = | %s |\n", ptr); + printDebug(DM_SqlLog, "length of msg sent = %d\n", datalen); + int ret = os::msgsnd(msgQId, msg, datalen, 0666); + if (ret != 0) { + printError(ErrSysInternal, "message send failed\n"); + ::free(msg); + return ErrSysInternal; + } + ::free(msg); + return OK; +}; + +DbRetVal MsgQueueSend::commit(int len, void *data) +{ + Message *msg = (Message *) ((char *)data - sizeof (long)); + msg->mtype = 2; + int ret = os::msgsnd(msgQId, msg, len, 0666); + if (ret != 0) { + printError(ErrSysInternal, "message send failed\n"); + return ErrSysInternal; + } + return OK; +} + +DbRetVal MsgQueueSend::free(int txnId, int stmtId) +{ + // data to be sent is len + txn id + stmtId + int dataLen = 3 * sizeof(int); + int bufferSize = sizeof(Message) - 1 + dataLen; + Message *msg = (Message *) malloc(bufferSize); + msg->mtype = 3; + *(int *) &msg->data = dataLen; + char *ptr = (char *) &msg->data; + ptr += sizeof(int); + *(int *) ptr = txnId; + ptr += sizeof(int); + *(int *) ptr = stmtId; + printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *) ptr); + int ret = os::msgsnd(msgQId, msg, dataLen, 0666); + if (ret != 0) { + printError(ErrSysInternal, "message send failed\n"); + ::free(msg); + return ErrSysInternal; + } + ::free(msg); + return OK; +} diff --git a/src/sqllog/SqlLogStatement.cxx b/src/sqllog/SqlLogStatement.cxx index a883a877..b823b2ae 100644 --- a/src/sqllog/SqlLogStatement.cxx +++ b/src/sqllog/SqlLogStatement.cxx @@ -18,8 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include - -GlobalUniqueID SqlLogStatement::stmtUID; +#include bool SqlLogStatement::isNonSelectDML(char *stmtstr) { @@ -30,29 +29,69 @@ bool SqlLogStatement::isNonSelectDML(char *stmtstr) return false; } +DbRetVal SqlLogStatement::executeDirect(char *stmtstr) +{ + DbRetVal rv = OK; + int rows = 0; + rv = prepare(stmtstr); + if (rv != OK) return rv; + rv = execute(rows); + if (rv != OK) return rv; + return rv; +} + DbRetVal SqlLogStatement::prepare(char *stmtstr) { DbRetVal rv = OK; SqlLogConnection *conn = (SqlLogConnection *)con; - int txnId=conn->getTxnID(); - if (innerStmt) rv = innerStmt->prepare(stmtstr); - if (rv != OK) { isNonSelDML = false; return rv; } + if (innerStmt) { + rv = innerStmt->prepare(stmtstr); + if (rv != OK) { isNonSelDML = false; return rv; } + if (innerStmt->getStmtType() == SelectStatement) { + isNonSelDML = false; return rv; + } + } if (Conf::config.useDurability()) { if (strlen(stmtstr) > 6 && ((strncasecmp(stmtstr,"CREATE", 6) == 0) || (strncasecmp(stmtstr,"DROP", 4) == 0))) { sid = SqlLogStatement::stmtUID.getID(STMT_ID); printDebug(DM_SqlLog, "CREATE|DROP: stmt id = %d\n", sid); - conn->fileLogPrepare(0, sid, strlen(stmtstr)+1, stmtstr); + conn->fileLogPrepare(0, sid, strlen(stmtstr)+1, stmtstr, NULL); isNonSelDML = false; return OK; } } if (!isNonSelectDML(stmtstr)) { isNonSelDML = false; return rv;} + char *tblName = NULL; + if (innerStmt) { + tblName = innerStmt->getTableName(); + unsigned int mode = TableConf::config.getTableMode(tblName); + if (TableConf::config.isTableCached(mode)) isCached = true; + } + isPrepared = true; + if (strncasecmp(stmtstr,"CACHE", 5) == 0 || + strncasecmp(stmtstr,"UNCACHE", 7) == 0) + { + isNonSelDML = false; + return OK; + } + if ( (!Conf::config.useCache() || + (Conf::config.useCache() && Conf::config.getCacheMode()==SYNC_MODE)) && + !Conf::config.useDurability()) + { + isNonSelDML = false; + return OK; + } + needLog = true; isNonSelDML = true; - sid = SqlLogStatement::stmtUID.getID(STMT_ID); + int txnId=conn->getTxnID(); + sid = stmtUID.getID(STMT_ID); printDebug(DM_SqlLog, "stmt id = %d\n", sid); + if ((Conf::config.useCache() && Conf::config.getCacheMode() == ASYNC_MODE) + && !conn->noMsgLog && isCached) + conn->msgPrepare(txnId, sid, strlen(stmtstr) + 1, stmtstr, tblName); if (Conf::config.useDurability()) - conn->fileLogPrepare(txnId, sid, strlen(stmtstr) + 1, stmtstr); + conn->fileLogPrepare(txnId, sid, strlen(stmtstr) + 1, stmtstr, NULL); return OK; } @@ -69,6 +108,7 @@ DbRetVal SqlLogStatement::execute(int &rowsAffected) if (innerStmt) rv = innerStmt->execute(rowsAffected); if (!isNonSelDML) return rv; if ( rv != OK) return rv; + if (!needLog) return rv; ExecLogInfo *elInfo = (ExecLogInfo *) malloc (sizeof(ExecLogInfo)); elInfo->stmtId = sid; printDebug(DM_SqlLog, "Execute: stmtID: %d", elInfo->stmtId); @@ -133,6 +173,17 @@ void* SqlLogStatement::getFieldValuePtr( int pos ) if (innerStmt) return innerStmt->getFieldValuePtr(pos); return NULL; } +void* SqlLogStatement::getFieldValuePtr( char *name ) +{ + if (innerStmt) return innerStmt->getFieldValuePtr(name); + return NULL; +} + +void SqlLogStatement::getProjFieldType(int *data) +{ + if (innerStmt) return innerStmt->getProjFieldType(data); + return; +} int SqlLogStatement::noOfProjFields() { @@ -161,25 +212,26 @@ DbRetVal SqlLogStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo) DbRetVal SqlLogStatement::free() { DbRetVal rv = OK; + if (!isPrepared) return OK; if (innerStmt) rv = innerStmt->free(); - //TODO::DEBUG::always innsrStmt->free() returns error if (rv != OK) return rv; - if (isNonSelDML) { + if (!needLog) { isPrepared = false; return rv; } + if (isNonSelDML && isCached) { SqlLogConnection* logConn = (SqlLogConnection*)con; if (sid != 0 ) logConn->freeLogs(sid); } - if (!isCached) return rv; - isCached= false; sid = 0; isNonSelDML = false; + isPrepared = false; return OK; } void SqlLogStatement::setShortParam(int paramPos, short value) { if (innerStmt) innerStmt->setShortParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(short); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(short); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; printDebug(DM_SqlLog, "setShort: stmtID: %d", elInfo->stmtId); @@ -203,8 +255,9 @@ void SqlLogStatement::setIntParam(int paramPos, int value) { if (innerStmt) innerStmt->setIntParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(int); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(int); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; printDebug(DM_SqlLog, "setInt: stmtID: %d", elInfo->stmtId); @@ -228,8 +281,9 @@ void SqlLogStatement::setLongParam(int paramPos, long value) { if (innerStmt) innerStmt->setLongParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(long); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(long); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -245,8 +299,9 @@ void SqlLogStatement::setLongLongParam(int paramPos, long long value) { if (innerStmt) innerStmt->setLongLongParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(long long); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(long long); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -262,8 +317,9 @@ void SqlLogStatement::setByteIntParam(int paramPos, ByteInt value) { if (innerStmt) innerStmt->setByteIntParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(ByteInt); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(ByteInt); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -279,8 +335,9 @@ void SqlLogStatement::setFloatParam(int paramPos, float value) { if (innerStmt) innerStmt->setFloatParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(float); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(float); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -296,8 +353,9 @@ void SqlLogStatement::setDoubleParam(int paramPos, double value) { if (innerStmt) innerStmt->setDoubleParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(double); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(double); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -313,8 +371,9 @@ void SqlLogStatement::setStringParam(int paramPos, char *value) { if (innerStmt) innerStmt->setStringParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + os::align(strlen(value) + 1); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + os::align(strlen(value) + 1); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -330,8 +389,9 @@ void SqlLogStatement::setDateParam(int paramPos, Date value) { if (innerStmt) innerStmt->setDateParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(Date); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(Date); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -347,8 +407,9 @@ void SqlLogStatement::setTimeParam(int paramPos, Time value) { if (innerStmt) innerStmt->setTimeParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(Time); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(Time); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -364,8 +425,9 @@ void SqlLogStatement::setTimeStampParam(int paramPos, TimeStamp value) { if (innerStmt) innerStmt->setTimeStampParam(paramPos,value); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + sizeof(TimeStamp); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + sizeof(TimeStamp); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -381,8 +443,9 @@ void SqlLogStatement::setBinaryParam(int paramPos, void *value, int length) { if (innerStmt) innerStmt->setBinaryParam(paramPos,value, length); if (!isNonSelDML) return; + if (!needLog) return; SqlLogConnection* logConn = (SqlLogConnection*)con; - int buffer = sizeof(ExecLogInfo) - sizeof(void *) + os::align(length); + int buffer = sizeof(ExecLogInfo) - sizeof(int) + os::align(length); ExecLogInfo *elInfo = (ExecLogInfo *) malloc (buffer); elInfo->stmtId = sid; elInfo->type = SETPARAM; @@ -408,3 +471,8 @@ List SqlLogStatement::getAllTableNames(DbRetVal &ret) if(innerStmt) return innerStmt->getAllTableNames(ret); } +List SqlLogStatement::getAllUserNames(DbRetVal &ret) +{ + if(innerStmt) return innerStmt->getAllUserNames(ret); +} + diff --git a/src/sqlnetwork/Makefile.am b/src/sqlnetwork/Makefile.am index c157e4d1..c5a55ea6 100644 --- a/src/sqlnetwork/Makefile.am +++ b/src/sqlnetwork/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I$(top_srcdir)/include $(all_includes) METASOURCES = AUTO lib_LTLIBRARIES = libcsqlsqlnw.la -libcsqlsqlnw_la_LDFLAGS = -avoid-version -module +libcsqlsqlnw_la_LDFLAGS = -version-info 2:4:0 -module libcsqlsqlnw_la_SOURCES = SqlNwConnection.cxx SqlNwStatement.cxx libcsqlsqlnw_a_LIBADD = $(top_builddir)/src/sql/libcsqlsql.la diff --git a/src/sqlnetwork/SqlNwConnection.cxx b/src/sqlnetwork/SqlNwConnection.cxx index 46741da0..5a5d2b21 100644 --- a/src/sqlnetwork/SqlNwConnection.cxx +++ b/src/sqlnetwork/SqlNwConnection.cxx @@ -29,12 +29,14 @@ DbRetVal SqlNwConnection::connect (char *user, char * pass) printError(ErrAlready, "Connection is already open"); return ErrAlready; } - nwClient = new TCPClient(); + if (nwClient == NULL) nwClient = new TCPClient(); int bufsize = 2 * IDENTIFIER_LENGTH + sizeof(int); nwClient->setHost(hostname, port, 123); rv = nwClient->connect(); if (rv != OK) { printError(rv, "Connection failed"); + delete nwClient; + nwClient = NULL; return rv; } SqlPacketConnect *pkt = new SqlPacketConnect(); @@ -46,19 +48,28 @@ DbRetVal SqlNwConnection::connect (char *user, char * pass) rv = nwClient->send(SQL_NW_PKT_CONNECT, buffer, bufsize); if (rv != OK) { printError(rv, "Data could not be sent"); + delete pkt; + delete nwClient; + nwClient = NULL; return rv; } - int response = 0; rv = nwClient->receive(); + if (rv == ErrPeerTimeOut) { + delete pkt; + delete nwClient; + nwClient = NULL; + return ErrNoConnection; + } ResponsePacket *rpkt = (ResponsePacket *) ((TCPClient *)nwClient)->respPkt; char *ptr = (char *) &rpkt->retVal; - if (*ptr != 1) { +/* if (*ptr != 1) { printError(ErrPeerResponse, "%s", rpkt->errorString); + delete pkt; nwClient->disconnect(); delete nwClient; - delete pkt; + nwClient = NULL; return ErrPeerResponse; - } + }*/ isConnOpen = true; delete pkt; return rv; @@ -73,6 +84,7 @@ DbRetVal SqlNwConnection::disconnect() rv = nwClient->disconnect(); isConnOpen=false; delete nwClient; + nwClient = NULL; return rv; } @@ -93,8 +105,16 @@ DbRetVal SqlNwConnection::commit() } DbRetVal rv = OK; rv = nwClient->send(SQL_NW_PKT_COMMIT); - int response = 0; - return nwClient->receive(); + if (rv == ErrNoConnection) { + setConnClosed(false); + return rv; + } + rv = nwClient->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + setConnClosed(false); + return ErrNoConnection; + } + return rv; } DbRetVal SqlNwConnection::rollback() @@ -105,7 +125,15 @@ DbRetVal SqlNwConnection::rollback() } DbRetVal rv = OK; rv = nwClient->send(SQL_NW_PKT_ROLLBACK); - int response = 0; - return nwClient->receive(); -} + if (rv == ErrNoConnection) { + setConnClosed(false); + return rv; + } + rv = nwClient->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + setConnClosed(false); + return ErrNoConnection; + } + return rv; +} diff --git a/src/sqlnetwork/SqlNwStatement.cxx b/src/sqlnetwork/SqlNwStatement.cxx index f26eaf24..4b39605b 100644 --- a/src/sqlnetwork/SqlNwStatement.cxx +++ b/src/sqlnetwork/SqlNwStatement.cxx @@ -20,6 +20,44 @@ #include #include +DbRetVal SqlNwStatement::executeDirect(char *stmtstr) +{ + DbRetVal rv = OK; + isSel = false; + SqlNwConnection *conn = (SqlNwConnection*)con; + if (! conn->isConOpen()) { + printError(ErrNoConnection, "No connection present"); + return ErrNoConnection; + } + if (isPrepared) free(); + if (nullInfoSel) { ::free(nullInfoSel); nullInfoSel = NULL; } + SqlPacketPrepare *pkt = new SqlPacketPrepare(); + pkt->stmtString = stmtstr; + pkt->stmtLength = os::align(strlen(stmtstr) + 1); + pkt->marshall(); + rv = conn->send(SQL_NW_PKT_EXECDIRECT, pkt->getMarshalledBuffer(), pkt->getBufferSize()); + if (rv != OK) { + conn->setConnClosed(false); + printError(rv, "Connection lost with the peer."); + delete pkt; + return rv; + } + rv = conn->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + printError(rv, "Connection lost with the peer."); + delete pkt; + return ErrNoConnection; + } + ResponsePacket *rpkt = (ResponsePacket *) + ((TCPClient *)conn->nwClient)->respPkt; + if (rv != OK) { delete pkt; return rv; } + char *ptr = (char *) &rpkt->retVal; + isPrepared = true; + delete pkt; + return rv; +} + DbRetVal SqlNwStatement::prepare(char *stmtstr) { DbRetVal rv = OK; @@ -38,19 +76,24 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) pkt->marshall(); rv = conn->send(SQL_NW_PKT_PREPARE, pkt->getMarshalledBuffer(), pkt->getBufferSize()); if (rv != OK) { - printError(rv, "Data could not be sent"); + conn->setConnClosed(false); + printError(rv, "Connection lost with the peer."); + delete pkt; return rv; } - int response = 0; rv = conn->receive(); - if (rv != OK) { - printError(rv, "Unable to Receive from peer"); - return rv; + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + printError(rv, "Connection lost with the peer."); + delete pkt; + return ErrNoConnection; } - ResponsePacket *rpkt = (ResponsePacket *) ((TCPClient *)conn->nwClient)->respPkt; + ResponsePacket *rpkt = (ResponsePacket *) + ((TCPClient *)conn->nwClient)->respPkt; + if (rv != OK) { delete pkt; return rv; } char *ptr = (char *) &rpkt->retVal; - if (*ptr == 0) { delete pkt; return ErrPeerResponse; } if (rpkt->isSelect) isSel = true; else isSel = false; + plan =(ResultSetPlan) *ptr ; int params = *(ptr + 2); int proj = *(ptr + 3); stmtID = rpkt->stmtID; @@ -61,14 +104,25 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) int numbytes = os::recv(fd, &header, sizeof(PacketHeader), 0); if (numbytes == -1) { printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + delete pkt; + return ErrNoConnection; } // printf("HEADER says packet type is %d\n", header.packetType); buffer = (char*) malloc(header.packetLength); numbytes = os::recv(fd,buffer,header.packetLength,0); if (numbytes == -1) { printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + delete pkt; + ::free(buffer); + return ErrNoConnection; } SqlPacketParamMetadata *mdpkt = new SqlPacketParamMetadata(); mdpkt->setBuffer(buffer); @@ -102,6 +156,7 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) ptr += sizeof (FieldInfo); } delete mdpkt; + delete fldInfo; } if (proj) { PacketHeader header; @@ -109,14 +164,25 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) int numbytes = os::recv(fd, &header, sizeof(PacketHeader), 0); if (numbytes == -1) { printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + delete pkt; + return ErrNoConnection; } // printf("HEADER says packet type is %d\n", header.packetType); buffer = (char*) malloc(header.packetLength); numbytes = os::recv(fd,buffer,header.packetLength,0); if (numbytes == -1) { printError(ErrOS, "Error reading from socket\n"); - return ErrOS; + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ::free (buffer); + delete pkt; + return ErrNoConnection; } SqlPacketProjMetadata *prjmdpkt = new SqlPacketProjMetadata(); prjmdpkt->setBuffer(buffer); @@ -133,6 +199,7 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) prjFld->length = fldInfo->length; prjFld->offset = fldInfo->offset; strcpy(prjFld->defaultValueBuf, fldInfo->defaultValueBuf); + prjFld->aType = fldInfo->aType; prjFld->isNull = fldInfo->isNull; prjFld->isPrimary = fldInfo->isPrimary; prjFld->isDefault = fldInfo->isDefault; @@ -144,6 +211,7 @@ DbRetVal SqlNwStatement::prepare(char *stmtstr) ptr += sizeof (FieldInfo); } delete prjmdpkt; + delete fldInfo; } isPrepared = true; delete pkt; @@ -167,21 +235,27 @@ DbRetVal SqlNwStatement::execute(int &rowsAffected) pkt->marshall(); rv = conn->send(SQL_NW_PKT_EXECUTE, pkt->getMarshalledBuffer(), pkt->getBufferSize()); if (rv != OK) { - printError(rv, "Data could not be sent"); + conn->setConnClosed(false); + printError(rv, "Connection lost with the peer."); + delete pkt; return rv; } rv = conn->receive(); - if (rv != OK) return rv; - memset(nullInfoDml, 0, os::align(pkt->noParams)); - //if(pkt->noParams) delete [] pkt->paramValues; - delete pkt; + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + delete pkt; + return ErrNoConnection; + } ResponsePacket *rpkt = (ResponsePacket *) ((TCPClient *)conn->nwClient)->respPkt; - char *ptr = (char *) &rpkt->retVal; - rowsAffected = rpkt->rows; - if (*ptr != 1) { - printError(rpkt->errRetVal, "%s", rpkt->errorString); - return rpkt->errRetVal; + if (rv != OK) { + printError(rv, "%s", rpkt->errorString); + delete pkt; + return rv; } + rowsAffected = rpkt->rows; + memset(nullInfoDml, 0, os::align(pkt->noParams)); + pkt->setNullInfo(NULL); + delete pkt; return rv; } @@ -196,9 +270,11 @@ DbRetVal SqlNwStatement::bindField(int pos, void* value) { if (!isPrepared) return OK; BindSqlProjectField *prjFld = (BindSqlProjectField *) bindList.get(pos); + if(prjFld->value) { ::free(prjFld->value); prjFld->isFreed = true; } prjFld->value = value; return OK; } + void* SqlNwStatement::fetch() { DbRetVal rv = OK; @@ -215,41 +291,37 @@ void* SqlNwStatement::fetch(DbRetVal &ret) } if (!isPrepared) return NULL; void *ptrToFirstField = NULL; - DbRetVal rv = conn->nwClient->send(SQL_NW_PKT_FETCH, getStmtID()); if (rv != OK) { - printError(rv, "Data could not be sent"); + conn->setConnClosed(false); + printError(rv, "Connection lost with peer."); + ret = ErrNoConnection; return NULL; } - - /*SqlPacketFetch *pkt = new SqlPacketFetch(); - pkt->stmtID = getStmtID(); - pkt->marshall(); - DbRetVal rv = conn->send(SQL_NW_PKT_FETCH, pkt->getMarshalledBuffer(), pkt->getBufferSize()); - if (rv != OK) { - printError(rv, "Data could not be sent"); - return NULL; - }*/ -// printf("HEADER says packet type is %d\n", header.packetType); int rowLength=0; int dummy =0; int fd = ((TCPClient *)(conn->nwClient))->sockfd; int numbytes = os::recv(fd, &rowLength, 4, 0); - if (rowLength ==1 ) return NULL; - else if (rowLength == 2) {ret = ErrUnknown; return NULL; } - - if ((numbytes = os::send(fd, &dummy, 4,MSG_NOSIGNAL)) == -1) { - if (errno == EPIPE) { - printError(ErrNoConnection, "connection not present"); - return NULL; - } - printError(ErrOS, "Unable to send the packet\n"); + if (numbytes == -1) { + printError(ErrOS, "Connection lost with peer\n"); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; return NULL; } + if (rowLength ==1 ) return NULL; + else if (rowLength == 2) {ret = ErrUnknown; return NULL; } char *rowBuffer = (char*) malloc(rowLength); numbytes = os::recv(fd,rowBuffer,rowLength,0); if (numbytes == -1) { - printError(ErrOS, "Error reading from socket\n"); + printError(ErrOS, "Connection lost with peer\n"); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; return NULL; } SqlPacketResultSet *rspkt = new SqlPacketResultSet(); @@ -261,14 +333,11 @@ void* SqlNwStatement::fetch(DbRetVal &ret) memset(nullInfoSel, 0, os::align(rspkt->noProjs)); rspkt->setNullInfo(nullInfoSel); rspkt->unmarshall(); - delete [] rspkt->projValues; ptrToFirstField = bindList.get(1); delete rspkt; - //delete pkt; return ptrToFirstField; } - void* SqlNwStatement::fetchAndPrint(bool SQL) { if (!isPrepared) return NULL; @@ -278,7 +347,10 @@ void* SqlNwStatement::fetchAndPrint(bool SQL) if (NULL == tuple) return NULL; for(int i = 0; i < noOfProjs; i++) { fld = (BindSqlProjectField *) bindList.get(i + 1); - if (isFldNull(i+1)) printf("NULL"); + if (isFldNull(i+1)) { + if (fld->aType == AGG_COUNT) printf("0"); + else printf("NULL"); + } else AllDataType::printVal(fld->value, fld->type, fld->length); printf("\t"); } @@ -302,6 +374,17 @@ void* SqlNwStatement::getFieldValuePtr( int pos ) BindSqlProjectField *fld=(BindSqlProjectField *) bindList.get(pos+1); return fld->value; } +void SqlNwStatement::getProjFieldType(int *data) +{ + ListIterator biter = bindList.getIterator(); + BindSqlProjectField *elem = NULL; + int i = 1; + while (biter.hasElement()) + { + elem = (BindSqlProjectField*) biter.nextElement(); + data[i++] = elem->type; + } +} int SqlNwStatement::noOfProjFields() { @@ -359,26 +442,29 @@ DbRetVal SqlNwStatement::free() pkt->marshall(); rv = conn->send(SQL_NW_PKT_FREE, pkt->getMarshalledBuffer(), pkt->getBufferSize()); if (rv != OK) { - printError(rv, "Data could not be sent"); + printError(rv, "Connection lost with peer"); + conn->setConnClosed(false); + delete pkt; return rv; } + delete pkt; rv = conn->receive(); - if (rv != OK) return rv; - ResponsePacket *rpkt = (ResponsePacket *) ((TCPClient *)conn->nwClient)->respPkt; - char *ptr = (char *) &rpkt->retVal; - if (*ptr != 1) { - printf("there is some error\n"); - return ErrPeerResponse; + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + return ErrNoConnection; } + else if (rv != OK) return rv; ListIterator itprm = paramList.getIterator(); BindSqlField *fld = NULL; while((fld = (BindSqlField *) itprm.nextElement()) != NULL) { - if (fld->value) ::free(fld->value); delete fld; + if (fld->value) ::free(fld->value); + delete fld; } paramList.reset(); ListIterator itprj = bindList.getIterator(); BindSqlProjectField *pfld = NULL; while((pfld = (BindSqlProjectField *) itprj.nextElement()) != NULL) { + if(pfld->value && !pfld->isFreed) ::free(pfld->value); delete pfld; } if (nullInfoSel) { ::free(nullInfoSel); nullInfoSel = NULL; } @@ -386,7 +472,6 @@ DbRetVal SqlNwStatement::free() bindList.reset(); isPrepared = false; - delete pkt; return rv; } @@ -478,7 +563,7 @@ void SqlNwStatement::setStringParam(int paramPos, char *value) if (paramPos <= 0) return; BindSqlField *bindField = (BindSqlField *) paramList.get(paramPos); bindField->type = typeString; - strcpy((char *) bindField->value, value); + strncpy((char *) bindField->value, value, bindField->length); return; } @@ -546,38 +631,48 @@ List SqlNwStatement::getAllTableNames(DbRetVal &ret) ret = ErrNoConnection; } rv = conn->send(SQL_NW_PKT_SHOWTABLES); - rv = conn->receive(); if (rv != OK) { - printError(rv, "Unable to Receive from peer"); - ret = rv; + conn->setConnClosed(false); + ret = ErrNoConnection; + return tblNameList; } - ResponsePacket *rpkt = (ResponsePacket *) ((TCPClient *)conn->nwClient)->respPkt; - char *ptr = (char *) &rpkt->retVal; - if (*ptr == 0) { ret = ErrPeerResponse; } - stmtID = rpkt->stmtID; + rv = conn->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + ret = ErrNoConnection; + return tblNameList; + } + ResponsePacket *rpkt = (ResponsePacket *) + ((TCPClient *)conn->nwClient)->respPkt; int noOfTables = rpkt->rows; PacketHeader header; int fd = ((TCPClient *)(conn->nwClient))->sockfd; int numbytes = os::recv(fd, &header, sizeof(PacketHeader), 0); if (numbytes == -1) { - printError(ErrOS, "Error reading from socket\n"); - ret = ErrOS; + printError(ErrOS, "Connection lost with peer."); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; + return tblNameList; } // printf("HEADER says packet type is %d\n", header.packetType); char *buffer = (char*) malloc(header.packetLength); numbytes = os::recv(fd,buffer,header.packetLength,0); if (numbytes == -1) { - printError(ErrOS, "Error reading from socket\n"); - ret = ErrOS; + printError(ErrOS, "Connection lost with peer."); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; + return tblNameList; } SqlPacketShowTables *pkt = new SqlPacketShowTables(); pkt->setBuffer(buffer); rv = pkt->unmarshall(); - if (rv != OK) { - printError(rv, "Data could not be sent"); - ret = rv; - } - ptr = (char *)pkt->data; + char *ptr = (char *)pkt->data; while (noOfTables) { Identifier *id = new Identifier(); strncpy(id->name, ptr, IDENTIFIER_LENGTH); @@ -588,6 +683,109 @@ List SqlNwStatement::getAllTableNames(DbRetVal &ret) return tblNameList; } +bool SqlNwStatement::isTablePresent(char *tblName, DbRetVal &ret) +{ + DbRetVal rv = OK; + SqlNwConnection *conn = (SqlNwConnection*)con; + if (! conn->isConOpen()) { + printError(ErrNoConnection, "No connection present"); + ret = ErrNoConnection; + return false; + } + + SqlPacketIsTablePresent *pkt = new SqlPacketIsTablePresent(); + pkt->setTableName(tblName); + pkt->marshall(); + rv = conn->send(SQL_NW_PKT_ISTABLEPRESENT, pkt->getMarshalledBuffer(), + pkt->getBufferSize()); + if (rv != OK) { + delete pkt; + printError(ErrOS, "Connection lost with peer."); + conn->setConnClosed(false); + ret = ErrNoConnection; + return false; + } + delete pkt; + rv = conn->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + ret = ErrNoConnection; + return false; + } + if (rv != OK) return false; + return true; +} + +void *SqlNwStatement::getLoadedRecords(char *tblName, DbRetVal &ret) +{ + DbRetVal rv = OK; + SqlNwConnection *conn = (SqlNwConnection*)con; + if (! conn->isConOpen()) { + printError(ErrNoConnection, "No connection present"); + ret = ErrNoConnection; + return NULL; + } + SqlPacketGetRecords *pkt = new SqlPacketGetRecords(); + pkt->setTableName(tblName); + pkt->marshall(); + rv = conn->send(SQL_NW_PKT_GETRECORDS, pkt->getMarshalledBuffer(), + pkt->getBufferSize()); + if (rv != OK) { + printError(rv, "Connection lost with peer."); + conn->setConnClosed(false); + ret = rv; + delete pkt; + return NULL; + } + delete pkt; + rv = conn->receive(); + if (rv == ErrNoConnection || rv == ErrPeerTimeOut) { + conn->setConnClosed(false); + ret = ErrNoConnection; + return NULL; + } + ResponsePacket *rpkt = (ResponsePacket *) + ((TCPClient *)conn->nwClient)->respPkt; + if (!rpkt->rows) { + ret = rpkt->errRetVal; + return NULL; + } + PacketHeader header; + int fd = ((TCPClient *)(conn->nwClient))->sockfd; + int numbytes = os::recv(fd, &header, sizeof(PacketHeader), 0); + if (numbytes == -1) { + printError(ErrOS, "Connection lost with peer"); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; + return NULL; + } +// printf("HEADER says packet length is %d\n", header.packetLength); + char *buffer = (char*) malloc(header.packetLength); + numbytes = os::recv(fd,buffer,header.packetLength,0); + if (numbytes == -1) { + printError(ErrOS, "Connection lost with peer"); + conn->setConnClosed(false); + os::closeFile(fd); + ((TCPClient *)(conn->nwClient))->sockfd = -1; + conn->setIsConnectedFlag(false); + ret = ErrNoConnection; + return NULL; + } + SqlPacketLoadRecords *lpkt = new SqlPacketLoadRecords(); + lpkt->setBuffer(buffer); + lpkt->unmarshall(); + char * data = (char *) lpkt->getMarshalledBuffer(); + int pages = *(int *) data; + int sizeToCopy = sizeof(int) + pages * PAGE_SIZE; + char *dataToReturn = (char *) malloc(sizeToCopy); + memcpy(dataToReturn, data, sizeToCopy); + delete lpkt; + return dataToReturn; +} + bool SqlNwStatement::isFldNull(int pos) { if (nullInfoSel[pos - 1]) return true; diff --git a/src/storage/AggTableImpl.cxx b/src/storage/AggTableImpl.cxx index 144a4894..12e1a9a8 100644 --- a/src/storage/AggTableImpl.cxx +++ b/src/storage/AggTableImpl.cxx @@ -17,12 +17,53 @@ #include #include #include +#include +static char AggNames[][20] = +{ + "MIN", "MAX", "SUM", "AVG", "COUNT", "" +}; + AggTableImpl::AggTableImpl() { + tableHdl = NULL; + curTuple = NULL; + havingPred = NULL; + groupSize = 0; + aggNodeSize = 0; + prjNullInfo = 0; + grpNullInfo = 0; + grpFldBuffer = NULL; + optGrpIntNoNull = false; + grpBindBuf = NULL; } AggTableImpl::~AggTableImpl() { - close(); + //free memory allocated. make sure that field buffers are freed only once. + //for stmts which has more than one agg on same field needs to be handled safely + closeScan(); + ListIterator iter = fldList.getIterator(); + AggFldDef *elem; + while (iter.hasElement()) + { + elem = (AggFldDef*) iter.nextElement(); + if(!elem->alreadyBinded) free(elem->bindBuf); + //if(elem->bindBuf) { free(elem->bindBuf); elem->bindBuf =NULL; } + delete elem; + } + fldList.reset(); + + ListIterator giter = fldGroupList.getIterator(); + while (giter.hasElement()) + { + elem = (AggFldDef*) giter.nextElement(); + if(!elem->alreadyBinded) free(elem->bindBuf); + //if(elem->bindBuf) { free(elem->bindBuf); elem->bindBuf =NULL; } + delete elem; + } + fldGroupList.reset(); + if (tableHdl != NULL) tableHdl->close(); + tableHdl = NULL; + ::free(grpFldBuffer); } void *AggTableImpl::getBindFldAddr(const char *name) { @@ -30,8 +71,6 @@ void *AggTableImpl::getBindFldAddr(const char *name) return NULL; } - - DbRetVal AggTableImpl::bindFld(const char *name, void *val) { printError(ErrBadCall, "AggTableImpl bindFld not implemented\n"); @@ -40,15 +79,25 @@ DbRetVal AggTableImpl::bindFld(const char *name, void *val) DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val) { FieldInfo *info = new FieldInfo(); - tableHdl->getFieldInfo(fldname, info); + DbRetVal rv = tableHdl->getFieldInfo(fldname, info); + if (OK != rv) { delete info; return rv; } AggFldDef *def = new AggFldDef(); strcpy(def->fldName, fldname); def->type = info->type; def->length= info->length; def->appBuf = val; - def->atype=aggType; + def->aType=aggType; def->bindBuf = NULL; def->alreadyBinded = false; + + //if underlying tablehandle is TableImpl, then set isNullable + def->isNullable = true; + if (info->isNull || info->isPrimary || + info->isDefault || info->isAutoIncrement) { + def->isNullable = false; + } + if (NULL == tableHdl->getName()) def->isNullable=true; + ListIterator iter = fldList.getIterator(); AggFldDef *elem; //If it is already binded, then use the same buffer which is binded. @@ -66,7 +115,14 @@ DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val) if (!def->bindBuf) { def->bindBuf = AllDataType::alloc(def->type, def->length); - tableHdl->bindFld(fldname, def->bindBuf); + rv = tableHdl->bindFld(fldname, def->bindBuf); + if (OK !=rv) { + delete info; + ::free(def->bindBuf); + delete def; + return rv; + } + def->alreadyBinded = true; } fldList.append(def); delete info; @@ -75,67 +131,201 @@ DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val) DbRetVal AggTableImpl::setGroup(const char *fldname, void *val) { FieldInfo *info = new FieldInfo(); - tableHdl->getFieldInfo(fldname, info); - strcpy(groupFld.fldName, fldname); - groupFld.type = info->type; - groupFld.length = info->length; - groupFld.appBuf = val; - groupFld.bindBuf = AllDataType::alloc(info->type, info->length); - tableHdl->bindFld(fldname, groupFld.bindBuf); + DbRetVal rv = tableHdl->getFieldInfo(fldname, info); + if (rv !=OK) { delete info; return rv; } + AggFldDef *groupFld=new AggFldDef(); + strcpy(groupFld->fldName, fldname); + groupFld->type = info->type; + groupFld->length = info->length; + groupFld->appBuf = val; + groupFld->bindBuf = NULL; + + groupFld->isNullable = true; + if (info->isNull || info->isPrimary || + info->isDefault || info->isAutoIncrement) { + groupFld->isNullable = false; + } + if (NULL == tableHdl->getName()) groupFld->isNullable=true; + + ListIterator iter = fldList.getIterator(); + AggFldDef *elem; + + while (iter.hasElement()) + { + elem = (AggFldDef*) iter.nextElement(); + if (strcmp(elem->fldName, fldname)==0) + { + groupFld->bindBuf = elem->bindBuf; + groupFld->alreadyBinded = true; + break; + } + } + if (!groupFld->bindBuf) + { + groupFld->bindBuf = AllDataType::alloc(groupFld->type, groupFld->length); + rv = tableHdl->bindFld(fldname, groupFld->bindBuf); + if (rv !=OK) { + delete info; + ::free(groupFld->bindBuf); + delete groupFld; + return rv; + } + } + + fldGroupList.append(groupFld); delete info; return OK; } +bool AggTableImpl::isFldPresentInGrp(char *fname) +{ + ListIterator iter = fldGroupList.getIterator(); + AggFldDef *grpFld=NULL; + while (iter.hasElement()) + { + grpFld=(AggFldDef *)iter.nextElement(); + if(0==strcmp(fname,grpFld->fldName)) return true; + } + return false; +} +int AggTableImpl::getAggOffset(char *fname, AggType aggType) +{ + ListIterator iter = fldList.getIterator(); + AggFldDef *projDef=NULL; + int offset = groupSize + sizeof(prjNullInfo); + while (iter.hasElement()) + { + projDef=(AggFldDef *)iter.nextElement(); + if(0==strcmp(fname, projDef->fldName) && aggType == projDef->aType) + { + return offset; + } + else { + if (projDef->aType == AGG_AVG) + offset = offset + sizeof (double)+ sizeof(int); + else if (projDef->aType == AGG_COUNT) offset = offset + sizeof(int); + else offset = offset + projDef->length; + } + } + printError(ErrSysFatal, "Aggregate condition not found in projection list %s", fname); + return offset; +} + +int AggTableImpl::computeGrpNodeSize() +{ + ListIterator iter = fldGroupList.getIterator(); + AggFldDef *grpFld=NULL; + int totalGrpNodeSize=sizeof(int); + while (iter.hasElement()) + { + grpFld=(AggFldDef *)iter.nextElement(); + totalGrpNodeSize=totalGrpNodeSize + grpFld->length; + } + return totalGrpNodeSize; +} + +DbRetVal AggTableImpl::copyValuesFromGrpBindBuf(char *buffer, char *fname) +{ + ListIterator iter = fldGroupList.getIterator(); + AggFldDef *grpFld=NULL; + while ((grpFld = (AggFldDef*)iter.nextElement()) != NULL) + { + //grpFld=(AggFldDef *)iter.nextElement(); + if(0==strcmp(fname,grpFld->fldName)) + { + AllDataType::copyVal(buffer, grpFld->bindBuf, grpFld->type, + grpFld->length); + break; + } + } + return OK; +} +DbRetVal AggTableImpl::optimize() +{ + AggFldDef *grpFld=NULL; + optGrpIntNoNull= false; + if (groupSize == sizeof(int)+ sizeof(int)) + { + ListIterator iter = fldGroupList.getIterator(); + grpFld = (AggFldDef*)iter.nextElement(); + if (!grpFld->isNullable && grpFld->type == typeInt) + { + optGrpIntNoNull=true; + grpBindBuf = grpFld->bindBuf; + aggNodeMap.setGrpIntNoNull(); + } + } + return OK; +} DbRetVal AggTableImpl::execute() { ListIterator iter = fldList.getIterator(); AggFldDef *def; - if (isGroupSet()) - aggNodeSize = groupFld.length; - else - aggNodeSize = 0; + aggNodeSize = groupSize = computeGrpNodeSize(); + aggNodeMap.setKeySize(groupSize); + optimize(); + + grpFldBuffer = (char*) ::malloc(groupSize); + aggNodeSize += sizeof(long long); // for proj field null Info while (iter.hasElement()) { - def = (AggFldDef*) iter.nextElement(); - if (def->atype != AGG_UNKNOWN && - 0 == strcmp(def->fldName, groupFld.fldName)) - { - def->atype = AGG_UNKNOWN; - } - aggNodeSize = aggNodeSize + def->length; - if (def->atype == AGG_AVG) aggNodeSize = aggNodeSize + sizeof(int);//for count + def = (AggFldDef*) iter.nextElement(); + if (def->aType == AGG_AVG) { + aggNodeSize += sizeof(double); + aggNodeSize += sizeof(int);//for count + } + else if (def->aType == AGG_COUNT) aggNodeSize += sizeof(int); + else aggNodeSize += def->length; } void *tuple = NULL; int offset=0; tableHdl->execute(); aggNodes.reset(); + int groupOffset = groupSize; while((tuple = tableHdl->fetch()) != NULL) { - char *buffer = (char*)insertOrGet(); + char *buffer = (char*)insertOrGetAggNode(); iter.reset(); - if (isGroupSet()) - offset = groupFld.length; - else - offset = 0; - while (iter.hasElement()) + offset = groupOffset; + char *nullInfo = buffer + offset; + prjNullInfo = *(long long *) nullInfo; + offset += sizeof(long long); + int colpos = 1; + while ((def = (AggFldDef*)iter.nextElement()) != NULL) { - def = (AggFldDef*) iter.nextElement(); - switch(def->atype) - { + //def = (AggFldDef*) iter.nextElement(); + if (def->isNullable && tableHdl->isFldNull(def->fldName)) { + if (def->aType == AGG_AVG) + offset = offset + sizeof(double) + sizeof(int); + else if (def->aType == AGG_COUNT) offset += sizeof(int); + else offset = offset + def->length; + colpos++; + continue; + } + bool result=false; bool isNull=false; + isNull = isFldNull(colpos); + switch(def->aType) + { case AGG_MIN: { - bool result = AllDataType::compareVal(buffer+offset, - def->bindBuf, OpGreaterThanEquals, def->type, def->length); - if (result) + if (!isNull) { + result = AllDataType::compareVal(buffer+offset, + def->bindBuf, OpGreaterThanEquals, def->type, + def->length); + } + if (result || isNull) AllDataType::copyVal(buffer+offset, def->bindBuf, - def->type, def->length); + def->type, def->length); break; } case AGG_MAX: { - bool result = AllDataType::compareVal(buffer+offset, - def->bindBuf, OpLessThanEquals, def->type, def->length); - if (result) + if (!isNull) { + result = AllDataType::compareVal(buffer+offset, + def->bindBuf, OpLessThanEquals, def->type, + def->length); + } + if (result || isNull) AllDataType::copyVal(buffer+offset, def->bindBuf, - def->type, def->length); + def->type, def->length); break; } case AGG_SUM: { @@ -143,105 +333,139 @@ DbRetVal AggTableImpl::execute() break; } case AGG_AVG: { - AllDataType::addVal(buffer+offset, def->bindBuf, def->type); - (*(int*)(buffer+offset + def->length))++; - offset = offset +sizeof(int); //->count + double tmpBuf=0.0; + AllDataType::convertToDouble(&tmpBuf, def->bindBuf, + def->type); + AllDataType::addVal(buffer+offset, &tmpBuf, typeDouble); + (*(int*)(buffer+offset + sizeof(double)))++; break; } case AGG_COUNT: (*(int*)(buffer+offset))++; - if ((*(int*)(buffer+offset)) % 1000000 ==0) - printf("PRABA:%d\n", (*(int*)(buffer+offset))); break; case AGG_UNKNOWN: { - AllDataType::copyVal(buffer+offset, groupFld.bindBuf, - groupFld.type, groupFld.length); + copyValuesFromGrpBindBuf(buffer+offset, def->fldName); break; } } - offset = offset + def->length; + clearFldNull(colpos); + if (def->aType == AGG_AVG) + offset = offset + sizeof(double) + sizeof(int); + else if (def->aType == AGG_COUNT) offset += sizeof(int); + else offset = offset + def->length; + colpos++; } + memcpy(nullInfo, &prjNullInfo, sizeof(long long)); } aggNodeIter = aggNodes.getIterator(); iter.reset(); char *element; + offset = groupOffset+sizeof(long long); while (iter.hasElement()) { def = (AggFldDef*) iter.nextElement(); - if (isGroupSet()) - offset = groupFld.length; - else - offset = 0; - switch(def->atype) - { - case AGG_AVG: { - while (aggNodeIter.hasElement()) { - element = (char*)aggNodeIter.nextElement(); - AllDataType::divVal(element+offset, - *(int*)(element+offset+ def->length), def->type); - } - offset = offset +sizeof(int); + if(def->aType == AGG_AVG) { + aggNodeIter.reset(); + while (aggNodeIter.hasElement()) { + element = (char*)aggNodeIter.nextElement(); + AllDataType::divVal((double *) (element+offset), + *(int *)(element+offset+ sizeof(double)), typeDouble); } + offset = offset + sizeof(double) + sizeof(int); + continue; } - offset = offset + def->length; + else if (def->aType == AGG_COUNT) offset += sizeof(int); + else offset = offset + def->length; } aggNodeIter.reset(); tableHdl->closeScan(); return OK; } -void* AggTableImpl::insertOrGet() + +void* AggTableImpl::getGroupValueBuffer() +{ + memset(grpFldBuffer, 0, groupSize); + AggFldDef *def; + char *offset= (char*)grpFldBuffer; + if (optGrpIntNoNull) { + *(int*)offset = *(int*)grpBindBuf; + return grpFldBuffer; + } + grpNullInfo = 0; + ListIterator giter = fldGroupList.getIterator(); + int colpos = 1; + while((def = (AggFldDef*) giter.nextElement()) != NULL) + { + if (def->isNullable && tableHdl->isFldNull(def->fldName)) markFldNull(colpos); + else AllDataType::copyVal(offset, def->bindBuf, def->type, def->length); + offset = offset + def->length; + colpos++; + } + memcpy(offset, &grpNullInfo, sizeof(int)); + return grpFldBuffer; +} +void* AggTableImpl::insertOrGetAggNode() { char *element; - if (!isGroupSet()) { + if (0 == fldGroupList.size()) { ListIterator aiter = aggNodes.getIterator(); - if (aiter.hasElement()) - return aiter.nextElement(); + if (aiter.hasElement()) return aiter.nextElement(); } else { - //TODO::perf opt for no group - //TODO::if group not set, use another class variable - element = (char*) aggNodeMap.find(groupFld.bindBuf); + void *grpBuffer = getGroupValueBuffer(); + element = (char*) aggNodeMap.find(grpBuffer); if (element) return element; } - /*ListIterator aiter = aggNodes.getIterator(); - while (aiter.hasElement()) { - element = (char*)aiter.nextElement(); - - if (!isGroupSet()) return element; - if (AllDataType::compareVal(element, groupFld.bindBuf, OpEquals, - groupFld.type, groupFld.length)) - { - return element; - } - }*/ element = (char*)malloc(aggNodeSize); + memset(element, 0, aggNodeSize); ListIterator iter = fldList.getIterator(); - AggFldDef *def; - char *offset; - if (isGroupSet()) { - AllDataType::copyVal(element, groupFld.bindBuf, groupFld.type, - groupFld.length); - offset = element + groupFld.length; + AggFldDef *def; + char *offset = element; + grpNullInfo = 0; + //offset += sizeof(int); + ListIterator giter = fldGroupList.getIterator(); + int colpos = 1; + while(giter.hasElement()) + { + def = (AggFldDef*) giter.nextElement(); + if(def->isNullable && tableHdl->isFldNull(def->fldName)) + markFldNull(colpos); + else + AllDataType::copyVal(offset, def->bindBuf, def->type,def->length); + offset = offset + def->length; + colpos++; } - else - offset = element; - + memcpy(offset, &grpNullInfo, sizeof(int)); + offset += sizeof(int); + memset(offset, 0xff, sizeof(long long)); + offset += sizeof(long long); while (iter.hasElement()) { def = (AggFldDef*) iter.nextElement(); - switch(def->atype) { - case AGG_MIN: { *(int*)(offset)=INT_MAX; break; } - case AGG_MAX: { *(int*)(offset)=INT_MIN; break; } - case AGG_SUM: { *(int*)(offset)=0; break; } + switch(def->aType) { + case AGG_MIN: + case AGG_MAX: + { + AllDataType::copyVal(offset, def->bindBuf, def->type, + def->length); + break; + } + case AGG_SUM: + { + AllDataType::copyZeroVal(offset, def->type, def->length); + break; + } case AGG_AVG: { - *(int*)(offset)=0; - *(int*)(offset+ def->length)=0; //count - offset = offset+ sizeof(int); + *(double*)(offset)=0; + *(int*)(offset+ sizeof(double))=0; //count break; } case AGG_COUNT: { *(int*)(offset)=0; break; } } - offset = offset + def->length; + if (def->aType == AGG_AVG) + offset = offset + sizeof(double) + sizeof(int); + else if (def->aType == AGG_COUNT) offset += sizeof(int); + else offset = offset + def->length; } aggNodes.append(element); aggNodeMap.insert(element); @@ -250,13 +474,18 @@ void* AggTableImpl::insertOrGet() void* AggTableImpl::fetch() { - if(aggNodeIter.hasElement()) + while(aggNodeIter.hasElement()) { void *elem = aggNodeIter.nextElement(); + bool result=false; + if (havingPred) { + PredicateImpl *pImpl = (PredicateImpl*)havingPred; + pImpl->evaluateForHaving(result , this, elem); + if (!result) continue; + } copyValuesToBindBuffer(elem); return elem; } - else return NULL; } @@ -289,16 +518,37 @@ DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem) //Iterate through the bind list and copy the value here ListIterator fIter = fldList.getIterator(); AggFldDef *def; - AllDataType::copyVal(groupFld.appBuf, elem, groupFld.type, groupFld.length); - char *colPtr = (char*) elem + groupFld.length; + char *colPtr=element+groupSize; + prjNullInfo = *(long long *) colPtr; + colPtr += sizeof(long long); + int colpos = 1; while (fIter.hasElement()) { def = (AggFldDef*) fIter.nextElement(); + if (isFldNull(colpos)) { + if (def->aType == AGG_AVG) + colPtr += sizeof(double) + sizeof(int); + else if (def->aType == AGG_COUNT) colPtr += sizeof(int); + else colPtr += def->length; + colpos++; + continue; + } if (NULL != def->appBuf) { - AllDataType::copyVal(def->appBuf, colPtr, def->type, def->length); + if (def->aType == AGG_AVG) { + os::memcpy(def->appBuf, colPtr, sizeof(double)); + colPtr = colPtr + sizeof(double) + sizeof(int); + } + else if (def->aType == AGG_COUNT) { + AllDataType::copyVal(def->appBuf, colPtr, typeInt, sizeof(int)); + colPtr += sizeof(int); + } + else { + AllDataType::copyVal(def->appBuf, colPtr, def->type, + def->length); + colPtr = colPtr + def->length; + } } - colPtr = colPtr + def->length; - if(def->atype == AGG_AVG) colPtr = colPtr + sizeof(int); + colpos++; } return OK; } @@ -318,72 +568,91 @@ DbRetVal AggTableImpl::closeScan() } aggNodes.reset(); aggNodeMap.removeAll(); - if(tableHdl) tableHdl->closeScan(); + if (tableHdl) tableHdl->closeScan(); + return OK; } DbRetVal AggTableImpl::close() { - //free memory allocated. make sure that field buffers are freed only once. - //for stmts which has more than one agg on same field needs to be handled safely - closeScan(); - free(groupFld.bindBuf); - groupFld.bindBuf= NULL; - ListIterator iter = fldList.getIterator(); - AggFldDef *elem; - while (iter.hasElement()) - { - elem = (AggFldDef*) iter.nextElement(); - if(!elem->alreadyBinded) free(elem->bindBuf); - delete elem; - } - fldList.reset(); + havingPred = NULL; + delete this; return OK; } -//------------------------------------------------------ -DbRetVal HashMap::insert(void *element) +bool AggTableImpl::isFldNull(const char *name) { - HashMapNode *newNode = new HashMapNode(); - newNode->elem = element; - newNode->next = NULL; - int hashVal = (*(int*) element) % bucketSize; - //printf("Hash val is %d\n", hashVal); - HashMapNode *node = (HashMapNode*) bucket[hashVal]; - if (NULL == node) - { - bucket[hashVal] = newNode; - return OK; + ListIterator it = fldList.getIterator(); + int colpos = 1; + char fldName[IDENTIFIER_LENGTH]; + AggType atp = getAggType(name, fldName); + while (it.hasElement()) { + AggFldDef *def = (AggFldDef *) it.nextElement(); + if (!def->isNullable) return false; + if (atp != AGG_UNKNOWN) { + if (strcmp(def->fldName, fldName)==0 && def->aType == atp) break; + } + else if (strcmp(def->fldName, name)==0) break; + colpos++; } - while(node->next != NULL) ; - node->next = newNode; - return OK; + return isFldNull(colpos); } -void* HashMap::find(void *element) +void AggTableImpl::printPlan(int space) { - int hashVal = (*(int*) element) % bucketSize; - //printf("Hash val is %d\n", hashVal); - if (bucket[hashVal] == NULL) + char spaceBuf[IDENTIFIER_LENGTH]; + memset(spaceBuf, 32, IDENTIFIER_LENGTH); + spaceBuf[space] = '\0'; + PredicateImpl* predImpl = (PredicateImpl*) havingPred; + printf("%s \n", spaceBuf); + printf("%s \n", spaceBuf); + AggFldDef *fldDef=NULL; + ListIterator iter = fldList.getIterator(); + while ((fldDef = (AggFldDef*)iter.nextElement()) != NULL) { - return NULL; + if (fldDef->aType == AGG_UNKNOWN) + printf("%s %s \n", spaceBuf, + fldDef->fldName); + else + printf("%s %s(%s) \n", spaceBuf, + AggNames[fldDef->aType -1], fldDef->fldName); } - HashMapNode *node = (HashMapNode*) bucket[hashVal]; - while(node != NULL) { - if ( (*(int*) node->elem) == (*(int*)element)) return node->elem; - node = node->next; + printf("%s \n", spaceBuf); + printf("%s \n", spaceBuf); + ListIterator giter = fldGroupList.getIterator(); + while ((fldDef = (AggFldDef*)giter.nextElement()) != NULL) + { + printf("%s %s \n", spaceBuf, fldDef->fldName); } - return NULL; + printf("%s \n", spaceBuf); + if (havingPred) predImpl->print(space); + printf("%s \n", spaceBuf); + if (tableHdl) tableHdl->printPlan(space+2); + return; } -void HashMap::removeAll() + +AggType AggTableImpl::getAggType(const char *name, char *fldName) { - for (int i=0; i next; - delete prev; - } - bucket[i]=NULL; - } - return; + char *ptr = (char *)name; + AggType atp = AGG_UNKNOWN; + if (strncmp(name, "COUNT", 5) == 0) { + ptr += strlen("COUNT("); + atp = AGG_COUNT; + } else if (strncmp(name, "MIN", 3) == 0) { + ptr += strlen("MIN("); + atp = AGG_MIN; + } else if (strncmp(name, "MAX", 3) == 0) { + ptr += strlen("MAX("); + atp = AGG_MAX; + } else if (strncmp(name, "SUM", 3) == 0) { + ptr += strlen("SUM("); + atp = AGG_SUM; + } else if (strncmp(name, "AVG", 3) == 0) { + ptr += strlen("AVG("); + atp = AGG_AVG; + } + if (atp == AGG_UNKNOWN) return atp; + strcpy(fldName, ptr); + ptr = fldName; + while (*ptr != ')') ptr++; + *ptr = '\0'; + return atp; } diff --git a/src/storage/BucketIter.cxx b/src/storage/BucketIter.cxx index 2b6bbdd3..4fe61228 100644 --- a/src/storage/BucketIter.cxx +++ b/src/storage/BucketIter.cxx @@ -14,13 +14,14 @@ * * ***************************************************************************/ #include -#include HashIndexNode* BucketIter::next() { if (iter == NULL) return NULL; + if(recordsOver) return NULL; HashIndexNode *node = iter; iter = iter ->next_; printDebug(DM_HashIndex,"BucketIter::next returns %x",node); + if (isUnique) recordsOver = true; return node; } diff --git a/src/storage/BucketList.cxx b/src/storage/BucketList.cxx index a19f01ef..b2e7ad61 100644 --- a/src/storage/BucketList.cxx +++ b/src/storage/BucketList.cxx @@ -21,10 +21,23 @@ DbRetVal BucketList::insert(Chunk *chunk, Database *db, void *key, void*tuple) { DbRetVal rv = OK; HashIndexNode *newNode;// (HashIndexNode*) chunk->allocate(db, &rv); - newNode= (HashIndexNode*) chunk->allocate(db, &rv); - if (NULL == newNode) + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) { - printError(rv, "Unable to allocate HashIndex node"); + rv = OK; + newNode= (HashIndexNode*) chunk->allocate(db, &rv); + if (newNode !=NULL) break; + if (rv != ErrLockTimeOut) + { + printError(rv, "Unable to allocate hash index node"); + return rv; + } + //printError (ErrWarning, "Hash Node Alloc: LockTimeOut Retry:%d", tries); + tries++; + } + if (newNode == NULL){ + printError(rv, "Unable to allocate hash index node after %d retry", Conf::config.getMutexRetries()); return rv; } printDebug(DM_HashIndex,"Hash Index node allocated:%x", newNode); @@ -36,14 +49,25 @@ DbRetVal BucketList::insert(Chunk *chunk, Database *db, void *key, void*tuple) if (NULL == head) { printDebug(DM_HashIndex, "BucketList:insert head is null key:%x",key); - head = newNode; + //head = newNode; + if ( 0 != Mutex::CASL((long*)&head, 0, (long)newNode)) { + printError(ErrLockTimeOut, "Unable to set bucket head..retry\n"); + chunk->free(db, newNode); + return ErrLockTimeOut; + } return OK; } HashIndexNode *it = head; while (NULL != it->next_) it = it->next_; - it->next_ = newNode; + //it->next_ = newNode; + if ( 0 != Mutex::CASL((long*)&it->next_, 0, (long)newNode)) { + printError(ErrLockTimeOut, "Unable to add to bucket..retry\n"); + chunk->free(db, newNode); + return ErrLockTimeOut; + } printDebug(DM_HashIndex, "BucketList:insert adding it to the end of list key:%x", key); + if (rv != OK) printError(ErrSysFatal, "rv is not OK %d\n", rv); return rv; } //Returns 2 if the head itself is removed. @@ -56,11 +80,20 @@ DbRetVal BucketList::remove(Chunk *chunk, Database *db, void *keyPtr) if (ite->ptrToKey_ == keyPtr) { if ( ite == head) { - head = ite->next_; + //head = ite->next_; + if ( 0 != Mutex::CASL((long*)&head, (long)ite, + (long)ite->next_)) { + printError(ErrLockTimeOut, "Unable to set bucket head..retry"); + return ErrLockTimeOut; + } chunk->free(db, ite); return SplCase; } - prev->next_ = ite->next_; + //prev->next_ = ite->next_; + if ( 0 != Mutex::CASL((long*)&prev->next_, (long)prev->next_, (long)ite->next_)) { + printError(ErrLockTimeOut, "Unable to remove hash bucket node..retry"); + return ErrLockTimeOut; + } chunk->free(db, ite); return OK; } @@ -68,5 +101,6 @@ DbRetVal BucketList::remove(Chunk *chunk, Database *db, void *keyPtr) ite = ite->next_; } printError(ErrNotFound, "Node not found in the bucket list"); + printStackTrace(); return ErrNotFound; } diff --git a/src/storage/CatalogTables.cxx b/src/storage/CatalogTables.cxx index 8bd4242d..9b39c54a 100644 --- a/src/storage/CatalogTables.cxx +++ b/src/storage/CatalogTables.cxx @@ -18,7 +18,7 @@ #include #include #include -char ChunkName[MAX_CHUNKS][CHUNK_NAME_LEN]={"UserChunkTableId","LockTableHashBucketId","LockTableMutexId","LockTableId","TransHasTableId","UndoLogTableId","","","","","DatabaseTableId","UserTableId","TableTableId","FieldTableId","AccessTableId","IndexTableId","IndexFieldTableId",""}; +char ChunkName[MAX_CHUNKS][CHUNK_NAME_LEN]={"UserChunkTableId","LockTableHashBucketId","LockTableMutexId","LockTableId","TransHasTableId","UndoLogTableId","","","","","DatabaseTableId","UserTableId","TableTableId","FieldTableId","AccessTableId","IndexTableId","IndexFieldTableId","ForeignKeyTableId","ForeignKeyFieldTableId"}; DbRetVal CatalogTableTABLE::insert(const char *name, int id, size_t size, @@ -92,6 +92,26 @@ DbRetVal CatalogTableTABLE::getChunkAndTblPtr(const char *name, return ErrNotFound; } + +DbRetVal CatalogTableTABLE::setChunkPtr(const char *name, void *firstPage, void *curPage) +{ + Chunk *chk = systemDatabase_->getSystemDatabaseChunk(TableTableId); + ChunkIterator iter = chk->getIterator();; + void *tptr; + while (NULL != (tptr = iter.nextElement())) + { + if (strcmp(((CTABLE*)tptr)->tblName_, name) == 0) + { + //there will be only one row for this table(Primary key) + ((Chunk*)((CTABLE*)tptr)->chunkPtr_)->setFirstPage(firstPage); + ((Chunk*)((CTABLE*)tptr)->chunkPtr_)->setCurPage(curPage); + return OK; + } + } + //table not found in TABLE + return ErrNotFound; +} + List CatalogTableTABLE::getTableList() { List tableList; @@ -177,7 +197,7 @@ void *CatalogTableFIELD::getFieldInfo(void* tptr, FieldList &list) strcpy(fldDef.fldName_, fTuple->fldName_); fldDef.fldName_[IDENTIFIER_LENGTH] = '\0'; fldDef.type_ = fTuple->type_; - fldDef.length_ = os::align(fTuple->length_); + fldDef.length_ = fTuple->length_; fldDef.offset_ = fTuple->offset_; fldDef.isDefault_ = fTuple->isDefault_; os::memcpy(fldDef.defaultValueBuf_, fTuple->defaultValueBuf_, @@ -186,8 +206,9 @@ void *CatalogTableFIELD::getFieldInfo(void* tptr, FieldList &list) fldDef.isUnique_ = fTuple->isUnique_; fldDef.isPrimary_ = fTuple->isPrimary_; fldDef.isAutoIncrement_= fTuple->isAutoIncrement_; - if(fTuple->isAutoIncrement_){ + if(fTuple->isAutoIncrement_){ ptrToAutoVal = &fTuple->autoVal_; + //os::memcpy(fldDef.autoVal_, fTuple->autoVal_,); } list.append(fldDef); } @@ -333,6 +354,34 @@ DbRetVal CatalogTableINDEX::get(const char *name, void *&chunk, void *&hchunk, v return OK; } +DbRetVal CatalogTableINDEX::setChunkPtr(const char *name, ObjectType type, void *bChunk, void *firstPage, void *curPage) +{ + Chunk *fChunk = systemDatabase_->getSystemDatabaseChunk(IndexTableId); + ChunkIterator iter = fChunk->getIterator(); + + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (0 == strcmp(((CINDEX*)data)->indName_, name)) + { + //remove this element and store the tuple ptr + //there will be only one row for this table(Primary key) + if (type == hIdx) { + ((Chunk*) ((CINDEX*)data)->chunkPtr_)->setFirstPage(bChunk); + ((Chunk*) ((CINDEX*)data)->chunkPtr_)->setCurPage(bChunk); + ((Chunk*)((CINDEX*)data)->hashNodeChunk_)->setFirstPage(firstPage); + ((Chunk*)((CINDEX*)data)->hashNodeChunk_)->setCurPage(curPage); + } else if (type == tIdx) { + ((Chunk*) ((CINDEX*)data)->chunkPtr_)->setFirstPage(firstPage); + ((Chunk*) ((CINDEX*)data)->chunkPtr_)->setCurPage(curPage); + ((CINDEX*)data)->hashNodeChunk_ = bChunk; + } + break; + } + } + return OK; +} + int CatalogTableINDEX::getNumIndexes(void *tptr) { Chunk *fChunk = systemDatabase_->getSystemDatabaseChunk(IndexTableId); @@ -346,6 +395,29 @@ int CatalogTableINDEX::getNumIndexes(void *tptr) return numIndex; } +ListIterator CatalogTableINDEXFIELD::getIndexListIterater(char *name) +{ + List indexList; + Chunk *chunk=systemDatabase_->getSystemDatabaseChunk(IndexFieldTableId); + ChunkIterator ifIter = chunk->getIterator(); + void *data = NULL; + while ((data = ifIter.nextElement())!= NULL) + { + IndexInfoForDriver *idxInfo = new IndexInfoForDriver(); + if(strcmp( name,((CTABLE*)(((CINDEXFIELD*)data)->tablePtr))->tblName_) == 0) + { + strcpy(idxInfo->indexName ,((CINDEX*)(((CINDEXFIELD*)data)->indexPtr))->indName_); + strcpy(idxInfo->tableName ,((CTABLE*)(((CINDEXFIELD*)data)->tablePtr))->tblName_); + strcpy(idxInfo->fieldName ,((CFIELD*)(((CINDEXFIELD*)data)->fieldPtr))->fldName_); + idxInfo->type = ((CINDEX*)(((CINDEXFIELD*)data)->indexPtr))->indexType_ ; + idxInfo->isUnique = ((CINDEX*)(((CINDEXFIELD*)data)->indexPtr))->isUnique_; + idxInfo->isPrimary = ((CFIELD*)(((CINDEXFIELD*)data)->fieldPtr))->isPrimary_; + indexList.append(idxInfo); + } + } + return indexList.getIterator(); +} + char* CatalogTableINDEX::getIndexName(void *tptr, int position) { if (position == 0) return NULL; @@ -397,12 +469,21 @@ int CatalogTableINDEX::getUnique(void *iptr) CINDEX *index = (CINDEX*)iptr; return index->isUnique_; } +IndexType CatalogTableINDEX::getType(void *iptr) +{ + CINDEX *index = (CINDEX*)iptr; + return index->indexType_; +} char* CatalogTableINDEX::getName(void *iptr) { CINDEX *index = (CINDEX*)iptr; return index->indName_; } - +int CatalogTableINDEX::getOffsetOfFirstField(void *iptr) +{ + CINDEX *index = (CINDEX*)iptr; + return ((CFIELD*)(((CINDEXFIELD*)(index->fstIndFld_))->fieldPtr))->offset_; +} DbRetVal CatalogTableINDEXFIELD::insert(FieldNameList &fldList, void *indexPtr, void *tblPtr, char **&fptr) @@ -498,6 +579,7 @@ DbRetVal CatalogTableINDEXFIELD::remove(void *iptr) if (((CINDEXFIELD*)data)->indexPtr == iptr) { //remove this element + if(((CFIELD *)((CINDEXFIELD*)data)->fieldPtr)->isUnique_) ((CFIELD *)((CINDEXFIELD*)data)->fieldPtr)->isUnique_ = false; fChunk->free(systemDatabase_, data); printDebug(DM_SystemDatabase,"One Row deleted from INDEXFIELD %x", data); } @@ -588,10 +670,37 @@ void CatalogTableINDEXFIELD::printAllIndex() } } +List CatalogTableUSER::getUserList() +{ + List userList; + Chunk *chk = systemDatabase_->getSystemDatabaseChunk(UserTableId); + ChunkIterator iter = chk->getIterator(); + void *tptr; + while (NULL != (tptr = iter.nextElement())) + { + Identifier *elem = new Identifier(); + strcpy(elem->name, ((CUSER*)tptr)->userName_); + userList.append(elem); + } + return userList; + +} + DbRetVal CatalogTableUSER::insert(const char *name, const char *pass) { Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(UserTableId); DbRetVal rv = OK; + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (0 == strcmp(((CUSER*)data)->userName_, name)) + { + printError(ErrAlready, "User with name \'%s\' already exists ", name); + return ErrAlready; + } + } + CUSER *usrInfo = (CUSER*)tChunk->allocate(systemDatabase_, &rv); if (NULL == usrInfo) { @@ -600,7 +709,8 @@ DbRetVal CatalogTableUSER::insert(const char *name, const char *pass) return rv; } strcpy(usrInfo->userName_, name); - strcpy(usrInfo->password_, os::encrypt(pass, "A0")); + strcpy(usrInfo->password_, pass); + //strcpy(usrInfo->password_, os::encrypt(pass, "A0")); return OK; } @@ -616,7 +726,8 @@ DbRetVal CatalogTableUSER::authenticate(const char *name, const char *pass, if (strcmp(((CUSER*)data)->userName_, name) == 0) { //verify the password - char * enpass = os::encrypt(pass,"A0"); + //char * enpass = os::encrypt(pass,"A0"); + char * enpass = (char*) pass; if (0 == strcmp(enpass, ((CUSER*)data)->password_)) { isAuthenticated = true; @@ -658,10 +769,263 @@ DbRetVal CatalogTableUSER::changePass(const char *name, const char *pass) if (strcmp(((CUSER*)data)->userName_, name) == 0) { //change the password - strcpy(((CUSER*)data)->password_, os::encrypt(pass, "A0")); + strcpy(((CUSER*)data)->password_,pass);// os::encrypt(pass, "A0")); return OK; } } printError(ErrNotExists,"User %s not exists in catalog table", name); return ErrNotExists; } + +DbRetVal CatalogTableFK::insert(char *name, void *tptr, void *tPkptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (0 == strcmp(((CFK*)data)->fkName_, name)) + { + printError(ErrAlready, "Index with name \'%s\' already exists " + "on the table \'%s\'.", name, ((CTABLE *)tptr)->tblName_); + return ErrAlready; + } + + } + + DbRetVal rv =OK; + void *fkptr = tChunk->allocate(systemDatabase_, &rv); + if (NULL == fkptr) + { + printError(rv, "Could not allocate for FK catalog table"); + return rv; + } + CFK *fkTblInfo = (CFK*)fkptr; + strcpy(fkTblInfo->fkName_, name); + fkTblInfo->fkTblPtr_= tptr; + fkTblInfo->pkTblPtr_= tPkptr; + printDebug(DM_SystemDatabase,"One Row inserted into FK %x %s",fkptr, name); + return OK; +} + +DbRetVal CatalogTableFKFIELD::insert(char *cFKName, char **fkFldPtrs, char **pkFldPtrs,int totalFld) +{ + Chunk *tChunk = NULL; + tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (0 == strcmp(((CFK*)data)->fkName_, cFKName)) + { + break; + } + } + tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyFieldTableId); + int i =0; + DbRetVal rv = OK; + while (i < totalFld) + { + void *fieldptr = tChunk->allocate(systemDatabase_, &rv); + if (NULL == fieldptr) + { + printError(rv, "Could not allocate for USER catalog table"); + return rv; + } + CFKFIELD *fldInfo = (CFKFIELD*)fieldptr; + fldInfo->fkPtr_ = data; + fldInfo->pfFldPtr_ = (CFIELD*)pkFldPtrs[i]; + fldInfo->fkFldPtr_ = (CFIELD*)fkFldPtrs[i++]; + //printDebug(DM_TEST,"TYPE %d\n",((CFIELD*)fldInfo->pfFldPtr_)->type_); + //printDebug(DM_TEST,"FK name %s\n",((CFIELD*)fldInfo->fkFldPtr_)->fldName_); + if(!(((CFIELD*)fldInfo->pfFldPtr_)->isUnique_) || !(((CFIELD*)fldInfo->pfFldPtr_)->isNull_)) + { + printError(ErrSysInternal,"Parent Table field should have primary key field "); + tChunk->free(systemDatabase_,fieldptr); + return ErrSysInternal; + } + if(((CFIELD*)fldInfo->pfFldPtr_)->type_!=((CFIELD*)fldInfo->fkFldPtr_)->type_) + { + printError(ErrSysInternal,"Type Missmatch in both PK field and FK field "); + tChunk->free(systemDatabase_,fieldptr); + return ErrSysInternal; + } + printDebug(DM_SystemDatabase,"One Row inserted into FKFIELD %x", fldInfo); + } + return OK; +} +DbRetVal CatalogTableFK::remove(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (data == ctptr) + { + tChunk->free(systemDatabase_,data); + printDebug(DM_SystemDatabase,"One Row deleted from FKFIELD %x", data); + } + + } + return OK; +} + +DbRetVal CatalogTableFKFIELD::remove(void *cFKfld) +{ + Chunk *fChunk = NULL; + fChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyFieldTableId); + ChunkIterator iter = fChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (((CFKFIELD*)data)->fkPtr_== cFKfld ) + { + fChunk->free(systemDatabase_, data); + printDebug(DM_SystemDatabase,"One Row deleted from CFKFIELD %x", data); + } + } + return OK; +} +void *CatalogTableFK::getFkCTable(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->fkTblPtr_== ctptr) + { + return data; + } + + } + return NULL; +} +int CatalogTableFK::getNumFkTable(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int count=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->pkTblPtr_== ctptr) + { + count++; + } + } + return count; +} + +bool CatalogTableFK::isFkTable(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int count=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->fkTblPtr_== ctptr) + { + return true; + } + } + return false; +} +int CatalogTableFK::getNoOfFkTable(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int count=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->pkTblPtr_== ctptr) + { + count++; + } + } + return count; +} + +int CatalogTableFK::getNoOfPkTable(void *ctptr) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int count=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->fkTblPtr_== ctptr) + { + count++; + } + } + return count; +} + +void CatalogTableFK::getPkTableName(void *ctptr,char **&array) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int i=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->fkTblPtr_== ctptr) + { + array[i++] = ((CTABLE*)((CFK*)data)->pkTblPtr_)->tblName_; + } + } +} +void CatalogTableFK::getFkTableName(void *ctptr,char **&array) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + int i=0; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->pkTblPtr_== ctptr) + { + array[i++] = ((CTABLE*)((CFK*)data)->fkTblPtr_)->tblName_; + } + } +} + + +DbRetVal CatalogTableFK::getPkFkFieldInfo(void *cpkptr, void *cfkptr, FieldNameList &pklist,FieldNameList &fklist) +{ + Chunk *tChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyTableId); + ChunkIterator iter = tChunk->getIterator(); + void *data = NULL; + while ((data = iter.nextElement())!= NULL) + { + if (((CFK*)data)->pkTblPtr_== cpkptr && ((CFK*)data)->fkTblPtr_ == cfkptr) + { + break; + } + } + if(data == NULL) + { + printError(ErrNotExists,"Foreign Key field CFK not found"); + return ErrNotExists; + } + Chunk *fChunk = systemDatabase_->getSystemDatabaseChunk(ForeignKeyFieldTableId); + iter = fChunk->getIterator(); + void *fdata=NULL; + while ((fdata = iter.nextElement())!= NULL) + { + if (((CFKFIELD*)fdata)->fkPtr_==data) + { + //printDebug(DM_TEST,"PK Field name %s\n",((CFIELD*)((CFKFIELD*)fdata)->pfFldPtr_)->fldName_); + //printDebug(DM_TEST,"FK Field name %s\n",((CFIELD*)((CFKFIELD*)fdata)->fkFldPtr_)->fldName_); + pklist.append(((CFIELD*)((CFKFIELD*)fdata)->pfFldPtr_)->fldName_); + fklist.append(((CFIELD*)((CFKFIELD*)fdata)->fkFldPtr_)->fldName_); + } + } + return OK; +} + + diff --git a/src/storage/Chunk.cxx b/src/storage/Chunk.cxx index 78db60b2..f906e7b8 100644 --- a/src/storage/Chunk.cxx +++ b/src/storage/Chunk.cxx @@ -28,7 +28,7 @@ void Chunk::setSize(size_t size) { - size_t needSize = size + sizeof(int); + size_t needSize = size + sizeof(long); size_t multiple = (size_t) os::floor(needSize / sizeof(size_t)); size_t rem = needSize % sizeof(size_t); if (0 == rem) @@ -51,13 +51,15 @@ void* Chunk::allocateForLargeDataSize(Database *db) if (pageInfo->hasFreeSpace_ == 1) { char *data = ((char*)curPage_) + sizeof(PageInfo); - pageInfo->hasFreeSpace_ =0; - *((int*)data) = 1; + //pageInfo->hasFreeSpace_ =0; + int retVal = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0); + if (retVal !=0) printError(ErrSysFatal, "Unable to set hashFreeSpace flag"); + *((InUse*)data) = 1; + //Mutex::CAS((InUse*)data , 0, 1); db->releaseAllocDatabaseMutex(); - return data + sizeof(int); + return data + sizeof(InUse); } - //no space in curpage , get new page from database pageInfo = (PageInfo*)db->getFreePage(allocSize_); if (NULL == pageInfo) @@ -68,25 +70,39 @@ void* Chunk::allocateForLargeDataSize(Database *db) } printDebug(DM_Alloc, "Chunk ID:%d Large Data Item newPage:%x", chunkID_, pageInfo); - int multiple = os::floor(allocSize_ / PAGE_SIZE); + int multiple = (int) os::floor(allocSize_ / PAGE_SIZE); int offset = ((multiple + 1) * PAGE_SIZE); pageInfo->setPageAsUsed(offset); //create the link - ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo; + //((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo; + int retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_), + (long)(((PageInfo*)curPage_)->nextPage_), (long)pageInfo); + if(retVal !=0) { + printError(ErrLockTimeOut, "Fatal: Unable to create page link."); + } + //Make this as current page - curPage_ = (Page*) pageInfo; + //curPage_ = (Page*) pageInfo; + retVal = Mutex::CASL((long*) &curPage_, (long)curPage_, (long)pageInfo); + if(retVal !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to set current page"); + } + char* data = ((char*)curPage_) + sizeof(PageInfo); - //TODO::check whether it is locked - *((int*)data) = 1; - pageInfo->hasFreeSpace_ =0; + retVal = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0); + if(retVal !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to set hasFreeSpace"); + } + *((InUse*)data) = 1; + //Mutex::CAS((InUse*)data , 0, 1); db->releaseAllocDatabaseMutex(); - return data + sizeof(int); + return data + sizeof(InUse); } -void* Chunk::allocateFromFirstPage(Database *db, int noOfDataNodes) +void* Chunk::allocateFromFirstPage(Database *db, int noOfDataNodes, DbRetVal *status) { PageInfo *pageIter = ((PageInfo*)firstPage_); printDebug(DM_Alloc, "Chunk ID:%d. No free page in database", @@ -101,39 +117,49 @@ void* Chunk::allocateFromFirstPage(Database *db, int noOfDataNodes) data = ((char*)pageIter) + sizeof(PageInfo); if (pageIter->hasFreeSpace_ == 1) { - for (i = 0; i< noOfDataNodes; i++) + for (i = 0; i< noOfDataNodes ; i++) { - if (1 == *((int*)data)) + if (1 == *((InUse*)data)) data = data + allocSize_; else break; } - if (i != noOfDataNodes ) break; + if (i != noOfDataNodes) break; } printDebug(DM_Alloc, "Chunk ID: %d Page :%x does not have free nodes", chunkID_, pageIter); pageIter = (PageInfo*)((PageInfo*) pageIter)->nextPage_; } - if (NULL == pageIter) return NULL; + if (NULL == pageIter) { + *status = ErrNoMemory; + return NULL; + } printDebug(DM_Alloc,"ChunkID:%d Scan for free node End:Page :%x", chunkID_, pageIter); - *((int*)data) = 1; - return data + sizeof(int); - + //*((InUse*)data) = 1; + int ret = Mutex::CAS((InUse*)data , 0, 1); + if(ret !=0) { + *status = ErrLockTimeOut; + //printError(ErrLockTimeOut, "Unable to allocate from first page. Retry..."); + return NULL; + } + return data + sizeof(InUse); } -void* Chunk::allocateFromNewPage(Database *db) +void* Chunk::allocateFromNewPage(Database *db, DbRetVal *status) { DbRetVal ret = db->getAllocDatabaseMutex(); if (ret != 0) { - printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex"); + printDebug(DM_Warning,"Unable to acquire alloc database Mutex Chunkid:%d", chunkID_); + *status = ErrLockTimeOut; return NULL; } //get a new page from db Page *page = db->getFreePage(); - if (page == NULL) - { + if (page == NULL) { + printError(ErrNoMemory, "Unable to allocate page"); db->releaseAllocDatabaseMutex(); + *status = ErrNoMemory; return NULL; } printDebug(DM_Alloc, "ChunkID:%d Normal Data Item newPage:%x", @@ -142,17 +168,39 @@ void* Chunk::allocateFromNewPage(Database *db) PageInfo *pInfo = (PageInfo*)page; pInfo->setPageAsUsed(0); + char* data = ((char*)page) + sizeof(PageInfo); + *((InUse*)data) = 1; + //Mutex::CAS((int*)data , 0, 1); + //create the link between old page and the newly created page PageInfo* pageInfo = ((PageInfo*)curPage_); - pageInfo->nextPage_ = page; + + long oldPage = (long)pageInfo->nextPage_; + //pageInfo->nextPage_ = page; + int retVal = Mutex::CASL((long*)&pageInfo->nextPage_ , (long)pageInfo->nextPage_, (long)page); + if(retVal !=0) { + *((InUse*)data) = 0; + pInfo->setPageAsFree(); + printDebug(DM_Warning, "Unable to get lock to set chunk list."); + *status = ErrLockTimeOut; + return NULL; + } //make this new page as the current page - curPage_ = page; + //curPage_ = page; + retVal = Mutex::CASL((long*)&curPage_ , (long)curPage_, (long)page); + if(retVal !=0) { + *((InUse*)data) = 0; + pInfo->setPageAsFree(); + retVal = Mutex::CASL((long*)&pageInfo->nextPage_ , (long)pageInfo->nextPage_, (long)oldPage); + if (retVal !=0) printError(ErrSysFatal, "Fatal: Unable to reset the nextPage"); + printDebug(DM_Warning, "Unable to get lock to set curPage"); + *status = ErrLockTimeOut; + return NULL; + } - char* data = ((char*)page) + sizeof(PageInfo); - *((int*)data) = 1; db->releaseAllocDatabaseMutex(); - return data + sizeof(int); + return data + sizeof(InUse); } //Allocates memory to store data @@ -165,7 +213,7 @@ void* Chunk::allocate(Database *db, DbRetVal *status) { PageInfo* pageInfo = ((PageInfo*)curPage_); - int noOfDataNodes= (int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); + int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); char *data = ((char*)curPage_) + sizeof(PageInfo); printDebug(DM_Alloc, "Chunk::allocate id:%d curPage:%x noOfDataNodes:%d", chunkID_, curPage_, noOfDataNodes); @@ -184,19 +232,19 @@ void* Chunk::allocate(Database *db, DbRetVal *status) return data; } - int ret = getChunkMutex(db->procSlot); + /*int ret = getChunkMutex(db->procSlot); if (ret != 0) { if (status != NULL) *status = ErrLockTimeOut; printError(ErrLockTimeOut,"Unable to acquire chunk Mutex"); return NULL; - } + }*/ int i = noOfDataNodes; if (pageInfo->hasFreeSpace_ == 1) { for (i = 1; i< noOfDataNodes; i++) { - if (*((int*)data) == 1) data = data + allocSize_; + if (*((InUse*)data) == 1) data = data + allocSize_; else break; } @@ -205,82 +253,95 @@ void* Chunk::allocate(Database *db, DbRetVal *status) chunkID_, i); //It comes here if the pageInfo->hasFreeSpace ==0 //or there are no free data space in this page - if (i == noOfDataNodes && *((int*)data) == 1) + if (i == noOfDataNodes && *((InUse*)data) == 1) { printDebug(DM_Alloc, "ChunkID:%d curPage does not have free nodes.", chunkID_); //there are no free data space in this page - pageInfo->hasFreeSpace_ = 0; - if (chunkID_ == LockTableId || chunkID_ == TransHasTableId) + //pageInfo->hasFreeSpace_ = 0; + int ret = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0); + if(ret !=0) { + *status = ErrLockTimeOut; + printDebug(DM_Warning, "Unable to set hasFreespace"); + return NULL; + } + //if (chunkID_ == LockTableId || chunkID_ == TransHasTableId) { - data = (char*) allocateFromFirstPage(db, noOfDataNodes); - if (NULL == data) + *status = OK; + data = (char*) allocateFromFirstPage(db, noOfDataNodes, status); + if (NULL == data && *status != ErrLockTimeOut) { - data = (char*) allocateFromNewPage(db); - if (data == NULL) + *status = OK; + data = (char*) allocateFromNewPage(db, status); + if (data == NULL && *status != ErrLockTimeOut) { printError(ErrNoMemory, "No memory in any of the pages:Increase db size"); - if (status != NULL) *status = ErrNoMemory; + *status = ErrNoMemory; } } } - else + /*else { - data = (char*) allocateFromNewPage(db); - if (NULL == data) + data = (char*) allocateFromNewPage(db, status); + if (NULL == data && *status != ErrLockTimeOut) { data = (char*) allocateFromFirstPage(db, noOfDataNodes); if (data == NULL) { printError(ErrNoMemory, "No memory in any of the pages:Increase db size"); - if (status != NULL) *status = ErrNoMemory; + *status = ErrNoMemory; } } - } - releaseChunkMutex(db->procSlot); + }*/ + //releaseChunkMutex(db->procSlot); return data; } - *((int*)data) = 1; - releaseChunkMutex(db->procSlot); - return data + sizeof(int); + //*((InUse*)data) = 1; + int ret = Mutex::CAS((InUse*)data , 0, 1); + if(ret !=0) { + *status = ErrLockTimeOut; + printDebug(DM_Warning, "Unable to set isUsed : retry..."); + return NULL; + } + //releaseChunkMutex(db->procSlot); + return data + sizeof(InUse); } void* Chunk::allocateForLargeDataSize(Database *db, size_t size) { //no need to take chunk mutexes for this, as we are taking alloc database mutex - int multiple = os::floor(size / PAGE_SIZE); + int multiple = (int) os::floor(size / PAGE_SIZE); int offset = ((multiple + 1) * PAGE_SIZE); PageInfo* pageInfo = ((PageInfo*)curPage_); - DbRetVal ret = db->getAllocDatabaseMutex(); - if (ret != 0) - { - printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex"); - return NULL; - } - if(0==allocSize_) + if(0==allocSize_) pageInfo = (PageInfo*)db->getFreePage(size); else pageInfo = (PageInfo*)db->getFreePage(allocSize_); if (NULL == pageInfo) { - db->releaseAllocDatabaseMutex(); printError(ErrNoMemory,"No more free pages in the database:Increase db size"); return NULL; } - printDebug(DM_VarAlloc,"Chunk::allocate Large Data Item id:%d Size:%d curPage:%x ", + printDebug(DM_VarAlloc,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ", chunkID_, size, curPage_); - if(allocSize_!=0){ + //TODO:: logic pending + if(allocSize_!=0){ //large size allocate for FixedSize data pageInfo->nextPageAfterMerge_ = ((char*)pageInfo + offset); ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo; curPage_ = (Page*) pageInfo; char* data = ((char*)curPage_) + sizeof(PageInfo); - *((int*)data) = 1; + //*((InUse*)data) = 1; + int ret = Mutex::CAS((InUse*)data , 0, 1); + if(ret !=0) { + printError(ErrLockTimeOut, "Lock Timeout: retry..."); + return NULL; + } pageInfo->isUsed_=1; - pageInfo->hasFreeSpace_ = 0; - db->releaseAllocDatabaseMutex(); - return data + sizeof(int); + ret = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0); + if (ret !=0) printError(ErrSysFatal, "Unable to set hashFreeSpace"); + return data + sizeof(InUse); }else{ //large size allocate for varSize data VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)pageInfo) + sizeof(PageInfo)); @@ -288,12 +349,14 @@ void* Chunk::allocateForLargeDataSize(Database *db, size_t size) ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo; curPage_ = (Page*) pageInfo; varInfo->size_= size; - varInfo->isUsed_= 1; + int ret = Mutex::CAS(&varInfo->isUsed_ , varInfo->isUsed_, 1); + if(ret !=0) { + printError(ErrLockTimeOut, "Unable to get lock for var alloc. Retry..."); + return NULL; + } pageInfo->isUsed_=1; - db->releaseAllocDatabaseMutex(); return (char *) varInfo + sizeof(VarSizeInfo); } - //REDESIGN MAY BE REQUIRED:Lets us live with this for now. //what happens to the space lets say 10000 bytes is allocated //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted @@ -301,51 +364,76 @@ void* Chunk::allocateForLargeDataSize(Database *db, size_t size) //Will be coded at later stage as this is developed to support //undo logging and currently we shall assume that the logs generated //wont be greater than PAGE_SIZE. - db->releaseAllocDatabaseMutex(); return NULL; } -void* Chunk::allocFromNewPageForVarSize(Database *db, size_t size) +void* Chunk::allocFromNewPageForVarSize(Database *db, size_t size, int pslot, DbRetVal *rv) { //Should be called only for data items getAllocDatabaseMutex(); if (ret != 0) { printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex"); return NULL; } - - void *vnode = varSizeFirstFitAllocate(size); - if (vnode != NULL) - { - db->releaseAllocDatabaseMutex(); - return vnode; - } - Page *newPage = db->getFreePage(); - db->releaseAllocDatabaseMutex(); if (NULL == newPage) { + db->releaseAllocDatabaseMutex(); return NULL; } printDebug(DM_VarAlloc, "ChunkID:%d New Page: %x ", chunkID_, newPage); PageInfo *pInfo = (PageInfo*) newPage; pInfo->setPageAsUsed(0); - createDataBucket(newPage, PAGE_SIZE, size); - - ((PageInfo*)curPage_)->nextPage_ = newPage; - curPage_ = newPage; + if (1 == createDataBucket(newPage, PAGE_SIZE, size, pslot)) + { + printError(ErrSysFatal, "Split failed in new page...Should never happen"); + *rv = ErrSysFatal; + db->releaseAllocDatabaseMutex(); + return NULL; + } + long oldPage = (long)((PageInfo*)curPage_)->nextPage_; + //((PageInfo*)curPage_)->nextPage_ = newPage; + int retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_), + (long)(((PageInfo*)curPage_)->nextPage_), (long)newPage); + if(retVal !=0) { + printError(ErrSysFatal, "Unable to get lock to set chunk next page"); + pInfo->setPageAsFree(); + db->releaseAllocDatabaseMutex(); + *rv = ErrSysFatal; + return NULL; + } + //curPage_ = newPage; + retVal = Mutex::CASL((long*) &curPage_, (long)curPage_, (long)newPage); + if(retVal !=0) { + printError(ErrSysFatal, "Unable to get lock to set curPage"); + retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_), + (long)(((PageInfo*)curPage_)->nextPage_), (long)oldPage); + if (retVal !=0 ) printError(ErrSysFatal, "Unable to reset curPage"); + pInfo->setPageAsFree(); + db->releaseAllocDatabaseMutex(); + *rv = ErrSysFatal; + return NULL; + } + db->releaseAllocDatabaseMutex(); char *data= ((char*)newPage) + sizeof(PageInfo) + sizeof(VarSizeInfo); return data; } //Allocates from the current page of the chunk. //Scans through the VarSizeInfo objects in the page and gets the free slot -void* Chunk::allocateFromCurPageForVarSize(size_t size) +void* Chunk::allocateFromCurPageForVarSize(size_t size, int pslot, DbRetVal *rv) { //Should be called only for data items isUsed_) { if( size + sizeof(VarSizeInfo) < varInfo->size_) { - splitDataBucket(varInfo, size); + if (1 == splitDataBucket(varInfo, size, pslot, rv)) + { + printDebug(DM_Warning, "Unable to split the data bucket"); + releaseChunkMutex(pslot); + return NULL; + } printDebug(DM_VarAlloc, "Chunkid:%d splitDataBucket: Size: %d Item:%x ", chunkID_, size, varInfo); + releaseChunkMutex(pslot); return (char*)varInfo + sizeof(VarSizeInfo); } else if (size == varInfo->size_) { - varInfo->isUsed_ = 1; + //varInfo->isUsed_ = 1; + int ret = Mutex::CAS(&varInfo->isUsed_ , 0, 1); + if(ret !=0) { + printDebug(DM_Warning, "Unable to get lock for var alloc size:%d ", size); + *rv = ErrLockTimeOut; + releaseChunkMutex(pslot); + return NULL; + } + releaseChunkMutex(pslot); return (char *) varInfo + sizeof(VarSizeInfo); } @@ -373,6 +476,7 @@ void* Chunk::allocateFromCurPageForVarSize(size_t size) varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo) +varInfo->size_); } + releaseChunkMutex(pslot); return NULL; } @@ -392,29 +496,30 @@ void* Chunk::allocate(Database *db, size_t size, DbRetVal *status) //TODO::During the scan, merge nearby nodes if both are free //if not available then allocate new page - size_t alignedSize = os::align(size); + size_t alignedSize = os::alignLong(size); void *data = NULL; - /* int ret = getChunkMutex(db->procSlot); + /*int ret = getChunkMutex(db->procSlot); if (ret != 0) { printError(ErrLockTimeOut,"Unable to acquire chunk Mutex"); *status = ErrLockTimeOut; return NULL; }*/ - if (alignedSize > PAGE_SIZE) + if (alignedSize > PAGE_SIZE ) { data = allocateForLargeDataSize(db, alignedSize); } else { - data = allocateFromCurPageForVarSize(alignedSize); + data = allocateFromCurPageForVarSize(alignedSize, db->procSlot, status); if (NULL == data) { + *status = OK; //No available spaces in the current page. //allocate new page - data= allocFromNewPageForVarSize(db, alignedSize); - if (NULL == data) { + data= allocFromNewPageForVarSize(db, alignedSize, db->procSlot, status); + if (NULL == data && *status !=ErrLockTimeOut) { printError(ErrNoMemory, "No memory in any of the pages:Increase db size"); - if (status != NULL) *status = ErrNoMemory; + *status = ErrNoMemory; } } } @@ -423,13 +528,14 @@ void* Chunk::allocate(Database *db, size_t size, DbRetVal *status) } //Assumes chunk mutex is already taken, before calling this -void* Chunk::varSizeFirstFitAllocate(size_t size) +void* Chunk::varSizeFirstFitAllocate(size_t size, int pslot, DbRetVal *rv) { printDebug(DM_VarAlloc, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x", size, firstPage_); Page *page = ((PageInfo*)firstPage_); - size_t alignedSize = os::align(size); + size_t alignedSize = os::alignLong(size); + if ( 0 != getChunkMutex(pslot)) { *rv = ErrLockTimeOut; return NULL; } while(NULL != page) { VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo)); @@ -439,12 +545,26 @@ void* Chunk::varSizeFirstFitAllocate(size_t size) { if( alignedSize +sizeof(VarSizeInfo) < varInfo->size_) { - splitDataBucket(varInfo, alignedSize); + if( 1 == splitDataBucket(varInfo, alignedSize, pslot, rv)) + { + printDebug(DM_Warning, "Unable to split the data bucket"); + releaseChunkMutex(pslot); + return NULL; + } + releaseChunkMutex(pslot); return ((char*)varInfo) + sizeof(VarSizeInfo); } else if (alignedSize == varInfo->size_) { - varInfo->isUsed_ = 1; + //varInfo->isUsed_ = 1; + int ret = Mutex::CAS((int*)&varInfo->isUsed_, 0, 1); + if(ret !=0) { + printDebug(DM_Warning,"Unable to get lock to set isUsed flag."); + *rv = ErrLockTimeOut; + releaseChunkMutex(pslot); + return NULL; + } printDebug(DM_VarAlloc, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo) +sizeof(VarSizeInfo)); + releaseChunkMutex(pslot); return ((char *) varInfo) + sizeof(VarSizeInfo); } } @@ -454,21 +574,21 @@ void* Chunk::varSizeFirstFitAllocate(size_t size) printDebug(DM_VarAlloc, "Chunk:This page does not have free data nodes page:%x", page); page = ((PageInfo*) page)->nextPage_; } + releaseChunkMutex(pslot); return NULL; } void Chunk::freeForVarSizeAllocator(void *ptr, int pslot) { - int ret = getChunkMutex(pslot); + /*int ret = getChunkMutex(pslot); if (ret != 0) { printError(ErrLockTimeOut,"Unable to acquire chunk Mutex"); return; - } + }*/ VarSizeInfo *varInfo = (VarSizeInfo*)((char*)ptr- sizeof(VarSizeInfo)); - varInfo->isUsed_ = 0; - if(varInfo->size_ > (PAGE_SIZE - (sizeof(VarSizeInfo)+sizeof(PageInfo)))) - { + //varInfo->isUsed_ = 0; + if(varInfo->size_ > (PAGE_SIZE - (sizeof(VarSizeInfo)+sizeof(PageInfo)))) { PageInfo *pageInfo = (PageInfo*)((char*)varInfo - sizeof(PageInfo)); PageInfo *pInfo = (PageInfo*)firstPage_, *prev = (PageInfo*)firstPage_; bool found = false; @@ -486,14 +606,18 @@ void Chunk::freeForVarSizeAllocator(void *ptr, int pslot) } if(curPage_== pageInfo) {curPage_ = prev ; } pageInfo->isUsed_ = 0; - pageInfo->nextPageAfterMerge_ = NULL; + pageInfo->nextPageAfterMerge_ = NULL; pageInfo->hasFreeSpace_ = 1; prev->nextPage_ = pageInfo->nextPage_; } - varInfo->isUsed_ = 0; + int ret = Mutex::CAS((int*)&varInfo->isUsed_, 1, 0); + if(ret !=0) { + printError(ErrAlready, "Fatal: Varsize double free for %x", ptr); + } printDebug(DM_VarAlloc,"chunkID:%d Unset isUsed for %x", chunkID_, varInfo); - releaseChunkMutex(pslot); + //releaseChunkMutex(pslot); return; + } void Chunk::freeForLargeAllocator(void *ptr, int pslot) @@ -507,7 +631,7 @@ void Chunk::freeForLargeAllocator(void *ptr, int pslot) return; } PageInfo *pageInfo = (PageInfo*)(((char*) - ptr) - (sizeof(PageInfo) + sizeof(int))); + ptr) - (sizeof(PageInfo) + sizeof(long))); PageInfo *pInfo = (PageInfo*)firstPage_, *prev = (PageInfo*)firstPage_; bool found = false; while(!found) @@ -524,15 +648,25 @@ void Chunk::freeForLargeAllocator(void *ptr, int pslot) } os::memset(((char*)pageInfo+sizeof(PageInfo)), 0 , allocSize_); if(((PageInfo*)firstPage_)->nextPage_ != NULL){ - pageInfo->isUsed_ = 0; - pageInfo->nextPageAfterMerge_ = NULL; - pageInfo->hasFreeSpace_ = 1; - if(pageInfo == firstPage_ && ((PageInfo*)firstPage_)->nextPage_ != NULL) - firstPage_ = pageInfo->nextPage_ ; - else - prev->nextPage_ = pageInfo->nextPage_; + pageInfo->nextPageAfterMerge_ = NULL; + //pageInfo->isUsed_ = 0; + ret = Mutex::CAS((int*)&pageInfo->isUsed_, pageInfo->isUsed_, 0); + if (ret != 0) printError(ErrSysFatal, "Unable to set isUsed flag"); + //pageInfo->hasFreeSpace_ = 1; + ret = Mutex::CAS((int*)&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 1); + if (ret != 0) printError(ErrSysFatal, "Unable to set hasFreeSpace flag"); + if(pageInfo == firstPage_ && ((PageInfo*)firstPage_)->nextPage_ != NULL) + //firstPage_ = pageInfo->nextPage_ ; + ret = Mutex::CASL((long*)&firstPage_, (long) firstPage_, + (long)pageInfo->nextPage_); + if (ret != 0) printError(ErrSysFatal, "Unable to set firstPage"); + else { + //prev->nextPage_ = pageInfo->nextPage_; + ret = Mutex::CASL((long*)&prev->nextPage_, (long) prev->nextPage_, + (long)pageInfo->nextPage_); + if (ret != 0) printError(ErrSysFatal, "Unable to set nextPage"); + } } - releaseChunkMutex(pslot); return; } @@ -545,34 +679,51 @@ void Chunk::free(Database *db, void *ptr) freeForVarSizeAllocator(ptr, db->procSlot); return; } - int noOfDataNodes =os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_); + int noOfDataNodes =(int) os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_); if (0 == noOfDataNodes) { freeForLargeAllocator(ptr, db->procSlot); return; } - int ret = getChunkMutex(db->procSlot); + /*int ret = getChunkMutex(db->procSlot); if (ret != 0) { printError(ErrLockTimeOut,"Unable to acquire chunk Mutex"); return; - } + }*/ //below is the code for freeing in fixed size allocator //unset the used flag - *((int*)ptr -1 ) = 0; + //*((int*)ptr -1 ) = 0; + if (*((InUse*)ptr -1 ) == 0) { + printError(ErrSysFatal, "Fatal:Data node already freed %x Chunk:%d", ptr, chunkID_); + //return; + } + int ret = Mutex::CAS(((InUse*)ptr -1), 1, 0); + if(ret !=0) { + printError(ErrSysFatal, "Unable to get lock to free for %x", ptr); + return; + } PageInfo *pageInfo; pageInfo = getPageInfo(db, ptr); if (NULL == pageInfo) { - printError(ErrSysFatal,"Probable Data corruption: pageInfo is NULL", pageInfo ); - releaseChunkMutex(db->procSlot); + printError(ErrSysFatal,"Fatal: pageInfo is NULL", pageInfo ); + //releaseChunkMutex(db->procSlot); return; } //set the pageinfo where this ptr points - pageInfo->hasFreeSpace_ = 1; - releaseChunkMutex(db->procSlot); + //pageInfo->hasFreeSpace_ = 1; + if (! (pageInfo->hasFreeSpace_ == 0 || pageInfo->hasFreeSpace_ == 1)) { + printError(ErrSysFatal, "Fatal: hasFreeSpace has invalid value:%d for page %x", pageInfo->hasFreeSpace_, pageInfo); + return; + } + ret = Mutex::CAS((int*)&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 1); + if(ret !=0) { + printError(ErrSysFatal, "Unable to get lock to set hasFreeSpace"); + } + //releaseChunkMutex(db->procSlot); return; } @@ -637,7 +788,7 @@ long Chunk::getTotalDataNodes() return totalNodes; } - int noOfDataNodes=os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); + int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); PageInfo* pageInfo = ((PageInfo*)firstPage_); char *data = ((char*)firstPage_) + sizeof(PageInfo); int i=0; @@ -646,7 +797,7 @@ long Chunk::getTotalDataNodes() data = ((char*)pageInfo) + sizeof(PageInfo); for (i = 0; i< noOfDataNodes; i++) { - if (*((int*)data) == 1) { totalNodes++;} + if (*((InUse*)data) == 1) { totalNodes++;} data = data + allocSize_; } pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ; @@ -655,7 +806,7 @@ long Chunk::getTotalDataNodes() } //TODO::for other type of allocators -int Chunk::compact() +int Chunk::compact(int procSlot) { PageInfo* pageInfo = ((PageInfo*)firstPage_); PageInfo* prevPage = pageInfo; @@ -663,6 +814,12 @@ int Chunk::compact() { return 0; } + int ret = getChunkMutex(procSlot); + if (ret != 0) + { + printError(ErrLockTimeOut,"Unable to acquire chunk Mutex"); + return ret; + } pageInfo = (PageInfo*)pageInfo->nextPage_; if (0 == allocSize_) { @@ -691,23 +848,26 @@ int Chunk::compact() while( pageInfo != NULL ) { bool flag = false; - int noOfDataNodes=os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); + int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_); char *data = ((char*)pageInfo) + sizeof(PageInfo); - for (int i = 0; i< noOfDataNodes -1; i++) + for (int i = 0; i< noOfDataNodes ; i++) { - if (1 == *((int*)data)) { flag = true; break; } + if (1 == *((InUse*)data)) { flag = true; break; } data = data +allocSize_; } if (!flag) { printDebug(DM_Alloc,"Freeing unused page in fixed allocator %x\n", pageInfo); prevPage->nextPage_ = pageInfo->nextPage_; pageInfo->isUsed_ = 0; + pageInfo = (PageInfo*)(((PageInfo*)prevPage)->nextPage_) ; + }else{ + prevPage = pageInfo; + pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ; } - prevPage = pageInfo; - pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ; printDebug(DM_Alloc,"compact iter %x\n", pageInfo); } } + releaseChunkMutex(procSlot); return 0; } @@ -740,27 +900,67 @@ int Chunk::destroyMutex() { return chunkMutex_.destroy(); } -void Chunk::splitDataBucket(VarSizeInfo *varInfo, size_t needSize) +int Chunk::splitDataBucket(VarSizeInfo *varInfo, size_t needSize, int pSlot, DbRetVal *rv) { int remSpace = varInfo->size_ - sizeof(VarSizeInfo) - needSize; - varInfo->isUsed_ = 1; - varInfo->size_ = needSize; - varInfo = (VarSizeInfo*)((char*)varInfo + + //varInfo->isUsed_ = 1; + int ret = Mutex::CAS((int*)&varInfo->isUsed_ , 0, 1); + if(ret !=0) { + printDebug(DM_Warning, "Unable to set I isUsed flag"); + *rv = ErrLockTimeOut; + return 1; + } + //varInfo->size_ = needSize; + ret = Mutex::CAS((int*)&varInfo->size_, varInfo->size_ , needSize); + if(ret !=0) { + printError(ErrSysFatal, "Unable to set I size flag"); + ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0); + if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag"); + *rv = ErrSysFatal; + return 1; + } + VarSizeInfo *varInfo2 = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo) + varInfo->size_); - varInfo->isUsed_ = 0; - varInfo->size_ = remSpace; + //varInfo2->isUsed_ = 0; + ret = Mutex::CAS((int*)&varInfo2->isUsed_ , varInfo2->isUsed_, 0); + if(ret !=0) { + printError(ErrSysFatal, "Unable to set II isUsed flag"); + ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0); + if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag"); + *rv = ErrSysFatal; + return 1; + } + //varInfo2->size_ = remSpace; + ret = Mutex::CAS((int*)&varInfo2->size_, varInfo2->size_ , remSpace); + if(ret !=0) { + printError(ErrSysFatal, "Unable to set II size flag"); + ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0); + if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag"); + *rv = ErrSysFatal; + return 1; + } printDebug(DM_VarAlloc, "Remaining space is %d\n", remSpace); - return; + return 0; } -void Chunk::createDataBucket(Page *page, size_t totalSize, size_t needSize) +int Chunk::createDataBucket(Page *page, size_t totalSize, size_t needSize, int pslot) { + //already db alloc mutex is taken VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo)); - varInfo->isUsed_ = 0; - varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo); - splitDataBucket(varInfo, needSize); - return; + //varInfo->isUsed_ = 0; + int ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0); + if(ret !=0) { + printError(ErrSysFatal, "Fatal:Unable to get lock to set isUsed flag"); + } + //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo); + ret = Mutex::CAS((int*)&varInfo->size_, varInfo->size_ , + PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo)); + if(ret !=0) { + printError(ErrSysFatal, "Unable to get lock to set size"); + } + DbRetVal rv =OK; + return splitDataBucket(varInfo, needSize, pslot, &rv); } void Chunk::setChunkNameForSystemDB(int id) { @@ -788,6 +988,3 @@ void Chunk::print() } printf("\n"); } - - - diff --git a/src/storage/ChunkIterator.cxx b/src/storage/ChunkIterator.cxx index e91d1206..62ab0ad5 100644 --- a/src/storage/ChunkIterator.cxx +++ b/src/storage/ChunkIterator.cxx @@ -28,49 +28,44 @@ ChunkIterator Chunk::getIterator() iter.allocType_ = allocType_; iter.iterPage_ = (PageInfo*)firstPage_; iter.nodeOffset_ = 0; - iter.noOfNodes_ = os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_); + if (allocSize_) + iter.noOfNodes_ = os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_); iter.data = NULL; iter.iterPageEnd = ((char*)firstPage_) +PAGE_SIZE; printDebug(DM_Iterator,"ChunkID:%d FirstPage is %x", - chunkID_, iter.iterPage_); + chunkID_, iter.iterPage_); return iter; } void* ChunkIterator::nextElement() { - /*if(NULL == iterPage_) - { - printError(ErrNotExists,"No iter page exists."); - return NULL; - }*/ - //PageInfo* pageInfo = (PageInfo*)iterPage_; if (0 == noOfNodes_) { //means tuple larger than PAGE_SIZE if(NULL == iterPage_) return NULL; char *record =NULL; record = ((char*)iterPage_) +sizeof(PageInfo); - while(*(int*)record != 1) + while(*(InUse*)record != 1) { iterPage_ = (PageInfo*) iterPage_->nextPage_; if(NULL == iterPage_) return NULL; record = ((char*)iterPage_) +sizeof(PageInfo); } iterPage_ = (PageInfo*) iterPage_->nextPage_; - return (record + sizeof(int)); + return (record + sizeof(InUse)); } //check whether there are any nodes in the current page //int i = nodeOffset_; if (!data) { data = ((char*)iterPage_) + sizeof(PageInfo); - if ((*(int*)data) == 1) - return data + sizeof(int); + if ((*(InUse*)data) == 1) + return data + sizeof(InUse); } - data = data + allocSize_; + data += allocSize_; while(data < iterPageEnd) { - if (*((int*)data) == 0) + if (*((InUse*)data) == 0) { //not used, so skip it data = data + allocSize_; @@ -82,8 +77,8 @@ void* ChunkIterator::nextElement() //used, return element pointer //nodeOffset_++; printDebug(DM_Iterator,"ChunkID:%d Returning %x nodeOffset:%d", - chunkID_, data + sizeof(int), nodeOffset_); - return data + sizeof(int); + chunkID_, data + sizeof(InUse), nodeOffset_); + return data + sizeof(InUse); } } //go to next page and check till it exhausts @@ -94,19 +89,57 @@ void* ChunkIterator::nextElement() iterPageEnd = ((char*)iterPage_) + PAGE_SIZE; while(data < iterPageEnd) { - if (*((int*)data) == 0) + if (*((InUse*)data) == 0) { //not used, so skip it data = data + allocSize_; - nodeOffset_++; } else { - //nodeOffset_++; printDebug(DM_Iterator,"ChunkID:%d Returning %x", - chunkID_, data + sizeof(int)); + chunkID_, data + sizeof(InUse)); + return data +sizeof(InUse); + } + } + } + return NULL; +} +void* ChunkIterator::nextElementIntMatch(int value, int offset) +{ + //check whether there are any nodes in the current page + if (!data) { + data = ((char*)iterPage_) + sizeof(PageInfo); + if ((*(InUse*)data) == 1 && *(int*)(data+sizeof(int)+offset) == value) + return data + sizeof(InUse); + } + data += allocSize_; + while(data < iterPageEnd) + { + if (*(int*)(data+sizeof(int)+offset) == value && *((InUse*)data)) + { + printDebug(DM_Iterator,"ChunkID:%d Returning %x nodeOffset:%d", + chunkID_, data + sizeof(InUse), nodeOffset_); + return data + sizeof(InUse); + } + data = data + allocSize_; + printDebug(DM_Iterator,"ChunkID:%d Moving to next data node %x", + chunkID_, data); + } + //go to next page and check till it exhausts + while(iterPage_->nextPage_ != NULL) + { + iterPage_ = (PageInfo*)iterPage_->nextPage_; + data = ((char*)iterPage_) + sizeof(PageInfo); + iterPageEnd = ((char*)iterPage_) + PAGE_SIZE; + while(data < iterPageEnd) + { + if (*(int*)(data+sizeof(int)+offset) == value && *((InUse*)data)) + { + printDebug(DM_Iterator,"ChunkID:%d Returning %x", + chunkID_, data + sizeof(InUse)); return data +sizeof(int); } + data = data + allocSize_; } } return NULL; diff --git a/src/storage/Config.cxx b/src/storage/Config.cxx index 6ff154c4..b9f9dd6a 100644 --- a/src/storage/Config.cxx +++ b/src/storage/Config.cxx @@ -90,10 +90,6 @@ int Config::storeKeyVal(char *key, char *value) } else if(os::strcasestr(key,"SITE_ID")!=NULL) { cVal.siteID = atoi(value);} - else if(os::strcasestr(key,"REPLICATION_SITES")!=NULL) - { cVal.maxReplSites = atoi(value);} - else if (os::strcasestr(key, "REPLICATION") != NULL) - { cVal.isReplication = os::atobool(value); } else if (os::strcasestr(key, "DURABILITY") != NULL) { cVal.isDurable = os::atobool(value); } else if (os::strcasestr(key, "DURABLE_MODE") != NULL) @@ -102,8 +98,6 @@ int Config::storeKeyVal(char *key, char *value) { cVal.isCsqlSqlServer = os::atobool(value); } else if (os::strcasestr(key, "PORT") != NULL) { cVal.port = atoi(value); } - else if (os::strcasestr(key, "NETWORK_CONFIG_FILE") != NULL) - { strcpy(cVal.replConfigFile , value); } else if (os::strcasestr(key, "MAX_QUEUE_LOGS") != NULL) { cVal.maxQueueLogs = atol(value); } else if (os::strcasestr(key, "MSG_KEY") != NULL) @@ -135,20 +129,11 @@ int Config::validateValues() printError(ErrBadArg, "PAGE_SIZE should be multiples of 1024"); return 1; } -#if (defined TRIAL) || (defined BASIC) - if (cVal.maxProcs < 1 || cVal.maxProcs > 5) - { - printf("Trial license supports only 5 connections"); - printf("Contact sales@csqldb.com to get full license"); - return 1; - } -#else if (cVal.maxProcs < 10 || cVal.maxProcs > 8192) { printError(ErrBadArg, "MAX_PROCS should be >= 10 and <= 8192"); return 1; } -#endif if (cVal.maxSysSize < 1024 * 1024 || cVal.maxSysSize > 1024 *1024 *1024) { printError(ErrBadArg, "MAX_SYS_DB_SIZE should be >= 1 MB and <= 1 GB"); @@ -160,39 +145,20 @@ int Config::validateValues() return 1; } -#ifdef TRIAL - if (cVal.maxDbSize < 1024 * 1024 || cVal.maxDbSize > (20 * 1024*1024)) - { - printf("Trial license supports only 20 MB db size"); - printf("Contact sales@csqldb.com to get full license"); - return 1; - } -#else -#ifdef BASIC - if (cVal.maxDbSize < 1024 * 1024 || cVal.maxDbSize > (100 * 1024*1024)) - { - printf("Basic subscription supports only 100 MB db size"); - printf("Contact sales@csqldb.com to upgrade"); - return 1; - } - -#else - #ifdef x86_64 + #ifdef x86_64 if (cVal.maxDbSize < 1024 * 1024 || cVal.maxDbSize > ( 100*1024*1024*1024L)) { printError(ErrBadArg, "MAX_DB_SIZE should be >= 1 MB and <= 100 GB"); return 1; } - #else + #else unsigned long maxVal = 2*1024*1024*1024L; if (cVal.maxDbSize < 1024 * 1024 || ((unsigned long)cVal.maxDbSize) > maxVal) { printError(ErrBadArg, "MAX_DB_SIZE should be >= 1 MB and <= 2 GB"); return 1; } - #endif -#endif -#endif + #endif if (cVal.maxDbSize % 8192 !=0) { printError(ErrBadArg, "MAX_DB_SIZE should be multiples of 8192"); @@ -225,11 +191,13 @@ int Config::validateValues() printError(ErrBadArg, "LOG_FILE is set to NULL"); return 1; } +#if (!defined __sparcv9) if (cVal.mapAddr < 400000000 || cVal.mapAddr > 2000000000) { printError(ErrBadArg, "MAP_ADDRESS should be >= 400000000 and <= 2000000000"); return 1; } +#endif if (cVal.mutexSecs < 0 || cVal.mutexSecs > 360) { printError(ErrBadArg, "MUTEX_TIMEOUT_SECS should be >= 0 and <= 360"); @@ -265,20 +233,6 @@ int Config::validateValues() printError(ErrBadArg, "LOG_LEVEL should be >= 0 and <= 3"); return 1; } -#ifdef NOREPL - if (cVal.isReplication) { - printf("This version does not support replication.\n"); - printf("Please contact sales@csqldb.com to upgrade\n"); - return 1; - } -#endif -/* if (cVal.isCache && cVal.isReplication) { - printError(ErrBadArg, "Either caching or replication option should be set." - " Both options are not supported together"); - return 1; - }*/ - - //printf("Debug:Config=%s\n",cVal.dsn); if (cVal.isCache) { if (0 == strcmp(cVal.dsn,"")) { @@ -286,23 +240,16 @@ int Config::validateValues() return 1; } } - - if (cVal.isReplication || cVal.isCache) { - if (0 == strcmp(cVal.replConfigFile,"")) - { - //TODO::check whether file exists - printError(ErrBadArg, "NETWORK_CONFIG_FILE is set to NULL"); - return 1; - } + if (cVal.isCache) { if (0 == strcmp(cVal.tableConfigFile,"")) { //TODO::check whether file exists printError(ErrBadArg, "TABLE_CONFIG_FILE is set to NULL"); return 1; } - /*FILE *fp = fopen(cVal.replConfigFile,"r"); + /*FILE *fp = fopen(cVal.tableConfigFile,"r"); if( fp == NULL ) { - printError(ErrSysInit, "Invalid path/filename for NETWORK_CONFIG_FILE.\n"); + printError(ErrSysInit, "Invalid path/filename for TABLE_CONFIG_FILE.\n"); return 1; } int count =0; @@ -313,39 +260,9 @@ int Config::validateValues() while(!feof(fp)) { fscanf(fp, "%d:%d:%s\n", &nwid, &port, hostname); count++; - } - if (count >2) { - printError(ErrSysInit, "NETWORK_CONFIG_FILE has more than 2 entries\n"); - return 1; }*/ } - /*if (cVal.isCache) - { - - if (cVal.cacheNetworkID == -1) - { - printError(ErrBadArg, "CACHE_NETWORK_ID should not be -1"); - return 1; - }else { - FILE *fp; - int nwid; - char hostname[IDENTIFIER_LENGTH]; - char nwmode; - int port; - fp = fopen(Conf::config.getReplConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "Invalid path/filename for NETWORK_CONFIG_FILE.\n"); - return 1; - } - bool found = false; - while(!feof(fp)) { - fscanf(fp, "%d:%d:%s\n", &nwid, &port, hostname); - if (cVal.cacheNetworkID == nwid) found = true; - } - if (!found) return 1; - } - }*/ if (cVal.nwResponseTimeout <0 || cVal.nwResponseTimeout > 60) { printError(ErrBadArg, "NETWORK_RESPONSE_TIMEOUT should be 0 to 60"); @@ -428,16 +345,6 @@ int Config::readAllValues(char *fileName) } void Config::logConfig() { - /* - logFinest(Conf::logger, "Config: MAX_SYS_DB_SIZE %d", getMaxSysDbSize()); - logFinest(Conf::logger, "Config: MAX_DB_SIZE %d", getMaxDbSize()); - logFinest(Conf::logger, "Config: SYS_DB_KEY %d", getSysDbKey()); - logFinest(Conf::logger, "Config: USER_DB_KEY %d", getUserDbKey()); - logFinest(Conf::logger, "Config: MAP_ADDRESS %ld", getMapAddress()); - logFinest(Conf::logger, "Config: DATABASE_FILE %s", getDbFile()); - //TODO:: for cache/sql/nw section - */ - logFinest(Conf::logger, "Config: LOG_FILE %s", getLogFile()); logFinest(Conf::logger, "Config: LOG_LEVEL %d", getLogLevel()); logFinest(Conf::logger, "Config: DURABILITY %d", useDurability()); @@ -478,73 +385,8 @@ void Config::print() printf(" getCacheWaitSecs %d\n", getCacheWaitSecs()); printf(" useCsqlSqlServer %d\n", useCsqlSqlServer()); printf(" getPort %d\n", getPort()); - printf(" useReplication %d\n", useReplication()); printf(" isDurable %d\n", useDurability()); - printf(" getReplConfigFile %s\n", getReplConfigFile()); printf(" getSiteID %d\n", getSiteID()); printf(" getMsgKey %d\n", getMsgKey()); printf(" getShmIDKey %d\n", getShmIDKey()); } - -DbRetVal SiteInfo::populateSiteInfoList() -{ - if (!Conf::config.useReplication()) return OK; - FILE *fp = fopen( Conf::config.getReplConfigFile(), "r"); - if (fp == NULL) { - printError(ErrSysInit, "Invalid path/filename for REPL_CONFIG_FILE.\n"); - return ErrSysInit; - } - char line[128]; - while(fgets(line, sizeof (line), fp) != NULL) { - SiteInfoData *sInfo = new SiteInfoData(); - char *token = strtok(line, ":"); - sInfo->siteId = atoi(token); - if ((token = strtok(NULL, ":")) != NULL) - strncpy(sInfo->hostName, token, IDENTIFIER_LENGTH); - if ((token = strtok(NULL, ":")) != NULL) sInfo->port = atoi(token); - if ((token = strtok(NULL, ":")) != NULL) - strncpy(sInfo->mode, token, 32); - siteInfoList.append(sInfo); - if(strncasecmp(sInfo->mode, "ASYNC", 5)==0) asyncSiteList.append(sInfo); - if(strncasecmp(sInfo->mode, "SYNC", 4)==0) syncSiteList.append(sInfo); - } - fclose(fp); - return OK; -} - -bool SiteInfo::isAsyncSitePresent() -{ - bool async = false; - if (!Conf::config.useReplication()) return false; - ListIterator it = siteInfoList.getIterator(); - while (it.hasElement()) { - SiteInfoData *data = (SiteInfoData *) it.nextElement(); - if (strncmp(data->mode, "ASYNC", 5) == 0) { async = true; break; } - } - return async; -} - -bool SiteInfo::isSyncSitePresent() -{ - bool sync = false; - if (!Conf::config.useReplication()) return false; - ListIterator it = siteInfoList.getIterator(); - while (it.hasElement()) { - SiteInfoData *data = (SiteInfoData *) it.nextElement(); - if (strncmp(data->mode, "SYNC", 4) == 0) { sync = true; break; } - } - return sync; -} - -SiteInfo::~SiteInfo() -{ -// ListIterator it = siteInfoList.getIterator(); -// while(it.hasElement()) delete (SiteInfoData *) it.nextElement(); -// siteInfoList.reset(); - ListIterator it = asyncSiteList.getIterator(); - while(it.hasElement()) delete (SiteInfoData *) it.nextElement(); - asyncSiteList.reset(); - it = syncSiteList.getIterator(); - while(it.hasElement()) delete (SiteInfoData *) it.nextElement(); - syncSiteList.reset(); -} diff --git a/src/storage/Connection.cxx b/src/storage/Connection.cxx index 2f77ef55..6f3d48ba 100644 --- a/src/storage/Connection.cxx +++ b/src/storage/Connection.cxx @@ -18,6 +18,7 @@ #include #include #include + Connection::~Connection() { if (NULL != session) { @@ -28,7 +29,10 @@ Connection::~Connection() } Index::destroy(); } - +char *Connection::getUserName() +{ + return session->getUserName(); +} DbRetVal Connection::open(const char *username, const char *password) { if (username == NULL || password == NULL ) @@ -36,7 +40,7 @@ DbRetVal Connection::open(const char *username, const char *password) printError(ErrBadArg, "Username or password should not be NULL\n"); return ErrBadArg; } - if (strlen(username) > 64 || strlen(password) >64) return ErrBadArg; + if (strlen(username) > IDENTIFIER_LENGTH || strlen(password) > IDENTIFIER_LENGTH) return ErrBadArg; if (session == NULL) session = new SessionImpl(); else { @@ -47,7 +51,7 @@ DbRetVal Connection::open(const char *username, const char *password) if (rv != OK) { delete session; session = NULL; return rv; } rv = Conf::logger.startLogger(Conf::config.getLogFile()); if (rv != OK) { delete session; session = NULL; return rv; } - logFinest(Conf::logger, "User logged in %s",username); + logFine(Conf::logger, "User logged in %s",username); Index::init(); return OK; } @@ -55,7 +59,7 @@ DbRetVal Connection::open(const char *username, const char *password) DbRetVal Connection::close() { if (session == NULL) return ErrNoConnection; - logFinest(Conf::logger, "User logged out"); + logFine(Conf::logger, "User logged out"); Conf::logger.stopLogger(); session->rollback(); delete session; // this inturn calls session->close @@ -95,7 +99,6 @@ DbRetVal Connection::rollback() if (session == NULL) return ErrNoConnection; return session->rollback(); } - DbRetVal Connection::getExclusiveLock() { if (session == NULL) return ErrNoConnection; diff --git a/src/storage/DataType.cxx b/src/storage/DataType.cxx index 98789f43..f86d62a4 100644 --- a/src/storage/DataType.cxx +++ b/src/storage/DataType.cxx @@ -16,8 +16,12 @@ #include #include #include - +//#include #define SmallestValJulDate (1721426) +#if defined(SOLARIS) +#undef _TIME_H +#endif + Date::Date(int year, int month, int day) { YMDToJulian(year, month, day, julianDate); } @@ -28,16 +32,69 @@ int Date::get(int &year, int &month, int &day) const int Date::parseFrom(const char *s) { int month,day,year; - int count; - count = sscanf(s,"%d/%d/%d",&year,&month,&day); - if (count < 3) return -1; + int count;char *p; + if(strcmp(s,"now")==0 || strcmp(s,"NOW")==0){ + time_t cnow = ::time(NULL); +#if defined(SOLARIS) && defined(REMOTE_SOLARIS) + struct std::tm *tmval = (struct std::tm*) localtime(&cnow); + return set(year=tmval->tm_year+1900, month=tmval->tm_mon+1, day=tmval->tm_mday); +#else + struct tm *tmval = localtime(&cnow); + return set(year=tmval->tm_year+1900,month=tmval->tm_mon+1,day=tmval->tm_mday); +#endif + } + else{ + p=(char*)s; + while(*p!='\0'){ + if(*p=='-'){ + count = sscanf(s,"%d-%d-%d",&year,&month,&day); + break; + } + if(*p=='/'){ + count = sscanf(s,"%d/%d/%d",&year,&month,&day); + break; + } + p++; + } + if (count < 3) return -1; + if (year < 100) year += 1900; + if (!isValidDate(year, month, day)) + return -1; + return set(year,month,day); + } +} - if (year < 100) year += 1900; +void Date::changeToCsqlFormat(char *src) +{ + char dst[10]=""; + char *srcPtr = src; + char *dstPtr = dst; + dst[0]='\0'; + srcPtr = src + 7; + strncpy(dstPtr, srcPtr, 4); + dst[4] = '-'; + dstPtr = &dst[5]; + srcPtr = src + 3; + if(strncasecmp(srcPtr,"JAN",3) == 0) strncpy(dstPtr, "01", 2); + else if(strncasecmp(srcPtr,"FEB",3)== 0) strncpy(dstPtr, "02", 2); + else if(strncasecmp(srcPtr,"MAR",3)== 0) strncpy(dstPtr, "03", 2); + else if(strncasecmp(srcPtr,"APR",3)== 0) strncpy(dstPtr, "04", 2); + else if(strncasecmp(srcPtr,"MAY",3)== 0) strncpy(dstPtr, "05", 2); + else if(strncasecmp(srcPtr,"JUN",3)== 0) strncpy(dstPtr, "06", 2); + else if(strncasecmp(srcPtr,"JUL",3)== 0) strncpy(dstPtr, "07", 2); + else if(strncasecmp(srcPtr,"AUG",3)== 0) strncpy(dstPtr, "08", 2); + else if(strncasecmp(srcPtr,"SEP",3)== 0) strncpy(dstPtr, "09", 2); + else if(strncasecmp(srcPtr,"OCT",3)== 0) strncpy(dstPtr, "10", 2); + else if(strncasecmp(srcPtr,"NOV",3)== 0) strncpy(dstPtr, "11", 2); + else if(strncasecmp(srcPtr,"DEC",3)== 0) strncpy(dstPtr, "12", 2); + dst[7]='-'; + dstPtr = &dst[8]; + strncpy(dstPtr, src, 2); + dst[10] = '\0'; + strcpy(src, dst); + return; +} - if (!isValidDate(year, month, day)) - return -1; - return set(year,month,day); -} int Date::dayOfMonth() const { int year, month, day; @@ -147,7 +204,8 @@ int Date::daysInMonth(int month, int year) { } bool Date::isValidDate(int year, int month, int day) { - if (year < 1 || year > 10000) return false; + + if (year < 1 || year >= 9999) return false; if (month < 1 || month > 12) return false; return (day >= 1) && (day <= daysInMonth(month,year)); } @@ -280,23 +338,58 @@ int operator!=(const Time &t1 ,const Time &t2 ) int Time::parseFrom(const char *s) { int hours,mins,secs; - int count; - count = sscanf(s,"%d:%d:%d",&hours,&mins,&secs); - if (count < 2) return -1; - if (count == 2) secs = 0; - - if (!isValidTime(hours,mins,secs)) - return -1; - return set(hours,mins,secs); + int count;char *p; + if(strcmp(s,"now")==0 || strcmp(s,"NOW")==0){ + time_t cnow = ::time(NULL); +#if defined(SOLARIS) && defined(REMOTE_SOLARIS) + struct std::tm *tmval = (struct std::tm*) localtime(&cnow); + return set(hours=tmval->tm_hour,mins=tmval->tm_min,secs=tmval->tm_sec); +#else + struct tm *tmval = localtime(&cnow); + return set(hours=tmval->tm_hour,mins=tmval->tm_min,secs=tmval->tm_sec); +#endif + } + else{ + count = sscanf(s,"%d:%d:%d",&hours,&mins,&secs); + if (count < 2) return -1; + if (count == 2) secs = 0; + + if (!isValidTime(hours,mins,secs)) + return -1; + return set(hours,mins,secs); + } } int TimeStamp::parseFrom(const char *s) { int hours,mins,secs; int month,day,year; - int count; - count = sscanf(s,"%d/%d/%d %d:%d:%d",&year,&month,&day, &hours, &mins, &secs); + int count;char *p; + if(strcmp(s,"now")==0 || strcmp(s,"NOW")==0){ + time_t cnow = ::time(NULL); +#if defined(SOLARIS) && defined(REMOTE_SOLARIS) + struct std::tm *tmval = (struct std::tm*) localtime(&cnow); + setDate(year=tmval->tm_year+1900,month=tmval->tm_mon+1,day=tmval->tm_mday); + return setTime(hours=tmval->tm_hour,mins=tmval->tm_min,secs=tmval->tm_sec); +#else + struct tm *tmval = localtime(&cnow); + setDate(year=tmval->tm_year+1900,month=tmval->tm_mon+1,day=tmval->tm_mday); + return setTime(hours=tmval->tm_hour,mins=tmval->tm_min,secs=tmval->tm_sec); +#endif + } + else{ + p=(char*)s; + while(*p!='\0'){ + if(*p=='-'){ + count = sscanf(s,"%d-%d-%d %d:%d:%d",&year,&month,&day, &hours, &mins, &secs); + break; + } + if(*p=='/'){ + count = sscanf(s,"%d/%d/%d %d:%d:%d",&year,&month,&day, &hours, &mins, &secs); + break; + } + p++; + } if (count < 5) return -1; if (count == 5) secs = 0; - if (year < 100) year += 1900; if (!date.isValidDate(year, month, day)) @@ -308,8 +401,42 @@ int TimeStamp::parseFrom(const char *s) { if (!time.isValidTime(hours,mins,secs)) return -1; return setTime(hours,mins,secs); + } } +void TimeStamp::changeToCsqlFormat(char *src) +{ + char dst[20]; + char *srcPtr = src; + char *dstPtr = dst; + dst[0]='\0'; + srcPtr = src + 7; + strncpy(dstPtr, srcPtr, 4); + dst[4] = '-'; + dstPtr = &dst[5]; + srcPtr = src + 3; + if(strncasecmp(srcPtr,"JAN",3) == 0) strncpy(dstPtr, "01", 2); + else if(strncasecmp(srcPtr,"FEB",3)== 0) strncpy(dstPtr, "02", 2); + else if(strncasecmp(srcPtr,"MAR",3)== 0) strncpy(dstPtr, "03", 2); + else if(strncasecmp(srcPtr,"APR",3)== 0) strncpy(dstPtr, "04", 2); + else if(strncasecmp(srcPtr,"MAY",3)== 0) strncpy(dstPtr, "05", 2); + else if(strncasecmp(srcPtr,"JUN",3)== 0) strncpy(dstPtr, "06", 2); + else if(strncasecmp(srcPtr,"JUL",3)== 0) strncpy(dstPtr, "07", 2); + else if(strncasecmp(srcPtr,"AUG",3)== 0) strncpy(dstPtr, "08", 2); + else if(strncasecmp(srcPtr,"SEP",3)== 0) strncpy(dstPtr, "09", 2); + else if(strncasecmp(srcPtr,"OCT",3)== 0) strncpy(dstPtr, "10", 2); + else if(strncasecmp(srcPtr,"NOV",3)== 0) strncpy(dstPtr, "11", 2); + else if(strncasecmp(srcPtr,"DEC",3)== 0) strncpy(dstPtr, "12", 2); + dst[7]='-'; + dstPtr = &dst[8]; + strncpy(dstPtr, src, 2); + dstPtr = &dst[10]; + srcPtr = src + 11; + strncpy(dstPtr, srcPtr, 9); + dst[19]='\0'; + strcpy(src, dst); + return; +} int operator< (const TimeStamp &d1, const TimeStamp &d2) { return (d1.date != d2.date) ? d1.date < d2.date : d1.time < d2.time; } int operator> (const TimeStamp &d1, const TimeStamp &d2) @@ -321,63 +448,9 @@ int operator>=(const TimeStamp &d1, const TimeStamp &d2) int operator==(const TimeStamp &d1, const TimeStamp &d2) { return d1.date == d2.date && d1.time == d2.time; } int operator!=(const TimeStamp &d1, const TimeStamp &d2) - { return d1.date != d2.date && d1.time != d2.time; } - + { return d1.date != d2.date || d1.time != d2.time; } -/*long AllDataType::size(DataType type, int length ) -{ - if (type == typeInt) return sizeof(int); - else if (type == typeString) return length; - long size = 0; - switch(type) - { - case typeInt: - size = sizeof(int); - break; - case typeLong: - size = sizeof(long); - break; - case typeLongLong: - size = sizeof(long long); - break; - case typeShort: - size = sizeof(short); - break; - case typeByteInt: - size = sizeof(char); - break; - case typeDouble: - size = sizeof(double); - break; - case typeFloat: - size = sizeof(float); - break; - case typeDecimal: - //TODO::for porting - //fldDef.length_ = sizeof(long double); - break; - case typeDate: - size = sizeof(Date); - break; - case typeTime: - size = sizeof(Time); - break; - case typeTimeStamp: - size = sizeof(TimeStamp); - break; - case typeString: - case typeBinary: - case typeComposite: - size = length; - break; - default: - size = 0; - break; - } - return size; -} -*/ char* AllDataType::getSQLString(DataType type) { switch(type) @@ -409,7 +482,7 @@ SQLSMALLINT AllDataType::convertToSQLType(DataType type) return SQL_INTEGER; case typeLongLong: //TODO - return SQL_INTEGER; + return SQL_BIGINT; case typeShort: return SQL_SMALLINT; case typeByteInt: @@ -435,7 +508,44 @@ SQLSMALLINT AllDataType::convertToSQLType(DataType type) } return SQL_INTEGER; } -SQLSMALLINT AllDataType::convertToSQL_C_Type(DataType type) +SQLSMALLINT AllDataType::convertToCSQLSQLType(DataType type) +{ + switch(type) + { + case typeInt: + return SQL_INTEGER; + case typeLong: + return SQL_INTEGER; + case typeLongLong: + //TODO + return SQL_BIGINT; + case typeShort: + return SQL_SMALLINT; + case typeByteInt: + //TODO + return SQL_TINYINT; + case typeDouble: + return SQL_DOUBLE; + case typeFloat: + return SQL_REAL; + case typeDecimal: + //TODO + return SQL_INTEGER; + case typeDate: + return SQL_TYPE_DATE; + case typeTime: + return SQL_TYPE_TIME; + case typeTimeStamp: + return SQL_TYPE_TIMESTAMP; + case typeString: + return SQL_CHAR; + case typeBinary: + return SQL_BINARY; + } + return SQL_INTEGER; +} + +SQLSMALLINT AllDataType::convertToSQL_C_Type(DataType type,TDBInfo tdbname) { switch(type) { @@ -444,7 +554,12 @@ SQLSMALLINT AllDataType::convertToSQL_C_Type(DataType type) case typeLong: return SQL_C_SLONG; case typeLongLong: - return SQL_C_SBIGINT; + { + if(tdbname == postgres) + return SQL_C_CHAR; + else + return SQL_C_SBIGINT; + } case typeShort: return SQL_C_SSHORT; case typeByteInt: @@ -470,14 +585,50 @@ SQLSMALLINT AllDataType::convertToSQL_C_Type(DataType type) return SQL_C_SLONG; } -DataType AllDataType::convertFromSQLType(SQLSMALLINT type) +DataType AllDataType::convertFromSQLType(SQLSMALLINT type,int length,int scale,TDBInfo tdbname) { + if(tdbname==postgres) + { + switch(type) + { + case SQL_INTEGER : + return typeInt; + case SQL_SMALLINT: + return typeShort; + case SQL_BIGINT: + return typeLongLong; + case SQL_FLOAT: + case SQL_DOUBLE: + return typeDouble; + case SQL_REAL: + return typeFloat; + case SQL_TYPE_DATE: + return typeDate; + case SQL_TYPE_TIME : + return typeTime; + case SQL_TYPE_TIMESTAMP : + return typeTimeStamp; + case SQL_CHAR: + return typeString; + case SQL_LONGVARCHAR: + return typeString; + case SQL_VARCHAR: + return typeString; + case SQL_BINARY: + return typeBinary; + } + return typeInt; + } switch(type) { + case SQL_TINYINT: + return typeByteInt; case SQL_INTEGER : return typeInt; case SQL_SMALLINT: return typeShort; + case SQL_BIGINT: + return typeLongLong; case SQL_DOUBLE: return typeDouble; case SQL_FLOAT: @@ -491,6 +642,8 @@ DataType AllDataType::convertFromSQLType(SQLSMALLINT type) return typeTimeStamp; case SQL_CHAR: return typeString; + case SQL_LONGVARCHAR: + return typeString; case SQL_VARCHAR: return typeString; case SQL_BINARY: @@ -498,91 +651,6 @@ DataType AllDataType::convertFromSQLType(SQLSMALLINT type) } return typeInt; } -/* -void AllDataType::copyVal(void* dest, void *src, DataType type, int length) -{ - //Performance optimization. putting likely case first - if (typeInt == type ) - { - *(int*)dest = *(int*)src; - return; - }else if (typeString == type) - { - //null is always put at the last byte by insert - //so using strcpy is safe - strcpy((char*)dest, (char*)src); - //strncpy((char*)dest, (char*)src, length); - //char *d =(char*)dest; - //d[length-1] = '\0'; - return; - }else if (typeShort == type) { - *(short*)dest = *(short*)src; - }else if (typeDouble == type) { - *(double*)dest = *(double*)src; - }else if (typeTimeStamp == type) { - *(TimeStamp*)dest = *(TimeStamp*)src; - }else if (typeDate == type) { - *(Date*)dest = *(Date*)src; - }else if (typeFloat == type) { - *(float*)dest = *(float*)src; - }else if (typeTime == type) { - *(Time*)dest = *(Time*)src; - }else if (typeLong == type) { - *(long*)dest = *(long*)src; - }else if (typeLongLong == type) { - *(long long*)dest = *(long long*)src; - }else if (typeByteInt == type) { - *(char*)dest = *(char*)src; - }else if (typeBinary == type) { - os::memcpy(dest, src, length); - }else if (typeComposite == type) { - os::memcpy(dest, src, length); - } - return; -} - -void AllDataType::addVal(void* dest, void *src, DataType type) -{ - if (type == typeInt) - { - *(int*)dest = *(int*)dest + *(int*)src; - return; - } - switch(type) - { - case typeInt: - *(int*)dest = *(int*)dest + *(int*)src; - break; - case typeLong: - *(long*)dest = *(long*)dest + *(long*)src; - break; - case typeLongLong: - *(long long*)dest = *(long long*)dest + *(long long*)src; - break; - case typeShort: - *(short*)dest = *(short*)dest + *(short*)src; - break; - case typeByteInt: - *(char*)dest = *(char*)dest + *(char*)src; - break; - case typeDouble: - *(double*)dest = *(double*)dest + *(double*)src; - break; - case typeFloat: - *(float*)dest = *(float*)dest + *(float*)src; - break; - case typeDecimal: - //TODO::for porting - case typeDate: - case typeTime: - case typeTimeStamp: - case typeBinary: - default: - break; - } - return; -} -*/ void AllDataType::subVal(void* dest, void *src, DataType type) { switch(type) @@ -733,37 +801,20 @@ void AllDataType::divVal(void* dest, void *src, DataType type) } return; } -void AllDataType::divVal(void* dest, int src, DataType type) +void AllDataType::divVal(double* dest, int src, DataType type) { - if(type == typeInt) - { - *(int*)dest = *(int*)dest / src; - return; - } switch(type) { - case typeInt: - *(int*)dest = *(int*)dest / src; - break; - case typeLong: - *(long*)dest = *(long*)dest / src; - break; - case typeLongLong: - *(long long*)dest = *(long long*)dest / src; - break; - case typeShort: - *(short*)dest = *(short*)dest / src; - break; - case typeByteInt: - *(char*)dest = *(char*)dest / src; - break; - case typeDouble: - *(double*)dest = *(double*)dest / src; - break; + case typeInt: + case typeLong: + case typeLongLong: + case typeShort: + case typeByteInt: + case typeDouble: case typeFloat: - *(float*)dest = *(float*)dest / src; - break; case typeDecimal: + *dest = *dest / src; + break; //TODO::for porting case typeDate: case typeTime: @@ -774,6 +825,7 @@ void AllDataType::divVal(void* dest, int src, DataType type) } return; } + void AllDataType::increment(void* dest, void *src, DataType type) { switch(type) @@ -787,6 +839,9 @@ void AllDataType::increment(void* dest, void *src, DataType type) case typeLongLong: *(long long*)dest = *(long long*)src + 1; break; + case typeByteInt: + *(char*)dest = *(char*)src + 1; + break; case typeShort: *(short*)dest = *(short*)src + 1; break; @@ -800,6 +855,7 @@ void AllDataType::increment(void* dest, void *src, DataType type) break; } } + bool AllDataType::isValueZero(void *src, DataType type) { switch(type) @@ -828,66 +884,9 @@ bool AllDataType::isValueZero(void *src, DataType type) return false; } -/* -bool AllDataType::compareVal(void *val1, void *val2, ComparisionOp op, - DataType type, long length) -{ - //Performance optimization. - //do not convert compareXXXVal to virtual functions. it takes more time - if (typeInt == type) - { - //as int is the heavily used type, hardcoding the compare here itself - if (OpEquals == op) { - if (*(int*)val1 == *(int*)val2) return true; - else return false; - }else if (OpLessThanEquals == op) { - if (*(int*)val1 <= *(int*)val2) return true; - else return false; - }else if (OpGreaterThanEquals == op) { - if (*(int*)val1 >= *(int*)val2) return true; - else return false; - }else if (OpGreaterThan == op) { - if (*(int*)val1 > *(int*)val2) return true; - else return false; - }else if (OpLessThan == op) { - if (*(int*)val1 < *(int*)val2) return true; - else return false; - }else if (OpNotEquals == op) { - if (*(int*)val1 != *(int*)val2) return true; - else return false; - } - - }else if(typeString == type) { - return AllDataType::compareStringVal(val1, val2, op); - } else if (typeShort == type) { - return AllDataType::compareShortVal(val1, val2, op); - } else if (typeDouble == type) { - return AllDataType::compareDoubleVal(val1, val2, op); - } else if (typeFloat == type) { - return AllDataType::compareFloatVal(val1, val2, op); - } else if (typeLong == type) { - return AllDataType::compareLongVal(val1, val2, op); - } else if (typeLongLong == type) { - return AllDataType::compareLongLongVal(val1, val2, op); - } else if (typeByteInt == type) { - return AllDataType::compareByteIntVal(val1, val2, op); - } else if (typeTimeStamp == type) { - return AllDataType::compareTimeStampVal(val1, val2, op); - } else if (typeDate == type) { - return AllDataType::compareDateVal(val1, val2, op); - } else if (typeTime == type) { - return AllDataType::compareTimeVal(val1, val2, op); - } else if (typeBinary == type) { - return AllDataType::compareBinaryVal(val1, val2, op, length); - } else if (typeComposite == type) { - return AllDataType::compareBinaryVal(val1, val2, op, length); - } -} -*/ - bool AllDataType::compareIntVal(void* src1, void *src2, ComparisionOp op) { - printf("This function should never be called by anyone"); + printf("This function should never be called by anyone\n"); if (OpEquals == op) { if (*(int*)src1 == *(int*)src2) return true; else return false; @@ -1267,29 +1266,6 @@ bool AllDataType::compareBinaryVal(void* src1, void *src2, } return result; } -/* -ComparisionOp AllDataType::getComparisionOperator(char *str) -{ - ComparisionOp op; - if (strcmp(str, "<=") == 0) - op = OpLessThanEquals; - else if (strcmp(str, ">=") == 0) - op = OpGreaterThanEquals; - else if (strcmp(str, "<") == 0) - op = OpLessThan; - else if (strcmp(str, ">") == 0) - op = OpGreaterThan; - else if (strcmp(str, "=") == 0) - op = OpEquals; - else if (strcmp(str, "!=") == 0 || strcmp(str, "<>") == 0 ) - op = OpNotEquals; - else if (strcasecmp(str, "LIKE") == 0 ) - op = OpLike; - else - op = OpInvalidComparisionOp; - return op; -} -*/ void* AllDataType::alloc(DataType type, int length) { @@ -1420,8 +1396,8 @@ DbRetVal AllDataType::strToValue(void* dest, char *src, DataType type, int lengt *(short*)dest = val; break; } case typeByteInt: { - int val; - sscanf( src, "%d", &val); + char val; + sscanf( src, "%hhd", &val); *(char*)dest = *(char *)&val; break; } case typeDouble: { @@ -1443,12 +1419,22 @@ DbRetVal AllDataType::strToValue(void* dest, char *src, DataType type, int lengt break;} case typeDate: { int d,m,y,res=0; - res = sscanf( src, "%d-%d-%d", &y, &m, &d ); - if( res != 3 ) - res = sscanf( src, "%d/%d/%d", &y, &m, &d ); + if (strlen(src) == 11) { + if ( src[6] == '-' || src[6] == '/' ) { + Date::changeToCsqlFormat(src); + } + } + res = sscanf( src, "%d-%d-%d", &y, &m, &d ); if( res != 3 ) + res = sscanf( src, "%d/%d/%d", &y, &m, &d ); + if (strcmp(src,"now")==0 || strcmp(src,"NOW")==0){ + Date *dt = (Date*) dest; + dt->parseFrom((char*)src); + break; + } + if( res != 3 ) { - fprintf(stderr,"Error reading date. yyyy{-/}mm{-/}dd is the valid format."); + fprintf(stderr,"Error reading date. yyyy{-/}mm{-/}dd is the valid format."); d=m=y=0; } Date dateObj(y,m,d); @@ -1456,25 +1442,40 @@ DbRetVal AllDataType::strToValue(void* dest, char *src, DataType type, int lengt break; } case typeTime: { int h,m,s,res=0; - res = sscanf( src, "%d:%d:%d", &h, &m, &s ); - if( res != 3 ) + res = sscanf( src, "%d:%d:%d", &h, &m, &s ); + if(strcmp(src,"now")==0 || strcmp(src,"NOW")==0){ + Time *dt = (Time*) dest; + dt->parseFrom((char*)src); + break; + } + if( res != 3 ) { fprintf(stderr, "Error reading time, hh:mm:ss is the valid format."); h=m=s=0; } - Time timeObj(h,m,s); + Time timeObj(h,m,s); *(Time*)dest = timeObj; break; } case typeTimeStamp: { int d,m,y, h,mn,s, res=0; - res = sscanf( src, "%d-%d-%d %d:%d:%d", &y, &m, &d, &h, &mn, &s ); + bool isNow = ( strcasecmp(src,"now")==0 ); + if(!isNow && isalpha(int(src[5]))) { + TimeStamp::changeToCsqlFormat(src); + } + res = sscanf( src, "%d-%d-%d %d:%d:%d", &y, &m, &d, &h, &mn, &s ); if( res != 6 ) res = sscanf( src, "%d-%d-%d, %d:%d:%d", &y, &m, &d, &h, &mn, &s ); if( res != 6 ) res = sscanf( src, "%d/%d/%d %d:%d:%d", &y, &m, &d, &h, &mn, &s ); if( res != 6 ) res = sscanf( src, "%d/%d/%d, %d:%d:%d", &y, &m, &d, &h, &mn, &s ); - if( res != 6 ) + + if(isNow){ + TimeStamp *dt = (TimeStamp*) dest; + dt->parseFrom((char*)src); + break; + } + if ( res != 6 ) { fprintf(stderr, "Error reading timestamp, yyyy{-/}mm{-/}dd[,] hh:mm:ss is the valid format."); d=m=y=h=mn=s=0; @@ -1652,7 +1653,7 @@ void AllDataType::convertToByteInt( void* dest, void* src, DataType srcType ) case typeFloat: *(char*)dest = (char) *(float *)src; break; case typeDouble: *(char*)dest =(char) *(double *)src; break; - case typeString: sscanf((const char*)src, "%c", (char*) dest); break; + case typeString: sscanf((const char*)src, "%hhd", (char*) dest); break; case typeDate: case typeTime: @@ -1708,13 +1709,13 @@ void AllDataType::convertToDouble( void* dest, void* src, DataType srcType ) } } -void AllDataType::convertToString( void* dest, void* src, DataType srcType, int length ) +void AllDataType::convertToString( void* dest, void* src, DataType srcType, int length,TDBInfo tdbname ) { switch(srcType) { case typeInt: { - sprintf ((char *)dest, "%d", *(int *)src); + Util::itoa(*(int*)src, (char*)dest); break; } case typeLong: @@ -1734,7 +1735,7 @@ void AllDataType::convertToString( void* dest, void* src, DataType srcType, int } case typeByteInt: { - sprintf ((char *)dest, "%hd", *(char *)src); + sprintf ((char *)dest, "%hhd", *(char *)src); break; } @@ -1757,8 +1758,7 @@ void AllDataType::convertToString( void* dest, void* src, DataType srcType, int case typeDate: { Date* dt = (Date*)src; - sprintf((char*) dest, "%d/%d/%d", dt->year(), - dt->month(), dt->dayOfMonth()); + sprintf((char*) dest, "%d/%d/%d", dt->year(),dt->month(), dt->dayOfMonth()); break; } case typeTime: @@ -1770,9 +1770,7 @@ void AllDataType::convertToString( void* dest, void* src, DataType srcType, int case typeTimeStamp: { TimeStamp* tm = (TimeStamp*)src; - sprintf((char*)dest, "%d/%d/%d %d:%d:%d.%d", tm->year(), - tm->month(), tm->dayOfMonth(), tm->hours(), - tm->minutes(), tm->seconds(), 0 ); + sprintf((char*)dest, "%d/%d/%d %d:%d:%d.%d", tm->year(),tm->month(), tm->dayOfMonth(), tm->hours(),tm->minutes(), tm->seconds(), 0 ); break; } case typeBinary: @@ -1903,8 +1901,9 @@ void AllDataType::convertToBinary(void *dest, void *src, DataType srcType, int l } } } -int AllDataType::printVal(void* src, DataType srcType, int length ) +int AllDataType::printVal(void* src, DataType srcType, int length,int dbFlag ) { + //dbFlag is the database flag 0:mysql (default), 1:postgres int count = 0; switch(srcType) { @@ -1920,7 +1919,12 @@ int AllDataType::printVal(void* src, DataType srcType, int length ) } case typeLongLong: { - count = printf ("%lld", *(long long *)src); + if(1 == dbFlag){ + long long temp = 0; + convertToLongLong((void*)&temp, src,typeString); + count = printf ("%lld", temp ); + } + else count = printf ("%lld", *(long long *)src); break; } case typeShort: @@ -1930,7 +1934,7 @@ int AllDataType::printVal(void* src, DataType srcType, int length ) } case typeByteInt: { - count = printf("%hd", *(char *)src); + count = printf("%hhd", *(char *)src); break; } @@ -1941,7 +1945,10 @@ int AllDataType::printVal(void* src, DataType srcType, int length ) } case typeDouble: { - count = printf("%lf", *(double *)src); + if (*(double*)src > 9999999999999999.0F) + count = printf("%g", *(double *)src); + else + count = printf("%lf", *(double *)src); break; } @@ -1999,6 +2006,3 @@ int AllDataType::printVal(void* src, DataType srcType, int length ) } return count; } - - - diff --git a/src/storage/Database.cxx b/src/storage/Database.cxx index c2c34125..91b9f21c 100644 --- a/src/storage/Database.cxx +++ b/src/storage/Database.cxx @@ -75,7 +75,8 @@ void Database::setCurrentSize(long size) } void Database::setCurrentPage(Page *page) { - metaData_->curPage_ = page; + //metaData_->curPage_ = page; + Mutex::CASL((long*)&metaData_->curPage_, (long)metaData_->curPage_, (long)page); } void Database::setFirstPage(Page *page) { @@ -110,7 +111,20 @@ DbRetVal Database::releaseAllocDatabaseMutex(bool procAccount) return OK; } - +int Database::initPrepareStmtMutex() +{ + return metaData_->dbPrepareStmtMutex_.init("prepstmt"); +} +DbRetVal Database::getPrepareStmtMutex(bool procAccount) +{ + int ret= metaData_->dbPrepareStmtMutex_.getLock(procSlot, procAccount); + if (ret) return ErrLockTimeOut; else return OK; +} +DbRetVal Database::releasePrepareStmtMutex(bool procAccount) +{ + metaData_->dbPrepareStmtMutex_.releaseLock(procSlot, procAccount); + return OK; +} int Database::initTransTableMutex() { @@ -249,7 +263,6 @@ Page* Database::getFreePage(size_t size) else break; } - } int i = 0; PageInfo *pInfo = pageInfo; @@ -436,6 +449,10 @@ void Database::createMetaDataTables() sizeof(CINDEX), IndexTableId); createSystemDatabaseChunk(FixedSizeAllocator, sizeof(CINDEXFIELD), IndexFieldTableId); + createSystemDatabaseChunk(FixedSizeAllocator, + sizeof(CFK), ForeignKeyTableId); + createSystemDatabaseChunk(FixedSizeAllocator, + sizeof(CFKFIELD), ForeignKeyFieldTableId); } //used in case of system database @@ -456,25 +473,6 @@ Transaction* Database::getSystemDatabaseTrans(int slot) return (Transaction*)(((char*) metaData_) + offset); } -//used in case of system database -ThreadInfo* Database::getThreadInfo(int slot) -{ -/* size_t offset = os::alignLong(sizeof (DatabaseMetaData)); - offset = offset + os::alignLong( MAX_CHUNKS * sizeof (Chunk)); - offset = offset + os::alignLong( Conf::config.getMaxProcs() * sizeof(Transaction)); - offset = offset + slot * sizeof (ThreadInfo); - return (ThreadInfo*)(((char*) metaData_) + offset); -*/ - - static size_t offset = os::alignLong(sizeof (DatabaseMetaData)) + - os::alignLong( MAX_CHUNKS * sizeof (Chunk)) + - os::alignLong( Conf::config.getMaxProcs()*sizeof(Transaction)); - - size_t off = offset + slot * sizeof (ThreadInfo); - return (ThreadInfo*)(((char*) metaData_) + off); - -} - bool Database::isValidAddress(void* addr) { if ((char*) addr >= ((char*)getMetaDataPtr()) + getMaxSize()) @@ -487,7 +485,8 @@ bool Database::isValidAddress(void* addr) void* Database::allocLockHashBuckets() { Chunk *chunk = getSystemDatabaseChunk(LockTableHashBucketId); - void *ptr = chunk->allocate(this); + DbRetVal rv=OK; + void *ptr = chunk->allocate(this, &rv); if (NULL == ptr) { printError(ErrNoMemory, "Chunk Allocation failed for lock hash bucket catalog table"); @@ -515,4 +514,80 @@ DbRetVal Database::recoverMutex(Mutex *mut) { //TODO: operations need to be undone before recovering the mutex. mut->recoverMutex(); + return OK; } + +DbRetVal Database::checkPoint() +{ + char dataFile[1024]; + char cmd[1024]; + if (!Conf::config.useMmap()) { + // sprintf(dataFile, "%s/db.chkpt.data1", Conf::config.getDbFile()); + sprintf(dataFile, "%s/db.chkpt.data", Conf::config.getDbFile()); + FILE *fp = NULL; + if (fp = fopen(dataFile, "r")) { + fclose(fp); + int ret = unlink(dataFile); + if (ret != OK) { + printError(ErrOS, "Unable to delete old chkpt file. Failure"); + return ErrOS; + } + } + int fd = open(dataFile, O_WRONLY|O_CREAT, 0644); + void *buf = (void *) metaData_; + write(fd, buf, Conf::config.getMaxDbSize()); + close(fd); + sprintf(cmd, "cp -f %s/db.chkpt.data %s/db.chkpt.data1", Conf::config.getDbFile(), Conf::config.getDbFile()); + int ret = system(cmd); + if (ret != 0) { + printError(ErrOS, "Unable to take checkpoint back up file"); + return ErrOS; + } + } else { + int fd = getChkptfd(); + if (!fdatasync(fd)) { printf("pages written. checkpoint taken\n"); } + sprintf(cmd, "cp -f %s/db.chkpt.data %s/db.chkpt.data1", Conf::config.getDbFile(), Conf::config.getDbFile()); + int ret = system(cmd); + if (ret != 0) { + printError(ErrOS, "Unable to take checkpoint back up file"); + return ErrOS; + } + } + return OK; +} + +//used only by the user database not the system database +DbRetVal Database::recoverUserDB() +{ + char dataFile[1024]; + char cmd[1024]; + sprintf(dataFile, "%s/db.chkpt.data", Conf::config.getDbFile()); + int fd = open(dataFile, O_RDONLY); + if (-1 == fd) { return OK; } + void *buf = (void *) metaData_; + read(fd, buf, Conf::config.getMaxDbSize()); + close(fd); + return OK; +} + +//used only by the system database +DbRetVal Database::recoverSystemDB() +{ + char mapFile[1024]; + sprintf(mapFile, "%s/db.chkpt.map", Conf::config.getDbFile()); + int fd = open(mapFile, O_RDONLY); + if (-1 == fd) { return OK; } + CatalogTableTABLE cTable(this); + CatalogTableINDEX cIndex(this); + struct Object buf; + while (read(fd, &buf, sizeof(buf))) { + if (buf.type == Tbl) { + cTable.setChunkPtr(buf.name, buf.firstPage, buf.curPage); + } + + else if (buf.type == hIdx || buf.type == tIdx) { + cIndex.setChunkPtr(buf.name, buf.type, buf.bucketChunk, buf.firstPage, buf.curPage); + } + } + return OK; +} diff --git a/src/storage/DatabaseManagerImpl.cxx b/src/storage/DatabaseManagerImpl.cxx index f1251545..d84a1c04 100644 --- a/src/storage/DatabaseManagerImpl.cxx +++ b/src/storage/DatabaseManagerImpl.cxx @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -55,8 +56,8 @@ void DatabaseManagerImpl::createTransactionManager() } void DatabaseManagerImpl::setProcSlot() { -systemDatabase_->setProcSlot(procSlot); -db_->setProcSlot(procSlot); + systemDatabase_->setProcSlot(procSlot); + db_->setProcSlot(procSlot); } DbRetVal DatabaseManagerImpl::openSystemDatabase() { @@ -65,7 +66,6 @@ DbRetVal DatabaseManagerImpl::openSystemDatabase() systemDatabase_ = db_; db_ = NULL; printDebug(DM_Database, "Opened system database"); - logFinest(Conf::Conf::logger, "Opened system database"); return OK; } @@ -78,18 +78,31 @@ DbRetVal DatabaseManagerImpl::closeSystemDatabase() closeDatabase(); db_ = db; printDebug(DM_Database, "Closed system database"); - logFinest(Conf::logger, "Closed System database"); return OK; } DbRetVal DatabaseManagerImpl::createDatabase(const char *name, size_t size) { + bool isMmapNeeded = Conf::config.useMmap(); +/* + if (isMmapNeeded && !Conf::config.useDurability()) { + printError(ErrBadArg, "If MMAP is set to true. Durability must be true."); + return ErrBadArg; + } +*/ + int fd = -1; + char cmd[1024]; + char dbMapFile[1024]; + struct stat st; + long fixAddr = 399998976L; + bool firstTimeServer = false; if (NULL != db_ ) { printError(ErrAlready, "Database is already created"); return ErrAlready; } caddr_t rtnAddr = (caddr_t) NULL; + void *mapAddr = NULL; shared_memory_id shm_id = 0; char *startaddr = (char*)Conf::config.getMapAddress(); @@ -104,26 +117,67 @@ DbRetVal DatabaseManagerImpl::createDatabase(const char *name, size_t size) startaddr = startaddr + Conf::config.getMaxSysDbSize(); key = Conf::config.getUserDbKey(); } - shm_id = os::shm_create(key, size, 0666); - if (-1 == shm_id) - { - if (errno == EEXIST) { - printError(ErrOS, "Shared Memory already exists"); - } - printError(ErrOS, "Shared memory create failed"); - return ErrOS; + if (!isMmapNeeded || isMmapNeeded && 0 == strcmp(name, SYSTEMDB)) { + shm_id = os::shm_create(key, size, 0666); + if (-1 == shm_id) { + if (errno == EEXIST) + printError(ErrOS, "Shared Memory already exists"); + printError(ErrOS, "Shared memory create failed"); + shm_id = os::shm_open(Conf::config.getSysDbKey(), 100, 0666); + os::shmctl(shm_id, IPC_RMID); + delete systemDatabase_; + systemDatabase_ = NULL; + return ErrOS; + } + } else { + sprintf(dbMapFile, "%s/db.chkpt.data1", Conf::config.getDbFile()); + if (FILE *file = fopen(dbMapFile, "r")) { + fclose(file); + sprintf(cmd, "cp %s %s/db.chkpt.data", dbMapFile, Conf::config.getDbFile()); + int ret = system(cmd); + if (ret != 0) { + printError(ErrOS, "could not copy data file to map file"); + return ErrOS; + } + } + sprintf(dbMapFile, "%s/db.chkpt.data", Conf::config.getDbFile()); + fd = open(dbMapFile, O_CREAT | O_RDWR, 0666); + if (-1 == fd) { + printError(ErrOS, "Mmap file could not be opened"); + return ErrOS; + } + if(fstat(fd, &st) == -1) { + printf("Unable to retrieve the db File data\n"); + close(fd); + db_->setChkptfd(-1); + return ErrOS; + } + if (st.st_size == 0) { + firstTimeServer = true; + off_t flSize = lseek(fd, size - 1, SEEK_SET); + } + char *a = "0"; + int wSize = write(fd, a, 1); + mapAddr = os::mmap((void *)(fixAddr + Conf::config.getMaxSysDbSize()), size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); + rtnAddr = (caddr_t) mapAddr; + printDebug(DM_Database, "Mapped db file address = %x", mapAddr); } - - void *shm_ptr = os::shm_attach(shm_id, startaddr, SHM_RND); - rtnAddr = (caddr_t) shm_ptr; - if (rtnAddr < 0 || shm_ptr == (char*)0xffffffff) - { - printError(ErrOS, "Shared memory attach returned -ve value %d", rtnAddr); - return ErrOS; + void *shm_ptr = NULL; + if (!isMmapNeeded || isMmapNeeded && 0 == strcmp(name, SYSTEMDB)) { + shm_ptr = os::shm_attach(shm_id, startaddr, SHM_RND); + rtnAddr = (caddr_t) shm_ptr; + if (rtnAddr < 0 || shm_ptr == (char*)0xffffffff) + { + printError(ErrOS, "Shared memory attach returned -ve value %d", rtnAddr); + return ErrOS; + } } - memset(shm_ptr, 0, size ); db_ = new Database(); printDebug(DM_Database, "Creating database:%s",name); + + /*if (!isMmapNeeded || isMmapNeeded && 0 == strcmp(name, SYSTEMDB)) { + memset(shm_ptr, 0, size ); + }*/ //TODO:for user database do not have transtable and processtable mutex db_->setMetaDataPtr((DatabaseMetaData*)rtnAddr); @@ -135,6 +189,7 @@ DbRetVal DatabaseManagerImpl::createDatabase(const char *name, size_t size) db_->initTransTableMutex(); db_->initDatabaseMutex(); db_->initProcessTableMutex(); + db_->initPrepareStmtMutex(); db_->setUniqueChunkID(100); //compute the first page after book keeping information size_t offset = os::alignLong(sizeof (DatabaseMetaData)); @@ -164,8 +219,6 @@ DbRetVal DatabaseManagerImpl::createDatabase(const char *name, size_t size) chunkInfo); db_->setHashIndexChunk(chunkInfo);*/ - logFinest(Conf::logger, "Created database %s" , name); - return OK; } @@ -184,14 +237,17 @@ DbRetVal DatabaseManagerImpl::deleteDatabase(const char *name) delete db_; db_ = NULL; } - logFinest(Conf::logger, "Deleted database %s" , name); return OK; } DbRetVal DatabaseManagerImpl::openDatabase(const char *name) { + bool isMmapNeeded = Conf::config.useMmap(); + char dbMapFile[1024]; + int fd = -1; long size = Conf::config.getMaxSysDbSize(); char *startaddr = (char*)Conf::config.getMapAddress(); + long fixAddr = 399998976L; if (0 == strcmp(name , SYSTEMDB)) { if (NULL !=systemDatabase_) @@ -209,6 +265,7 @@ DbRetVal DatabaseManagerImpl::openDatabase(const char *name) } size = Conf::config.getMaxDbSize(); startaddr = startaddr + Conf::config.getMaxSysDbSize(); + fixAddr += Conf::config.getMaxSysDbSize(); } if (NULL != db_) { @@ -217,7 +274,7 @@ DbRetVal DatabaseManagerImpl::openDatabase(const char *name) } //system db should be opened before user database files caddr_t rtnAddr = (caddr_t) NULL; - + shared_memory_id shm_id = 0; shared_memory_key key = 0; @@ -236,37 +293,60 @@ DbRetVal DatabaseManagerImpl::openDatabase(const char *name) return ErrSysInternal; } void *shm_ptr = NULL; + void *mapAddr = NULL; bool firstThread = false; //printf("PRABA::DEBUG:: opendb %d %s\n", ProcessManager::noThreads, name); - if (ProcessManager::noThreads == 0 && 0 == strcmp(name, SYSTEMDB) - || ProcessManager::noThreads == 1 && 0 != strcmp(name, SYSTEMDB) ) { - shm_id = os::shm_open(key, size, 0666); - if (shm_id == -1 ) - { - printError(ErrOS, "Shared memory open failed"); - ProcessManager::mutex.releaseLock(-1, false); - return ErrOS; - } - shm_ptr = os::shm_attach(shm_id, startaddr, SHM_RND); - if (0 == strcmp(name, SYSTEMDB)) - { - firstThread = true; - ProcessManager::sysAddr = (char*) shm_ptr; - } - else - { - ProcessManager::usrAddr = (char*) shm_ptr; - } - } else { + if ( ( ProcessManager::noThreads == 0 && 0 == strcmp(name, SYSTEMDB) || + ProcessManager::noThreads == 1 && 0 != strcmp(name, SYSTEMDB) ) && + ( !isMmapNeeded || isMmapNeeded && 0 == strcmp(name, SYSTEMDB) ) ) { + shm_id = os::shm_open(key, size, 0666); + if (shm_id == -1 ) + { + printError(ErrOS, "Shared memory open failed"); + ProcessManager::mutex.releaseLock(-1, false); + return ErrOS; + } + shm_ptr = os::shm_attach(shm_id, startaddr, SHM_RND); if (0 == strcmp(name, SYSTEMDB)) - shm_ptr = ProcessManager::sysAddr; + { + firstThread = true; + ProcessManager::sysAddr = (char*) shm_ptr; + } else - shm_ptr = ProcessManager::usrAddr; + { + ProcessManager::usrAddr = (char*) shm_ptr; + } + } else if (ProcessManager::noThreads == 1 && + 0 != strcmp(name, SYSTEMDB) && isMmapNeeded) { + //dbFile to be mmapped + sprintf(dbMapFile, "%s/db.chkpt.data", Conf::config.getDbFile()); + fd = open(dbMapFile, O_RDWR, 0666); + if (-1 == fd) { + printError(ErrOS, "Mmap file could not be opened"); + ProcessManager::mutex.releaseLock(-1, false); + return ErrOS; + } + mapAddr = os::mmap((void *)fixAddr, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0); + + rtnAddr = (caddr_t) mapAddr; + printDebug(DM_Database, "Mapped db file address = %x", mapAddr); + } else { + if (!isMmapNeeded) { + if (0 == strcmp(name, SYSTEMDB)) + shm_ptr = ProcessManager::sysAddr; + else shm_ptr = ProcessManager::usrAddr; + } else { + if (0 == strcmp(name, SYSTEMDB)) + shm_ptr = ProcessManager::sysAddr; + else mapAddr = ProcessManager::usrAddr; + } } + ProcessManager::mutex.releaseLock(-1, false); - - rtnAddr = (caddr_t) shm_ptr; + if (!isMmapNeeded || isMmapNeeded && 0 == strcmp(name, SYSTEMDB)) + rtnAddr = (caddr_t) shm_ptr; + else rtnAddr = (caddr_t) mapAddr; if (rtnAddr < 0 || shm_ptr == (char*)0xffffffff) { @@ -275,11 +355,11 @@ DbRetVal DatabaseManagerImpl::openDatabase(const char *name) } db_ = new Database(); db_->setMetaDataPtr((DatabaseMetaData*)rtnAddr); + db_->setChkptfd(fd); if (firstThread) ProcessManager::systemDatabase = db_; printDebug(DM_Database, "Opening database: %s", name); - logFinest(Conf::logger, "Opened database %s" , name); return OK; } @@ -304,7 +384,6 @@ DbRetVal DatabaseManagerImpl::closeDatabase() } } ProcessManager::mutex.releaseLock(-1, false); - logFinest(Conf::logger, "Closed database"); delete db_; db_ = NULL; return OK; @@ -421,19 +500,24 @@ DbRetVal DatabaseManagerImpl::deleteUserChunk(Chunk *chunk) DbRetVal DatabaseManagerImpl::createTable(const char *name, TableDef &def) { DbRetVal rv = OK; + if (!Util::isIdentifier((char*)name)) { + printError(ErrBadArg, "Invalid character for index name"); + return ErrBadArg; + } int fldCount = def.getFieldCount(); if(0==fldCount) { printError(ErrNotExists,"Table can't be created without Field"); return ErrNotExists; } + //If total field count is less than 32, then 1 integer is used to store all null //information, if it is more then 1 char is used to store null information //of each field //This is to done to reduce cpu cycles for small tables int addSize = 0; if (fldCount < 31) addSize = 4; else addSize = os::align(fldCount); - size_t sizeofTuple = os::align(def.getTupleSize())+addSize; + size_t sizeofTuple = os::alignLong(def.getTupleSize()+addSize); rv = systemDatabase_->getDatabaseMutex(); if (OK != rv ) { @@ -510,7 +594,6 @@ DbRetVal DatabaseManagerImpl::dropTable(const char *name) printError(ErrSysInternal, "Unable to get database mutex"); return ErrSysInternal; } - //remove the entry in TABLE CatalogTableTABLE cTable(systemDatabase_); rv = cTable.getChunkAndTblPtr(name, chunk, tptr); @@ -519,6 +602,14 @@ DbRetVal DatabaseManagerImpl::dropTable(const char *name) printError(ErrSysInternal, "Table %s does not exist", name); return ErrSysInternal; } + CatalogTableFK cFK(systemDatabase_); + int noOfRelation =cFK.getNumFkTable(tptr); + if(noOfRelation) + { + printError(ErrSysInternal, "Unable to drop table due to relation exist.Drop child table..."); + systemDatabase_->releaseDatabaseMutex(); + return ErrSysInternal; + } rv = lMgr_->getExclusiveLock(chunk, NULL); if (rv !=OK) { @@ -552,7 +643,6 @@ DbRetVal DatabaseManagerImpl::dropTable(const char *name) return rv; } printDebug(DM_Database,"Deleted UserChunk:%x", chunk); - //TODO::check whether indexes are available and drop that also. CatalogTableINDEX cIndex(systemDatabase_); int noIndexes = cIndex.getNumIndexes(tptr); @@ -560,8 +650,11 @@ DbRetVal DatabaseManagerImpl::dropTable(const char *name) char *idxName = cIndex.getIndexName(tptr, 1); dropIndexInt(idxName, false); } - Chunk *chunkNode = systemDatabase_->getSystemDatabaseChunk(UserChunkTableId); - chunkNode->free(systemDatabase_, (Chunk *) chunk); + bool isFkExist=cFK.isFkTable(tptr); + if(isFkExist) + { + dropForeignKey(tptr,false); + } systemDatabase_->releaseDatabaseMutex(); printDebug(DM_Database, "Deleted Table %s" , name); logFinest(Conf::logger, "Deleted Table %s" , name); @@ -575,7 +668,7 @@ DbRetVal DatabaseManagerImpl::dropTable(const char *name) } //Return values: NULL for table not found -Table* DatabaseManagerImpl::openTable(const char *name) +Table* DatabaseManagerImpl::openTable(const char *name,bool checkpkfk) { DbRetVal ret = OK; //TODO::store table handles in list so that if it is @@ -705,6 +798,38 @@ Table* DatabaseManagerImpl::openTable(const char *name) table->idxInfo[i] = (IndexInfo*) hIdxInfo; } systemDatabase_->releaseDatabaseMutex(); + //Foreign key Operation + if(checkpkfk){ + CatalogTableFK cFk(systemDatabase_); + int totalFld=0; + table->numFkRelation_ = cFk.getNumFkTable(tptr); + if (table->numFkRelation_) { + table->isPkTbl=true;//TODO:for Delete In casecade + totalFld=cFk.getNoOfFkTable(tptr); + //printDebug(DM_TEST,"Total table is %d\n",totalFld); + char **fptr = new char* [totalFld]; + cFk.getFkTableName(tptr,fptr); + for(int count=0; count < totalFld; count++){ + //printDebug(DM_TEST,"FK Name is %s\n",fptr[count]); + table->tblFkList.append(openTable(fptr[count],false)); + } + delete[] fptr; + + } + char *tblName = NULL; + table->isFkTbl = cFk.isFkTable(tptr); + if(table->isFkTbl) + { + totalFld=cFk.getNoOfPkTable(tptr); + char **fptr = new char* [totalFld]; + cFk.getPkTableName(tptr,fptr); + for(int count=0; counttblList.append(openTable(fptr[count],false)); + } + delete[] fptr; + } + } // lMgr-> tTuple->chunkPtr_ printDebug(DM_Database,"Opening table handle name:%s chunk:%x numIndex:%d", name, chunk, table->numIndexes_); @@ -717,7 +842,7 @@ Table* DatabaseManagerImpl::openTable(const char *name) -List DatabaseManagerImpl::getAllTableNames() +List DatabaseManagerImpl::getAllTableNames(int *retval) { DbRetVal ret = OK; //to store the tuple pointer of the table @@ -726,6 +851,7 @@ List DatabaseManagerImpl::getAllTableNames() DbRetVal rv = systemDatabase_->getDatabaseMutex(); if (OK != rv) { printError(ErrSysInternal, "Unable to get database mutex"); + *retval = rv; List tableList; return tableList; } @@ -744,6 +870,21 @@ void DatabaseManagerImpl::closeTable(Table *table) printDebug(DM_Database,"Closing table handle: %x", table); if (NULL == table) return; //table->unlock(); + /* TableImpl *fkTbl =NULL; + ListIterator tblIter = ((TableImpl*)table)->tblList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + closeTable(fkTbl); + } + ((TableImpl*)table)->tblList.reset(); + tblIter = ((TableImpl*)table)->tblFkList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + closeTable(fkTbl); + } + ((TableImpl*)table)->tblFkList.reset();*/ tableHandleList.remove(table, false); if (table) delete table; table = NULL; logFinest(Conf::logger, "Closing Table"); @@ -757,6 +898,11 @@ DbRetVal DatabaseManagerImpl::createIndex(const char *indName, IndexInitInfo *in printError(ErrBadCall, "Primary key cannot be non unique\n"); return ErrBadCall; } + if (!Util::isIdentifier((char*)indName)) { + printError(ErrBadArg, "Invalid character for index name"); + return ErrBadArg; + } + if (info->indType == hashIndex) { //Assumes info is of type HashIndexInitInfo @@ -892,6 +1038,7 @@ DbRetVal DatabaseManagerImpl::createHashIndex(const char *indName, const char *t printError(ErrSysInternal, "Unable to create chunk for storing hash index nodes"); return ErrSysInternal; } + hChunk->setChunkName(indName); //add row to INDEX void *tupleptr = NULL; @@ -944,6 +1091,7 @@ DbRetVal DatabaseManagerImpl::createHashIndex(const char *indName, const char *t } void *recPtr = NULL; ChunkIterator chIter = ((Chunk *)chunk)->getIterator(); + tbl->setLoading(true); while ((recPtr = chIter.nextElement()) != NULL) { rv = tbl->insertIndexNode(*tbl->trans, tupleptr, indxInfo, recPtr); if (rv == ErrUnique) { @@ -969,10 +1117,12 @@ DbRetVal DatabaseManagerImpl::createTreeIndex(const char *indName, const char *t return ErrBadRange; } int totFlds = fldList.size(); - if (totFlds == 0) - { + if (totFlds == 0) { printError(ErrBadCall, "No Field name specified"); return ErrBadCall; + }else if (totFlds != 1) { + printError(ErrBadCall, "Composite index not supported for Tree"); + return ErrBadCall; } void *tptr =NULL; void *chunk = NULL; @@ -1062,6 +1212,7 @@ DbRetVal DatabaseManagerImpl::createTreeIndex(const char *indName, const char *t if (! tbl->numTuples()) { printDebug(DM_Database, "Creating Tree Index Name:%s tblname:%s node size:%x",indName, tblName, nodeSize); logFinest(Conf::logger, "Creating TreeIndex %s on %s with node size %d",indName, tblName, nodeSize); + closeTable(tbl); return OK; } HashIndexInfo *indxInfo = NULL; @@ -1074,6 +1225,7 @@ DbRetVal DatabaseManagerImpl::createTreeIndex(const char *indName, const char *t } void *recPtr = NULL; ChunkIterator chIter = ((Chunk *)chunk)->getIterator(); + tbl->setLoading(true); while ((recPtr = chIter.nextElement()) != NULL) { rv = tbl->insertIndexNode(*tbl->trans, tupleptr, indxInfo, recPtr); if (rv == ErrUnique) { @@ -1164,11 +1316,6 @@ DbRetVal DatabaseManagerImpl::dropIndexInt(const char *name, bool takeLock) } } if (takeLock) systemDatabase_->releaseDatabaseMutex(); - Chunk *chunkNode = systemDatabase_->getSystemDatabaseChunk(UserChunkTableId); - chunkNode->free(systemDatabase_, (Chunk *) chunk); - if (iptr->indexType_ == hashIndex) { - chunkNode->free(systemDatabase_, (Chunk *) hchunk); - } //TODO::If tuples present in this table, then //free all hash index nodes for this table. @@ -1179,6 +1326,169 @@ DbRetVal DatabaseManagerImpl::dropIndexInt(const char *name, bool takeLock) logFinest(Conf::logger, "Deleted Index %s", name); return OK; } +DbRetVal DatabaseManagerImpl::createForeignKey(char *fKName,ForeignKeyInfo *info) +{ + DbRetVal rv = OK; + int totFkFlds = info->fkFldList.size(); + int totPkFlds = info->pkFldList.size(); + if (totFkFlds==0 && totPkFlds==0) { + printError(ErrBadCall, "No Field name specified"); + return ErrBadCall; + } + void *tptr =NULL; + void *chunk = NULL; + rv = systemDatabase_->getDatabaseMutex(); + if (OK != rv) + { + printError(ErrSysInternal, "Unable to get database mutex"); + return ErrSysInternal; + } + CatalogTableTABLE cTable(systemDatabase_); + cTable.getChunkAndTblPtr(info->fkTableName, chunk, tptr); + if (NULL == tptr) + { + systemDatabase_->releaseDatabaseMutex(); + printError(ErrNotExists, "Table does not exist %s", info->fkTableName); + return ErrNotExists; + } + char **fptr = new char* [totFkFlds]; + CatalogTableFIELD cField(systemDatabase_); + rv = cField.getFieldPtrs(info->fkFldList, tptr, fptr); + if (OK != rv) + { + delete[] fptr; + systemDatabase_->releaseDatabaseMutex(); + if (rv != ErrBadCall) { + printError(ErrNotExists, "Field does not exist"); + return ErrNotExists; + } + } + void *tPkptr =NULL; + void *chunkPk = NULL; + CatalogTableTABLE c2Table(systemDatabase_); + c2Table.getChunkAndTblPtr(info->pkTableName, chunkPk, tPkptr); + if (NULL == tPkptr) + { + systemDatabase_->releaseDatabaseMutex(); + printError(ErrNotExists, "Table does not exist %s", info->pkTableName); + return ErrNotExists; + } + char **fPkptr = new char* [totPkFlds]; + CatalogTableFIELD c2Field(systemDatabase_); + rv = c2Field.getFieldPtrs(info->pkFldList, tPkptr, fPkptr); + if (OK != rv) + { + delete[] fptr; + delete[] fPkptr; + systemDatabase_->releaseDatabaseMutex(); + if (rv != ErrBadCall) { + printError(ErrNotExists, "Field does not exist"); + return ErrNotExists; + } + } + //Create New chunkdatanode + CatalogTableFK cFK(systemDatabase_); + rv = cFK.insert(fKName, tptr, tPkptr);//TODO + if (OK != rv) + { + delete[] fptr; + delete[] fPkptr; + systemDatabase_->releaseDatabaseMutex(); + printError(ErrSysInternal, "Catalog table updation failed in CFK table"); + return ErrSysInternal; + } + + CatalogTableFKFIELD cFKField(systemDatabase_); + rv = cFKField.insert(fKName,fptr,fPkptr,totFkFlds); + if (OK != rv) + { + delete[] fptr; + delete[] fPkptr; + cFK.remove(tptr); + systemDatabase_->releaseDatabaseMutex(); + printError(ErrSysInternal, "Catalog table updation failed in CFKFIELD table"); + return ErrSysInternal; + } + systemDatabase_->releaseDatabaseMutex(); + delete[] fptr; + delete[] fPkptr; + return rv; +} +DbRetVal DatabaseManagerImpl::dropForeignKey(void *tptr,bool trylock) +{ + DbRetVal rv = OK; + if(trylock){ + rv = systemDatabase_->getDatabaseMutex(); + if (OK != rv) + { + printError(ErrSysInternal, "Unable to get database mutex"); + return ErrSysInternal; + } + } + void *fkChunk=NULL; + CatalogTableFK cFK(systemDatabase_); + int total = cFK.getNoOfPkTable(tptr); + //printDebug(DM_TEST,"total fk chunk %d",total); + for (int i=0;i< total; i++) + { + fkChunk = cFK.getFkCTable(tptr); + if(NULL==fkChunk) + { + if(trylock){ + systemDatabase_->releaseDatabaseMutex(); + } + printError(ErrSysInternal, "Catalog table not finds CFKFIELD table"); + return ErrSysInternal; + } + CatalogTableFKFIELD cFKField(systemDatabase_); + rv = cFKField.remove(fkChunk); + if (OK != rv) + { + if(trylock){ + systemDatabase_->releaseDatabaseMutex(); + } + printError(ErrSysInternal, "Catalog table updation failed in CFKFIELD table"); + return ErrSysInternal; + } + rv =cFK.remove(fkChunk); + if (OK != rv) + { + if(trylock){ + systemDatabase_->releaseDatabaseMutex(); + } + printError(ErrSysInternal, "Catalog table updation failed for INDEX table"); + return ErrSysInternal; + } + } + if(trylock){ + systemDatabase_->releaseDatabaseMutex(); + } + return rv; +} + +void DatabaseManagerImpl::printTreeIndexNodeInfo(char *name, bool flag) +{ + CatalogTableINDEX cIndex(systemDatabase_); + DbRetVal rv = OK; + void *chunk = NULL, *hchunk = NULL; + void *tptr =NULL; + rv = cIndex.get(name, chunk, hchunk, tptr); + if (OK != rv) return; + IndexType iType = CatalogTableINDEX::getType(tptr); + if (treeIndex != iType) + { + printf("%s is not a tree index\n "); + return; + } + Chunk *ch = (Chunk*) chunk; + if(flag){ if(hchunk)((TreeNode*) hchunk)->displayAll(); } + else { + int offset = CatalogTableINDEX::getOffsetOfFirstField(tptr); + //if(typeInt != offset) { printf("%s is not on Integer Type Field. To see info Index should be on integer type field. \n "); return;} + if(hchunk) ((TreeNode*) hchunk)->displayAll(offset); + } +} + DbRetVal DatabaseManagerImpl::printIndexInfo(char *name) { CatalogTableINDEX cIndex(systemDatabase_); @@ -1189,17 +1499,34 @@ DbRetVal DatabaseManagerImpl::printIndexInfo(char *name) if (OK != rv) return rv; printf(" %s \n", name); printf(" %d \n", CatalogTableINDEX::getUnique(tptr)); + IndexType iType = CatalogTableINDEX::getType(tptr); + if(hashIndex == iType) + printf(" Hash Index \n"); + else if (treeIndex == iType) + printf(" Tree Index \n"); + else + printf(" Unknown Index \n"); + Chunk *ch = (Chunk*) chunk; printf("\n"); printf(" %d \n", ch->totalPages()); printf(" %d \n", CatalogTableINDEX::getNoOfBuckets(tptr)); printf("\n"); - - ch = (Chunk*) hchunk; - printf("\n"); - printf(" %d \n", ch->totalPages()); - printf(" %d \n", ch->getTotalDataNodes()); - printf("\n"); + if(treeIndex != iType){ + ch = (Chunk*) hchunk; + printf("\n"); + printf(" %d \n", ch->totalPages()); + printf(" %d \n", ch->getTotalDataNodes()); + printf("\n"); + }else{ + printf("\n"); + printf(" %d \n", ch->getTotalDataNodes()); + if(hchunk) + printf(" %lld \n",((TreeNode*) hchunk)->getTotalElements()); + else + printf(" 0 \n"); + printf("\n"); + } return OK; } @@ -1272,3 +1599,171 @@ Chunk* DatabaseManagerImpl::getSystemTableChunk(CatalogTableID id) { return systemDatabase_->getSystemDatabaseChunk(id); } + +int DatabaseManagerImpl::getNoOfPagesForTable(char *tblName) +{ + Table *tbl = openTable(tblName); + TableImpl *tb = (TableImpl *) tbl; + int pages = 0; + if (tb->numTuples()) pages = tb->pagesUsed(); + closeTable(tbl); + return pages; +} + +DbRetVal DatabaseManagerImpl::loadRecords(char *tblName, char *buffer) +{ + // buffer should be as big as the no of pages occupied by the records + Table *tbl = openTable(tblName); + TableImpl *tb = (TableImpl *) tbl; + char *bufIter = buffer; + int pages = *(int *) bufIter; bufIter += sizeof(int); + Page *firstPage = ((Chunk *)(tb->chunkPtr_))->getFirstPage(); + PageInfo *pi = (PageInfo *) firstPage; + memcpy(bufIter, pi, PAGE_SIZE); + bufIter += PAGE_SIZE; + for (int i = 0; i < pages - 1; i++) { + Page *nPage = pi->nextPage_; + memcpy(bufIter, nPage, PAGE_SIZE); + bufIter += PAGE_SIZE; + pi = (PageInfo *) nPage; + } + closeTable(tbl); + return OK; +} + +DbRetVal DatabaseManagerImpl::pasteRecords(char *tblName, void *buffer) +{ + // buffer should be as big as the no of pages occupied by the records + Table *tbl = openTable(tblName); + TableImpl *tb = (TableImpl *) tbl; + Database *db = tb->getDB(); + char *bufIter = (char *) buffer; + int pages = *(int *) bufIter; + bufIter += sizeof(int); + + Page *firstPage = ((Chunk *)(tb->chunkPtr_))->getFirstPage(); + PageInfo *pi = (PageInfo *) firstPage; + memcpy(pi, bufIter, PAGE_SIZE); + bufIter += PAGE_SIZE; + while (--pages != 0) { + //get a new page allocated + Page *newPage = db->getFreePage(); + memcpy(newPage, bufIter, PAGE_SIZE); + pi->nextPage_ = newPage; + pi = (PageInfo *) newPage; + } + // initialize chunk details and pageInfo + ((Chunk *)tb->chunkPtr_)->curPage_ = pi; + closeTable(tbl); + return OK; +} + +DbRetVal DatabaseManagerImpl::checkPoint() +{ + DbRetVal rv = writeSchemaFile(); + if (rv != OK) { printf ("checkpoint error\n"); } + rv = db()->checkPoint(); + return rv; +} + +DbRetVal DatabaseManagerImpl::writeSchemaFile() +{ + DbRetVal rv = OK; + FILE *fp = NULL; + FILE *fp1 = NULL; + int fd = -1; + char schFile[1024]; + char mapFile[1024]; + sprintf(schFile, "%s/db.chkpt.schema1", Conf::config.getDbFile()); + sprintf(mapFile, "%s/db.chkpt.map1", Conf::config.getDbFile()); + fp = fopen(schFile, "r"); + if (fp != NULL) { + fclose(fp); + int ret = unlink(schFile); + if( ret != 0) { + printError(ErrOS, "checkpoint: delete schema file failed"); + return ErrOS; + } + } + fp = fopen(schFile, "w+"); + if (fp == NULL) { + printError(ErrOS, "Unable to create schema file for chkpt."); + return ErrOS; + } + fp1 = fopen(mapFile, "r"); + if (fp1 != NULL) { + fclose(fp1); + int ret = unlink(mapFile); + if( ret != 0) { + printError(ErrOS, "checkpoint: delete schema file failed"); + return ErrOS; + } + } + fd = open(mapFile, O_WRONLY|O_CREAT, 0644); + if (fd == -1) { + printError(ErrOS, "checkpoint: Unable to create map file."); + return ErrOS; + } + List tableList = getAllTableNames(); + ListIterator iter = tableList.getIterator(); + Identifier *elem = NULL; + int count =0; + while (iter.hasElement()) { + elem = (Identifier*) iter.nextElement(); +// if (TableConf::config.isTableCached(elem->name) == OK) continue; + fprintf(fp, "CREATE TABLE %s (", elem->name); + Table *table = openTable(elem->name); + + void *chunk = NULL; void *tptr =NULL; + CatalogTableTABLE cTable(systemDatabase_); + rv = cTable.getChunkAndTblPtr(elem->name, chunk, tptr); + struct Object obj; + strcpy(obj.name, elem->name); + obj.type = Tbl; + obj.bucketChunk = NULL; + obj.firstPage = ((Chunk *)chunk)->getFirstPage(); + obj.curPage = ((Chunk *)chunk)->getCurrentPage(); + void *buf = &obj; + write(fd, buf, sizeof(obj)); + FieldInfo *info = new FieldInfo(); + List fNameList = table->getFieldNameList(); + ListIterator fNameIter = fNameList.getIterator(); + count++; + bool firstField=true; + char fieldName[IDENTIFIER_LENGTH]; + while (fNameIter.hasElement()) { + elem = (Identifier*) fNameIter.nextElement(); + Table::getFieldNameAlone(elem->name, fieldName); + rv = table->getFieldInfo(elem->name, info); + if (rv !=OK) { + printf("unable to retrive info for table %s\n", elem->name); + } + if (firstField) { + fprintf(fp, "%s %s ", fieldName, AllDataType::getSQLString(info->type)); + firstField = false; + } else + fprintf(fp, ", %s %s ", fieldName, AllDataType::getSQLString(info->type)); + if (info->type == typeString) fprintf(fp, "(%d)",info->length ); + if (info->type == typeBinary) fprintf(fp, "(%d)",info->length); + if (info->isNull) fprintf(fp, " NOT NULL "); + if (info->isDefault) fprintf(fp, " DEFAULT '%s' ", info->defaultValueBuf); + if (info->isAutoIncrement) fprintf(fp, " AUTO_INCREMENT "); + } + fprintf(fp, ");\n"); + table->printSQLIndexString(fp, fd); + delete info; + closeTable(table); + } + fclose(fp); + close(fd); + return OK; +} + +DbRetVal DatabaseManagerImpl::recover() +{ + DbRetVal rv = OK; + if (!Conf::config.useMmap())rv = db()->recoverUserDB(); + rv = sysDb()->recoverSystemDB(); + return rv; +} + diff --git a/src/storage/Debug.cxx b/src/storage/Debug.cxx index 6c9b5325..79628d22 100644 --- a/src/storage/Debug.cxx +++ b/src/storage/Debug.cxx @@ -14,8 +14,9 @@ * * ***************************************************************************/ #include +#include -int DebugDM_Alloc = 1; +int DebugDM_Alloc = 0; int DebugDM_VarAlloc = 0; int DebugDM_Lock = 0; int DebugDM_Transaction = 0; @@ -28,36 +29,62 @@ int DebugDM_SystemDatabase = 0; int DebugDM_Database = 0; int DebugDM_Table = 0; int DebugDM_Predicate = 0; -int DebugDM_TableIterator = 1; +int DebugDM_TableIterator = 0; int DebugDM_Process=0; int DebugDM_Network=0; int DebugDM_Gateway=0; int DebugDM_Adapter=0; int DebugDM_SqlLog=0; +int DebugDM_CacheServer=0; +int DebugDM_TEST=1; +int DebugDM_Warning=0; +int printStackTrace() +{ +#ifdef LINUX + void *array[10]; + size_t size = backtrace(array, 10); + backtrace_symbols_fd(array, size, 2); +#endif + return 0; +} int printError1(DbRetVal val, char* fname, int lno, char *format, ...) { - va_list ap; - char mesgBuf[1024]; - - sprintf(mesgBuf, "%d:%lu:%s:%d:", - os::getpid(), os::getthrid(), fname, lno); - os::write(2, mesgBuf, strlen(mesgBuf)); + va_list ap; + int fd = -1; + char tempBuffer[25]; + struct timeval timeStamp; + os::gettimeofday(&timeStamp); + struct tm *tempTm = os::localtime(&timeStamp.tv_sec); + char mesgBuf[1024]; +#if defined(SOLARIS) && defined(REMOTE_SOLARIS) + strftime(tempBuffer, 25, "%d/%m/%Y %H:%M:%S", (struct std::tm*) tempTm); +#else + strftime(tempBuffer, 25, "%d/%m/%Y %H:%M:%S", tempTm); +#endif - va_start(ap, format); + if (strncasecmp(Conf::config.getStderrFile(),"stderr", 6) == 0) fd = 2; + else { + fd = os::openFileForAppend(Conf::config.getStderrFile(), O_CREAT); + if (fd == -1) fd = 2; + } - int err = ::vsnprintf(mesgBuf, sizeof(mesgBuf), format,ap); - if(err < 0) { - return err; - } - os::write(2, mesgBuf, strlen(mesgBuf)); - strcpy(mesgBuf,"\n"); - os::write(2, mesgBuf, strlen(mesgBuf)); - //2->stderr - return 0; -} + snprintf(mesgBuf, MAX_TRACE_LOG_LENGTH, "%s.%6d:%5d:%10lu:%s:%d:", + tempBuffer, timeStamp.tv_usec, os::getpid(), os::getthrid(), fname, lno); + os::write(fd, mesgBuf, strlen(mesgBuf)); + + va_start(ap, format); + int err = ::vsnprintf(mesgBuf, sizeof(mesgBuf), format,ap); + if (err < 0) { return err; } + + os::write(fd, mesgBuf, strlen(mesgBuf)); + strcpy(mesgBuf,"\n"); + os::write(fd, mesgBuf, strlen(mesgBuf)); + //2->stderr + return 0; +} int printDebug1(int module, char *fname, int lno, char *format, ...) { @@ -80,6 +107,9 @@ int printDebug1(int module, char *fname, int lno, char *format, ...) case DM_Gateway: { if (!DebugDM_Gateway) return 1; break; } case DM_Adapter: { if (!DebugDM_Adapter) return 1; break; } case DM_SqlLog: { if (!DebugDM_SqlLog) return 1; break; } + case DM_CacheServer: { if (!DebugDM_CacheServer) return 1; break; } + case DM_TEST: { if (!DebugDM_TEST) return 1; break; } + case DM_Warning: { if (!DebugDM_Warning) return 1; break; } } diff --git a/src/storage/Expression.cxx b/src/storage/Expression.cxx index d8a49e95..8042125c 100644 --- a/src/storage/Expression.cxx +++ b/src/storage/Expression.cxx @@ -71,7 +71,7 @@ void Expression::setExpr(Expression *exp1, ArithOperator op, Expression *exp2) void *Expression::evaluate(DataType type,bool &result) { calVal=AllDataType::alloc(type,IDENTIFIER_LENGTH); - AllDataType::memoryset(calVal, type); + AllDataType::memoryset(calVal,type); char *rhsResult = NULL , *lhsResult = NULL; if (NULL != lhs) { diff --git a/src/storage/FieldList.cxx b/src/storage/FieldList.cxx index 756072b6..6923106a 100644 --- a/src/storage/FieldList.cxx +++ b/src/storage/FieldList.cxx @@ -127,6 +127,22 @@ void *FieldList::getBindField(const char *fldName) printError(ErrNotFound, "Field not present in the list"); return NULL; } +void FieldList::fillFieldInfo(int fldpos, void *inp) +{ + int pos=0; + FieldNode *iter = head; + while (pos next; pos++; } + FieldInfoValue *info = (FieldInfoValue*) inp; + strcpy(info->fldName , iter->fldDef.fldName_); + info->length = iter->fldDef.length_; + info->type = iter->fldDef.type_; + info->offset = iter->fldDef.offset_; + info->isNullable = iter->fldDef.isNull_; + info->isPrimary = iter->fldDef.isPrimary_; + info->isUnique = iter->fldDef.isUnique_; + info->isAutoIncrement = iter->fldDef.isAutoIncrement_; +} + DbRetVal FieldList::getFieldInfo(const char *fldName, FieldInfo *&info) { @@ -143,6 +159,7 @@ DbRetVal FieldList::getFieldInfo(const char *fldName, FieldInfo *&info) info->isNull = iter->fldDef.isNull_; info->isPrimary = iter->fldDef.isPrimary_; info->isUnique = iter->fldDef.isUnique_; + info->isAutoIncrement = iter->fldDef.isAutoIncrement_; return OK; } @@ -159,6 +176,7 @@ DbRetVal FieldList::getFieldInfo(const char *fldName, FieldInfo *&info) info->isNull = iter->fldDef.isNull_; info->isPrimary = iter->fldDef.isPrimary_; info->isUnique = iter->fldDef.isUnique_; + info->isAutoIncrement = iter->fldDef.isAutoIncrement_; return OK; } iter = iter ->next; @@ -176,7 +194,7 @@ int FieldList::getFieldOffset(const char *fldName) { return offset; } - offset = offset + os::align(iter->fldDef.length_); + offset = offset + iter->fldDef.length_; iter = iter ->next; } return -1; @@ -193,7 +211,7 @@ int FieldList::getFieldOffset(int fldpos) { return offset; } - offset = offset + os::align(iter->fldDef.length_); + offset = offset + iter->fldDef.length_; iter = iter ->next; counter++; } @@ -205,11 +223,13 @@ int FieldList::getFieldOffset(int fldpos) //-1 if field not found in the list int FieldList::getFieldPosition(const char *fldName) { + char onlyFldName[IDENTIFIER_LENGTH]; + Table::getFieldNameAlone((char*)fldName, onlyFldName); int position = 1; FieldNode *iter = head; while(iter != NULL) { - if (0 == strcmp(iter->fldDef.fldName_, fldName)) + if (0 == strcmp(iter->fldDef.fldName_, onlyFldName)) return position; position++; iter = iter->next; @@ -224,7 +244,7 @@ int FieldList::getTupleSize() int offset = 0; while(iter != NULL) { - offset = offset + os::align(iter->fldDef.length_); + offset = offset + iter->fldDef.length_; iter = iter ->next; } return offset; diff --git a/src/storage/FixedHeapAllocator.cxx b/src/storage/FixedHeapAllocator.cxx new file mode 100644 index 00000000..aaa8cf97 --- /dev/null +++ b/src/storage/FixedHeapAllocator.cxx @@ -0,0 +1,118 @@ +#include +#include +#include + +void FixedHeapAllocator::initializeInfo(void *ptr) +{ + *(void **)ptr = top; + top = ptr; + usedBytes = 0; + offset = (char*)top+PAGEINFOSIZE; + *(short*)((char*)offset+1) = pageSize- PAGEINFOSIZE-BLOCKINFOSIZE; +} + +void FixedHeapAllocator::init(int pSize,int allocSize) +{ + void *ptr; + ptr = ::calloc(pSize,1); + if(ptr == NULL) + { + printError(ErrOS, "Unable to allocate %d bytes", pSize); + return; + } + allocateSize = allocSize; + pageSize = pSize; + initializeInfo(ptr); + isInitialized = 1; + pageCounter++; + +} + +void* FixedHeapAllocator::allocate() +{ + void *allocateptr, *ptr, *freeSpaceDetector, *pageDetector; + short int pageSizeCounter = 0, add; + short int isFound = 0; + + if(isInitialized != 1) + { + printError(ErrBadCall, "Allocator is not initialized"); + return NULL; + } + if(allocateSize > ( pageSize - PAGEINFOSIZE-(2*BLOCKINFOSIZE) )) + { + printf("The requested size is greater than the page Size"); + return NULL; + } + //TODO::we will implement mode later for this fixed size allocator + //printf("\ninside allocate offset = %u\tpagesize= %d\tusedmemory=%d\tmemoryrequested = %d",offset,pageSize,usedBytes, allocateSize ); + if( ( usedBytes + allocateSize ) > ( pageSize - PAGEINFOSIZE ) ) + { + printDebug(DM_Alloc, "Current page exhausted. allocating new page"); + ptr = calloc(pageSize,1); + if(ptr == NULL) + { + printError(ErrOS, "Unable to allocate %d bytes", pageSize); + return NULL; + } + pageCounter++; + initializeInfo(ptr); + } + allocateptr = offset; + offset = (char *)offset+allocateSize ; + usedBytes += allocateSize ; + //printf("\nafter allocate offset = %u\tusedmemory=%d\tmemoryrequested = %d\treturn ptr = %u",offset,usedBytes, allocateSize,allocateptr); + return (allocateptr); +} + +void FixedHeapAllocator::deAllocate(void *ptr) +{ +} + +void FixedHeapAllocator::destroy() +{ + void *ptr, *temp; + ptr = top; + unsigned int add; + while(ptr) + { + temp = ptr; + ptr = *(void **)ptr; + //printf("deallocating %u",temp); + free(temp); + } +} + +/*int main() +{ + cout << "This is the main program"; + int bsize; + FixedHeapAllocator mAllocator; + mAllocator.init(50,10); + int i = 0, choice; + unsigned int ptr; + while(true) + { + cout << "enter the choice that u want"; + cin>> choice; + if(choice == 1) + { + // cout << "please enter the memory in bytes that u want to allocate"; + // cin >> bsize; + mAllocator.allocate(); + } + else if(choice == 2) + { + cout << "please enter the memory address to deallocate"; + cin >> ptr; + } + else + { + // exit(1); + break; + } + } + + mAllocator.destroy(); + exit(1); +}*/ diff --git a/src/storage/HashIndex.cxx b/src/storage/HashIndex.cxx index 4ec441e8..90ea74d3 100644 --- a/src/storage/HashIndex.cxx +++ b/src/storage/HashIndex.cxx @@ -115,43 +115,39 @@ DbRetVal HashIndex::insert(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde int noOfBuckets = info->noOfBuckets; int offset = info->fldOffset; DataType type = info->type; - char *keyBuffer = (char*) malloc(info->compLength); - memset(keyBuffer, 0, info->compLength); - void *keyStartBuffer = keyBuffer, *keyPtr; - FieldIterator iter = info->idxFldList.getIterator(); - while(iter.hasElement()) - { - FieldDef *def = iter.nextElement(); - keyPtr = (char *)tuple + def->offset_; - AllDataType::copyVal(keyBuffer, keyPtr, def->type_, def->length_); - keyBuffer = keyBuffer + AllDataType::size(def->type_, def->length_); - } printDebug(DM_HashIndex, "Inserting hash index node for %s", iptr->indName_); ChunkIterator citer = CatalogTableINDEX::getIterator(indexPtr); Bucket* buckets = (Bucket*)citer.nextElement(); - keyPtr =(void*)((char*)tuple + offset); + void *keyPtr =(void*)((char*)tuple + offset); int bucketNo = 0; - if (type == typeComposite) + if (type == typeComposite) { + char *keyBuffer = (char*) malloc(info->compLength); + memset(keyBuffer, 0, info->compLength); + void* keyStartBuffer = keyBuffer; + FieldIterator iter = info->idxFldList.getIterator(); + while(iter.hasElement()) + { + FieldDef *def = iter.nextElement(); + keyPtr = (char *)tuple + def->offset_; + AllDataType::copyVal(keyBuffer, keyPtr, def->type_, def->length_); + keyBuffer = keyBuffer + AllDataType::size(def->type_, def->length_); + } bucketNo = computeHashBucket(type, keyStartBuffer, noOfBuckets, info->compLength); - else + ::free(keyStartBuffer); + } + else { bucketNo = computeHashBucket(type, keyPtr, noOfBuckets, info->compLength); + } printDebug(DM_HashIndex, "HashIndex insert bucketno %d", bucketNo); Bucket *bucket = &(buckets[bucketNo]); - HashUndoLogInfo *hInfo = new HashUndoLogInfo(); - hInfo->metaData_ = tbl->db_->getMetaDataPtr(); - hInfo->bucket_ = bucket; - hInfo->tuple_ = tuple; - hInfo->hChunk_ = ((CINDEX *)indexPtr)->hashNodeChunk_; - hInfo->keyPtr_ = keyPtr; - int ret = bucket->mutex_.getLock(tbl->db_->procSlot); - if (ret != 0) - { - delete hInfo; - free(keyStartBuffer); - printError(ErrLockTimeOut,"Unable to acquire bucket Mutex for bucket %d",bucketNo); - return ErrLockTimeOut; - } + HashUndoLogInfo hInfo; + hInfo.metaData_ = tbl->db_->getMetaDataPtr(); + hInfo.bucket_ = bucket; + hInfo.tuple_ = tuple; + hInfo.hChunk_ = ((CINDEX *)indexPtr)->hashNodeChunk_; + hInfo.keyPtr_ = keyPtr; + HashIndexNode *head = (HashIndexNode*) bucket->bucketList_; if (head && info->isUnique) { @@ -177,32 +173,48 @@ DbRetVal HashIndex::insert(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde else res = AllDataType::compareVal((void*)((char*)bucketTuple +offset), (void*)((char*)tuple +offset), OpEquals,type, info->compLength); if (res) { - delete hInfo; - free(keyStartBuffer); printError(ErrUnique, "Unique key violation"); - bucket->mutex_.releaseLock(tbl->db_->procSlot); + if (type == typeLongLong) printError(ErrUnique, "Unique key violation for id:%lld",*(long long*) ((char*)tuple +offset) ); return ErrUnique; } } } + Chunk *hIdxNodeChunk = (Chunk*)iptr->hashNodeChunk_; printDebug(DM_HashIndex, "HashIndex insert into bucket list"); if (!head) { printDebug(DM_HashIndex, "HashIndex insert head is empty"); DbRetVal rv = OK; - HashIndexNode *firstNode= (HashIndexNode*)(((Chunk*)iptr->hashNodeChunk_)->allocate(tbl->db_, &rv)); - if (firstNode == NULL) + HashIndexNode *firstNode= NULL; + + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) { - bucket->mutex_.releaseLock(tbl->db_->procSlot); - delete hInfo; - free(keyStartBuffer); + rv = OK; + firstNode= (HashIndexNode*) hIdxNodeChunk->allocate(tbl->db_, &rv); + if (firstNode !=NULL) break; + if (rv != ErrLockTimeOut) + { + printError(rv, "Unable to allocate hash index node"); + return rv; + } + tries++; + } + if (firstNode == NULL){ + printError(rv, "Unable to allocate hash index node after %d retry", tries); return rv; } firstNode->ptrToKey_ = keyPtr; firstNode->ptrToTuple_ = tuple; firstNode->next_ = NULL; - bucket->bucketList_ = (HashIndexNode*)firstNode; + if (0 != Mutex::CASL((long*)&bucket->bucketList_, 0, (long)firstNode)) { + printError(ErrLockTimeOut, "Hash Index bucket lock timeout.. retry"); + hIdxNodeChunk->free(tbl->db_, firstNode); + return ErrLockTimeOut; + } + printDebug(DM_HashIndex, "HashIndex insert new node %x in empty bucket", bucket->bucketList_); } else @@ -210,26 +222,28 @@ DbRetVal HashIndex::insert(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde BucketList list(head); rc = list.insert((Chunk*)iptr->hashNodeChunk_, tbl->db_, keyPtr, tuple); if (rc !=OK) { - bucket->mutex_.releaseLock(tbl->db_->procSlot); - delete hInfo; - free(keyStartBuffer); + printError(rc, "unable to insert into bucketlist rv:%d", rc); return rc; } } if (!loadFlag) { - rc = tr->appendLogicalHashUndoLog(tbl->sysDB_, InsertHashIndexOperation, hInfo, sizeof(HashUndoLogInfo)); + rc = tr->appendLogicalHashUndoLog(tbl->sysDB_, InsertHashIndexOperation, &hInfo, sizeof(HashUndoLogInfo)); if (rc !=OK) { + printError(rc, "Unable to append logical log before rc:%d", rc); BucketList list(head); - rc = list.remove((Chunk*)iptr->hashNodeChunk_, tbl->db_, keyPtr); - if (rc !=OK) printError(ErrSysFatal, "double failure on undo log insert followed by hash bucket list remove\n"); - bucket->bucketList_ = list.getBucketListHead(); + DbRetVal rv = list.remove((Chunk*)iptr->hashNodeChunk_, tbl->db_, keyPtr); + //bucket->bucketList_ = list.getBucketListHead(); + if (rv == SplCase) { + printError(ErrWarning, "SplCase occured"); + if (0 != Mutex::CASL((long*)&bucket->bucketList_, + (long)bucket->bucketList_, (long)list.getBucketListHead())) { + printError(ErrSysFatal, "Double failure, may lead to hash node leak\n"); + } + }else if (rv !=OK) printError(ErrSysFatal, "double failure on undo log insert followed by hash bucket list remove\n"); } } - free(keyStartBuffer); - delete hInfo; hInfo = NULL; - bucket->mutex_.releaseLock(tbl->db_->procSlot); return rc; } @@ -245,46 +259,39 @@ DbRetVal HashIndex::remove(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde ChunkIterator citer = CatalogTableINDEX::getIterator(indexPtr); Bucket* buckets = (Bucket*)citer.nextElement(); - char *keyBuffer = (char*) malloc(info->compLength); - memset(keyBuffer, 0, info->compLength); - void *keyStartBuffer = keyBuffer, *keyPtr; - FieldIterator iter = info->idxFldList.getIterator(); - while(iter.hasElement()) - { - FieldDef *def = iter.nextElement(); - keyPtr = (char *)tuple + def->offset_; - AllDataType::copyVal(keyBuffer, keyPtr, def->type_, def->length_); - keyBuffer = keyBuffer + AllDataType::size(def->type_, def->length_); - } - keyPtr =(void*)((char*)tuple + offset); + void *keyPtr =(void*)((char*)tuple + offset); int bucket = 0; - if (type == typeComposite) + if (type == typeComposite) { + char *keyBuffer = (char*) malloc(info->compLength); + memset(keyBuffer, 0, info->compLength); + void *keyStartBuffer = keyBuffer; + FieldIterator iter = info->idxFldList.getIterator(); + while(iter.hasElement()) + { + FieldDef *def = iter.nextElement(); + keyPtr = (char *)tuple + def->offset_; + AllDataType::copyVal(keyBuffer, keyPtr, def->type_, def->length_); + keyBuffer = keyBuffer + AllDataType::size(def->type_, def->length_); + } bucket = HashIndex::computeHashBucket(type, keyStartBuffer, noOfBuckets, info->compLength); - else bucket = HashIndex::computeHashBucket(type, keyPtr, noOfBuckets, info->compLength); + ::free(keyStartBuffer); + } + else { + bucket = HashIndex::computeHashBucket(type, keyPtr, noOfBuckets, info->compLength); + } Bucket *bucket1 = &buckets[bucket]; - HashUndoLogInfo *hInfo = new HashUndoLogInfo(); - hInfo->metaData_ = tbl->db_->getMetaDataPtr(); - hInfo->bucket_ = bucket1; - hInfo->tuple_ = tuple; - hInfo->hChunk_ = ((CINDEX *)indexPtr)->hashNodeChunk_; - hInfo->keyPtr_ = keyPtr; + HashUndoLogInfo hInfo; + hInfo.metaData_ = tbl->db_->getMetaDataPtr(); + hInfo.bucket_ = bucket1; + hInfo.tuple_ = tuple; + hInfo.hChunk_ = ((CINDEX *)indexPtr)->hashNodeChunk_; + hInfo.keyPtr_ = keyPtr; - int ret = bucket1->mutex_.getLock(tbl->db_->procSlot); - if (ret != 0) - { - delete hInfo; - free(keyStartBuffer); - printError(ErrLockTimeOut,"Unable to acquire bucket Mutex for bucket %d",bucket); - return ErrLockTimeOut; - } HashIndexNode *head = (HashIndexNode*) bucket1->bucketList_; if (!head) { printError(ErrNotExists, "Hash index does not exist:should never happen\n"); - bucket1->mutex_.releaseLock(tbl->db_->procSlot); - delete hInfo; - free(keyStartBuffer); return ErrNotExists; } BucketList list(head); @@ -294,21 +301,27 @@ DbRetVal HashIndex::remove(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde if (SplCase == rc) { printDebug(DM_HashIndex, "Removing hash index node from head "); - bucket1->bucketList_ = list.getBucketListHead(); + //bucket1->bucketList_ = list.getBucketListHead(); + if (0 != Mutex::CASL((long*)&bucket1->bucketList_, + (long)head, (long)list.getBucketListHead())) { + printError(ErrSysFatal, "Lock time out for hash bucket. retry\n"); + return ErrLockTimeOut; + } rc = OK; } if (!loadFlag) { - rc =tr->appendLogicalHashUndoLog(tbl->sysDB_, DeleteHashIndexOperation, hInfo, sizeof(HashUndoLogInfo)); + rc =tr->appendLogicalHashUndoLog(tbl->sysDB_, DeleteHashIndexOperation, &hInfo, sizeof(HashUndoLogInfo)); if (rc !=OK) { rc = list.insert((Chunk*)iptr->hashNodeChunk_, tbl->db_, keyPtr, tuple); if (rc !=OK) printError(ErrSysFatal, "double failure on undo log remove followed by hash bucket list insert\n"); - bucket1->bucketList_ = list.getBucketListHead(); + //bucket1->bucketList_ = list.getBucketListHead(); + if (0 != Mutex::CASL((long*)&bucket1->bucketList_, + (long)bucket1->bucketList_, (long)list.getBucketListHead())) { + printError(ErrSysFatal, "Double failure on index insert"); + } } } - bucket1->mutex_.releaseLock(tbl->db_->procSlot); - delete hInfo; - free(keyStartBuffer); return rc; } @@ -345,7 +358,7 @@ DbRetVal HashIndex::update(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde if(type==typeBinary) { keyBindBuffer = (char*) malloc(2 * info->compLength); memset(keyBindBuffer, 0, 2 * info->compLength); - }else { + } else { keyBindBuffer = (char*) malloc(info->compLength); memset(keyBindBuffer, 0, info->compLength); } @@ -380,12 +393,12 @@ DbRetVal HashIndex::update(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde } } if (!keyUpdated) { - //printf("PRABA::key not updated\n"); + //printf("DEBUG::key not updated\n"); free(keyStartBuffer); free(oldKeyStartBuffer); return OK; } - //printf("PRABA::it is wrong coming here\n"); + //printf("DEBUG::it is wrong coming here\n"); bool result = false; if (type == typeComposite) result = AllDataType::compareVal(oldKeyStartBuffer, keyStartBuffer, @@ -415,7 +428,7 @@ DbRetVal HashIndex::update(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde hInfo1->metaData_ = tbl->db_->getMetaDataPtr(); hInfo1->bucket_ = bucket; hInfo1->tuple_ = tuple; - hInfo1->hChunk_ = indexPtr; + hInfo1->hChunk_ = ((CINDEX *)indexPtr)->hashNodeChunk_; hInfo1->keyPtr_ = keyPtr; //it may run into deadlock, when two threads updates tuples which falls in @@ -555,13 +568,25 @@ DbRetVal HashIndex::insertLogicalUndoLog(Database *sysdb, void *data) { HashUndoLogInfo *info = (HashUndoLogInfo *) data; Chunk *hChunk = (Chunk *) info->hChunk_; - Database *db = new Database(); - db->setMetaDataPtr((DatabaseMetaData *) info->metaData_); - db->setProcSlot(sysdb->procSlot); + Database db; + db.setMetaDataPtr((DatabaseMetaData *) info->metaData_); + db.setProcSlot(sysdb->procSlot); HashIndexNode *head = (HashIndexNode *)((Bucket *)info->bucket_)->bucketList_; BucketList list(head); - list.insert(hChunk, db, info->keyPtr_, info->tuple_); - ((Bucket *)info->bucket_)->bucketList_ = list.getBucketListHead(); + DbRetVal rv = list.insert(hChunk, &db, info->keyPtr_, info->tuple_); + if (rv != OK) + { + printError(ErrLockTimeOut, "Unable to add to bucket..retry\n"); + return ErrLockTimeOut; + } + //((Bucket *)info->bucket_)->bucketList_ = list.getBucketListHead(); + if (0 != Mutex::CASL((long*)& (((Bucket *)info->bucket_)->bucketList_), + (long)(((Bucket *)info->bucket_)->bucketList_), + (long)list.getBucketListHead())) + { + printError(ErrLockTimeOut, "Unable to add to bucket..retry\n"); + return ErrLockTimeOut; + } return OK; } @@ -569,14 +594,24 @@ DbRetVal HashIndex::deleteLogicalUndoLog(Database *sysdb, void *data) { HashUndoLogInfo *info = (HashUndoLogInfo *) data; Chunk *hChunk = (Chunk *) info->hChunk_; - Database *db = new Database(); - db->setMetaDataPtr((DatabaseMetaData *)info->metaData_); - db->setProcSlot(sysdb->procSlot); + Database db; + db.setMetaDataPtr((DatabaseMetaData *)info->metaData_); + db.setProcSlot(sysdb->procSlot); HashIndexNode *head = (HashIndexNode *)((Bucket *)info->bucket_)->bucketList_; BucketList list(head); - DbRetVal rc = list.remove(hChunk, db, info->keyPtr_); + DbRetVal rc = list.remove(hChunk, &db, info->keyPtr_); + //((Bucket *)info->bucket_)->bucketList_ = list.getBucketListHead(); if (SplCase == rc) { - ((Bucket *)info->bucket_)->bucketList_ = list.getBucketListHead(); + if (0 != Mutex::CASL((long*)& (((Bucket *)info->bucket_)->bucketList_), + (long)(((Bucket *)info->bucket_)->bucketList_), + (long)list.getBucketListHead())) + { + printError(ErrLockTimeOut, "Unable to set the head of hash index bucket\n"); + return ErrLockTimeOut; + } + }else if (rc != OK) { + printError(ErrLockTimeOut, "Unable to remove hash index node"); + return ErrLockTimeOut; } return OK; } diff --git a/src/storage/HashMap.cxx b/src/storage/HashMap.cxx new file mode 100644 index 00000000..9953aaa1 --- /dev/null +++ b/src/storage/HashMap.cxx @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +DbRetVal HashMap::insert(void *element) +{ + HashMapNode *newNode = new HashMapNode(); + newNode->elem = element; + newNode->next = NULL; + int hashVal =0; + if (optGrpIntNoNull) + hashVal = (*(int*)element) % bucketSize; + else + hashVal = Util::hashBinary((char*)element, keySize) % bucketSize; + HashMapNode *node = (HashMapNode*) bucket[hashVal]; + if (NULL == node) + { + bucket[hashVal] = newNode; + return OK; + } + while(node->next != NULL) { node=node->next; } + node->next = newNode; + return OK; +} +void* HashMap::find(void *element) +{ + int hashVal = 0; + if (optGrpIntNoNull) { + int value = *(int*)element; + hashVal = value % bucketSize; + HashMapNode *node = (HashMapNode*) bucket[hashVal]; + while(node != NULL) { + if (*(int*)node->elem == value) return node->elem; + node = node->next; + } + } + else { + hashVal = Util::hashBinary((char*)element, keySize) % bucketSize; + HashMapNode *node = (HashMapNode*) bucket[hashVal]; + while(node != NULL) { + if (AllDataType::compareVal(node->elem, element, OpEquals, + typeBinary, keySize)) + return node->elem; + node = node->next; + } + } + return NULL; +} +void HashMap::removeAll() +{ + for (int i=0; i next; + delete prev; + } + bucket[i]=NULL; + } + return; +} + diff --git a/src/storage/JoinTableImpl.cxx b/src/storage/JoinTableImpl.cxx index 234ff140..688779a2 100644 --- a/src/storage/JoinTableImpl.cxx +++ b/src/storage/JoinTableImpl.cxx @@ -26,31 +26,19 @@ JoinTableImpl::JoinTableImpl() curTuple = NULL; leftTableHdl = NULL; rightTableHdl = NULL; + isLeftRecOver = false; + isFirstCall = true; + availableLeft = true; + isFirstFetch = true; + isReturnNull = false; + isOuterJoin = false; + leftSideFail = false; + jType = INNER_JOIN; + isNestedLoop = true; + rightExhausted = false; } JoinTableImpl::~JoinTableImpl() {} -/* moved to Table class - * shall be removed -void JoinTableImpl::getFieldNameAlone(char *fname, char *name) { - bool dotFound= false; - char *fullname = fname; - while(*fullname != '\0') - { - if (*fullname == '.') { dotFound = true; break; } - fullname++; - } - if (dotFound) strcpy(name, ++fullname); else strcpy(name, fname); -} -void JoinTableImpl::getTableNameAlone(char *fname, char *name) { - strcpy(name, fname); - while(*name != '\0') - { - if (*name == '.') { *name='\0'; break; } - name++; - } - return; -} -*/ DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val) { FieldInfo *info = new FieldInfo(); @@ -76,7 +64,12 @@ DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val) strcpy(def->fieldName, fieldName); strcpy(def->tabFieldName, fldname); def->appBuf = val; - getFieldInfo(fldname, info); + DbRetVal rv = getFieldInfo(fldname, info); + if ( OK != rv) { + printError(ErrBadCall, "Field not found or unqualified field name %s", fldname); + delete info; + return ErrSyntaxError; + } def->bindBuf = AllDataType::alloc(info->type, info->length); if (availableLeft) leftTableHdl->bindFld(fldname, def->bindBuf); @@ -200,6 +193,15 @@ void JoinTableImpl::printPlan(int space) spaceBuf[space] = '\0'; PredicateImpl* predImpl = (PredicateImpl*) pred; printf("%s \n", spaceBuf); + if (jType == INNER_JOIN) + printf("%s INNER_JOIN \n", spaceBuf); + else if (jType == LEFT_JOIN) + printf("%s LEFT_JOIN \n", spaceBuf); + else if (jType == RIGHT_JOIN) + printf("%s RIGHT_JOIN \n", spaceBuf); + else if (jType == FULL_JOIN) + printf("%s FULL_JOIN \n", spaceBuf); + if (predImpl) predImpl->print(space); printf("%s \n", spaceBuf); leftTableHdl->printPlan(space+2); @@ -211,23 +213,57 @@ void JoinTableImpl::printPlan(int space) } DbRetVal JoinTableImpl::execute() { + //if (!leftTableHdl->getName()) printf("execute called with isFirstCall %d\n", isFirstCall); PredicateImpl* predImpl = (PredicateImpl*) pred; isNestedLoop = true; - if (pred) predImpl->setProjectionList(&projList); + if (pred) + { + predImpl->setProjectionList(&projList); + predImpl->solveForProjList(this); + } //push the table scan predicates - optimize(); - leftTableHdl->execute(); - leftTableHdl->fetch(); + //PRABA::TEMP: + //if( jType != LEFT_JOIN) optimize(); + if (leftTableHdl->getName()) { + //printf("left execute call %s", leftTableHdl->getName()); + optimize(); + leftTableHdl->execute(); + leftTableHdl->fetch(); + }else if (isFirstCall) { + //printf("First call"); + optimize(); + leftTableHdl->execute(); + void *rec = leftTableHdl->fetch(); + //printf("rec value is %x\n", rec); + isFirstCall = false; + } rightTableHdl->execute(); - //TODO - //if join condition is not set then do nl - //if it is inner join, hen do nl - //nl cannot be done for outer join + TableImpl *tImpl = (TableImpl*) rightTableHdl; + isOuterJoin= true; + isFirstFetch = true; return OK; } - void* JoinTableImpl::fetch() { + //if (!leftTableHdl->getName()) printf("fetch called\n"); + if (isLeftRecOver) return NULL; + void * rec = fetchInt(); + //if (!leftTableHdl->getName()) printf("rec got %x\n", rec); + + if (rec == NULL && jType == LEFT_JOIN && isFirstFetch) + { + isFirstFetch= false; + isReturnNull = true; + copyValuesToBindBuffer(NULL); + //if (!leftTableHdl->getName()) printf("rec value is 0x1\n"); + return (void*)0x1; + } + isReturnNull = false; + //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec); + return rec; +} +void* JoinTableImpl::fetchInt() +{ PredicateImpl* predImpl = (PredicateImpl*) pred; DbRetVal rv = OK; if (isNestedLoop) @@ -235,47 +271,82 @@ void* JoinTableImpl::fetch() void *rec = rightTableHdl->fetch(); if (rec==NULL) { - rightTableHdl->closeScan(); - rec = leftTableHdl->fetch(); - if (rec == NULL) return NULL; - rightTableHdl->execute(); - rec = rightTableHdl->fetch(); - if (rec == NULL) return NULL; - bool result = true; - while (true) { - if (pred) rv = predImpl->evaluate(result); - if ( OK != rv) return NULL; - if (result) break; - rec = rightTableHdl->fetch(); - if (rec == NULL) return fetch(); - } - copyValuesToBindBuffer(NULL); - return rec; + return fetchRightFail(); } else { + if (jType == LEFT_JOIN && leftSideFail + && !leftTableHdl->getName() + && !isFirstFetch) return fetchRightFail(); + bool result = true; while (true) { if (pred) rv = predImpl->evaluate(result); if ( rv !=OK) return NULL; if (result) break; rec = rightTableHdl->fetch(); - if (rec == NULL) return fetch(); + if (rec == NULL) { + if (jType == LEFT_JOIN && isFirstFetch) return NULL; + return fetchInt(); + } } copyValuesToBindBuffer(NULL); + isFirstFetch = false; return rec; } - } return NULL; } + +void* JoinTableImpl::fetchRightFail() +{ + if (jType == LEFT_JOIN && isFirstFetch) { return NULL;} + //if (!leftTableHdl->getName()) printf("fetch right fail called\n"); + PredicateImpl* predImpl = (PredicateImpl*) pred; + DbRetVal rv = OK; + rightTableHdl->closeScan(); + void *rec = leftTableHdl->fetch(); + //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec); + leftSideFail= false; + if (rec == NULL) {isLeftRecOver= true; return NULL;} + else if (rec == (char*)0x1) { leftSideFail = true;} + rightTableHdl->execute(); + isFirstFetch = true; + rec = rightTableHdl->fetch(); + if (rec == NULL || leftSideFail) { + //if(!leftTableHdl->getName()) printf("RIGHT FETCH returns NULL\n"); + //if join condition(pred) is set and if it is pushed to tablehdl + //when there is index, it returns no record + if (jType == LEFT_JOIN && pred) return NULL; + return fetchRightFail(); + } + bool result = true; + isReturnNull = false; + while (true) { + if (pred) rv = predImpl->evaluate(result); + if ( OK != rv) return NULL; + if (result) { break; } + rec = rightTableHdl->fetch(); + if (rec == NULL) { + if (jType == LEFT_JOIN) { + //return from here so that null values for rhs table will be set + return (void*) NULL; + } + return fetchInt(); + } + } + isFirstFetch = false; + copyValuesToBindBuffer(NULL); + return rec; +} void* JoinTableImpl::fetch(DbRetVal &rv) { rv = OK; - return fetch(); + return fetchInt(); } void* JoinTableImpl::fetchNoBind() { + printError(ErrBadCall, "fetchNoBind not implemented for JoinTableImpl"); return NULL; } @@ -301,20 +372,21 @@ DbRetVal JoinTableImpl::copyValuesToBindBuffer(void *elem) } DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info) { - DbRetVal retCode = OK; + DbRetVal retCode = OK, retCode1 =OK; + availableLeft = false; retCode = leftTableHdl->getFieldInfo(fldname, info); if (retCode ==OK) { availableLeft= true; - return OK; + //return OK; } - retCode = rightTableHdl->getFieldInfo(fldname, info); - if (retCode ==OK) + retCode1 = rightTableHdl->getFieldInfo(fldname, info); + if (retCode1 ==OK) { - availableLeft= false; + if (availableLeft) return ErrSyntaxError; return OK; } - return ErrNotExists; + return retCode; } long JoinTableImpl::numTuples() @@ -323,17 +395,20 @@ long JoinTableImpl::numTuples() } DbRetVal JoinTableImpl::closeScan() { + //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan(); if (leftTableHdl) leftTableHdl->closeScan(); if (rightTableHdl) rightTableHdl->closeScan(); + isLeftRecOver = false; + isFirstCall = true; return OK; } DbRetVal JoinTableImpl::close() { + closeScan(); if (leftTableHdl) { leftTableHdl->close(); leftTableHdl = NULL; } if (rightTableHdl) { rightTableHdl->close(); rightTableHdl = NULL; } - closeScan(); ListIterator iter = projList.getIterator(); JoinProjFieldInfo *elem; while (iter.hasElement()) @@ -343,14 +418,22 @@ DbRetVal JoinTableImpl::close() delete elem; } projList.reset(); - delete pred; + //delete pred; + ListIterator pIter = predList.getIterator(); + while(pIter.hasElement()) + { + PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement(); + delete pImpl; + } + predList.reset(); delete this; return OK; } void* JoinTableImpl::getBindFldAddr(const char *name) { - printf("PRABA::join getBindFldAddr not implemented\n"); - return NULL; + void* bindAddr = leftTableHdl->getBindFldAddr(name); + if (bindAddr) return bindAddr; + return rightTableHdl->getBindFldAddr(name); } List JoinTableImpl::getFieldNameList() { @@ -438,19 +521,19 @@ bool JoinTableImpl::pushPredicate(Predicate *pr) if (strcmp(rTbl, rTabName) ==0) { //bool ind = rightTableHdl->hasIndex(rFldName); - //if (ind) { + if (OpEquals ==op) { void *buf = getBindedBuf(lTabName, lFldName); rightTableHdl->addPredicate(rFldName, op, buf); pImpl->setDontEvaluate(); - //} + } }else if (strcmp(rTbl, lTabName) ==0) { //bool ind = rightTableHdl->hasIndex(lFldName); - //if (ind) { + if (OpEquals ==op) { void *buf = getBindedBuf(rTabName, rFldName); rightTableHdl->addPredicate(lFldName, op, buf); pImpl->setDontEvaluate(); - //} + } } //PRABA::END setPredicate(pr); @@ -466,19 +549,19 @@ bool JoinTableImpl::pushPredicate(Predicate *pr) if (strcmp(rTbl, rTabName) ==0) { //bool ind = rightTableHdl->hasIndex(rFldName); - //if (ind) { + if (OpEquals ==op) { void *buf = getBindedBuf(lTabName, lFldName); rightTableHdl->addPredicate(rFldName, op, buf); pImpl->setDontEvaluate(); - //} + } }else if (strcmp(rTbl, lTabName) ==0) { //bool ind = rightTableHdl->hasIndex(lFldName); - //if (ind) { + if (OpEquals ==op) { void *buf = getBindedBuf(rTabName, rFldName); rightTableHdl->addPredicate(lFldName, op, buf); pImpl->setDontEvaluate(); - //} + } } //PRABA::END setPredicate(pr); @@ -495,6 +578,7 @@ void JoinTableImpl::setPredicate(Predicate *pr) PredicateImpl *newPred = new PredicateImpl(); newPred->setTerm(curPred, OpAnd, pr); newPred->setProjectionList(&projList); + predList.append(newPred); pred = newPred; return; } @@ -517,6 +601,7 @@ bool JoinTableImpl::isFldNull(const char *name) } if(NULL==rightTableHdl->getName()) { + if (isReturnNull) return true; ret = rightTableHdl->isFldNull(name); if(ret==true) return true; } @@ -525,8 +610,44 @@ bool JoinTableImpl::isFldNull(const char *name) Table::getTableNameAlone((char*)name, tableName); if(0==strcmp(tableName,rightTableHdl->getName())) { + if (isReturnNull) return true; return rightTableHdl->isFldNull(name); } } return ret; } +//same as above expect it does not check for isRecordFound flag +//as it is set only after predicate evaluate +bool JoinTableImpl::isFldNullInt(const char *name) +{ + bool ret = false; + if(NULL==leftTableHdl->getName()) + { + ret = leftTableHdl->isFldNull(name); + if(ret==true) return true; + } + else + { + char tableName[IDENTIFIER_LENGTH]; + Table::getTableNameAlone((char*)name, tableName); + if(0 == strcmp(tableName,leftTableHdl->getName())) + { + return leftTableHdl->isFldNull(name); + } + } + if(NULL==rightTableHdl->getName()) + { + ret = rightTableHdl->isFldNull(name); + if(ret==true) return true; + } + else{ + char tableName[IDENTIFIER_LENGTH]; + Table::getTableNameAlone((char*)name, tableName); + if(0==strcmp(tableName,rightTableHdl->getName())) + { + return rightTableHdl->isFldNull(name); + } + } + return ret; +} + diff --git a/src/storage/LockManager.cxx b/src/storage/LockManager.cxx index 50350336..01796457 100644 --- a/src/storage/LockManager.cxx +++ b/src/storage/LockManager.cxx @@ -131,13 +131,6 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) //to acquire lock so for sure we will get it. printDebug(DM_Lock, "LockManager::getSharedLock Begin"); Bucket *bucket = getLockBucket(tuple); - int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); - if (lockRet != 0) - { - printDebug(DM_Lock, "LockManager::getSharedLock:End-Unable to get mutex"); - printError(ErrLockTimeOut,"Unable to acquire bucket mutex"); - return ErrLockTimeOut; - } LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_; if (NULL == lockNode) { @@ -147,14 +140,25 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) { printError(rv, "Could not allocate Lock node"); return rv; - } + } printDebug(DM_Lock, "Bucket list is null: Allocating new LockHashNode %x", node); - bucket->bucketList_ = (void*)node; //make it as head - bucket->mutex_.releaseLock(systemDatabase_->procSlot); rv = OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, node); - if (rv !=OK) linfo.noOfReaders_--; + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, node); + if (rv !=OK) { + deallocLockNode(node); + printError(ErrLockTimeOut,"Unable to insert into hasList. Timeout.Retry..."); + return ErrLockTimeOut; + } + + //bucket->bucketList_ = (void*)node; //make it as head + int ret = Mutex::CASL((long*)&bucket->bucketList_, 0 , (long)node); + if (ret != 0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + printError(ErrLockTimeOut, "Unable to set lock list head. Timeout. Retry..."); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "LockManager::getSharedLock End"); return rv; } @@ -169,9 +173,16 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) if (iter->lInfo_.noOfReaders_ == -1) { - iter->lInfo_.waitReaders_++; - cachedLockNode = iter; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //iter->lInfo_.waitReaders_++; + int ret = Mutex::CAS((int*)&iter->lInfo_.waitReaders_, + iter->lInfo_.waitReaders_, + iter->lInfo_.waitReaders_+1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to inc waitReaders:%d : Timeout. Retry..", iter->lInfo_.waitReaders_); + return ErrLockTimeOut; + } + cachedLockNode = iter; + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->updateWaitLock(iter); printDebug(DM_Lock, "lock node:%x exclusive locked",iter); break; @@ -180,21 +191,38 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) { if(iter->lInfo_.waitWriters_ >0) { - iter->lInfo_.waitReaders_++; + //iter->lInfo_.waitReaders_++; + int ret = Mutex::CAS((int*)&iter->lInfo_.waitReaders_, + iter->lInfo_.waitReaders_, + iter->lInfo_.waitReaders_+1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to inc waitReaders:%d : Timeout. Retry..", iter->lInfo_.waitReaders_); + return ErrLockTimeOut; + } cachedLockNode = iter; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->updateWaitLock(iter); printDebug(DM_Lock, "lock node:%x Writers waiting.",iter); break; } else { - iter->lInfo_.noOfReaders_++; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv = OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, iter); - if (rv != OK) iter->lInfo_.noOfReaders_--; + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, iter); + if (rv != OK) { + printError(ErrLockTimeOut,"Unable to insert into hasList. Timeout. Retry.."); + return ErrLockTimeOut; + } + //iter->lInfo_.noOfReaders_++; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, + iter->lInfo_.noOfReaders_, + iter->lInfo_.noOfReaders_+1); + if (ret !=0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + printError(ErrLockTimeOut, "Unable to inc noOfReaders:%d : Timeout. Retry..", iter->lInfo_.noOfReaders_); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "lock node:%x First to take shared lock", iter); printDebug(DM_Lock, "LockManager::getSharedLock End"); @@ -202,12 +230,22 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) } }else { - iter->lInfo_.noOfReaders_++; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv = OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, iter); - if (rv != OK) iter->lInfo_.noOfReaders_--; + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, iter); + if (rv != OK) { + printError(ErrLockTimeOut, "Unable to insert into hasList. Timeout : Retry.."); + return ErrLockTimeOut; + } + //iter->lInfo_.noOfReaders_++; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, + iter->lInfo_.noOfReaders_, + iter->lInfo_.noOfReaders_+1); + if (ret !=0) { + if (trans!=NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + printError(ErrLockTimeOut, "Unable to take S lock. Timeout : Retry.."); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "lock node:%x incr readers",iter); printDebug(DM_Lock, "LockManager::getSharedLock End"); return rv; @@ -222,23 +260,60 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) LockHashNode *node = allocLockNode(linfo, tuple, &rv); if (NULL == node) { - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printError(rv, "Could not allocate Lock node"); if (trans != NULL) (*trans)->removeWaitLock(); return rv; } printDebug(DM_Lock,"Not Found.Created new lock node:%x",node); - LockHashNode *it = lockNode; - while (NULL != it->next_) it = it->next_; - it->next_ = node; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); rv = OK; if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, node); - if (rv != OK) linfo.noOfReaders_--; + if (rv != OK) { + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to add to hasList : Timeout. Retry.."); + return ErrLockTimeOut; + } + int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + if (lockRet != 0) + { + printError(ErrLockTimeOut, "Unable to acquire bucket mutex"); + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + return ErrLockTimeOut; + } + + LockHashNode *it = (LockHashNode*) bucket->bucketList_; + + if (NULL == it) { + int ret = Mutex::CASL((long*)&bucket->bucketList_, 0 , (long)node); + if (ret != 0) { + bucket->mutex_.releaseLock(systemDatabase_->procSlot); + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to set Lock Bucket. Timeout: retry..."); + return ErrLockTimeOut; + } + } else { + while (NULL != it->next_) it = it->next_; + //it->next_ = node; + int ret = Mutex::CASL((long*)&it->next_, 0, (long)node); + if (ret !=0) { + bucket->mutex_.releaseLock(systemDatabase_->procSlot); + if (trans !=NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to add to lock table list : Retry.."); + return ErrLockTimeOut; + } + } + bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getSharedLock End"); - return rv; + return OK; } //bucket->mutex_.releaseLock(); int tries = 0; @@ -250,7 +325,7 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) //printDebug(DM_Lock, "Trying to get mutex: for bucket %x\n", bucket); while (tries < Conf::config.getLockRetries()) { - lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + /*lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); if (lockRet != 0) { printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock"); @@ -258,24 +333,39 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) printError(ErrLockTimeOut, "Unable to get bucket mutex"); if (trans != NULL) (*trans)->removeWaitLock(); return ErrLockTimeOut; - } + }*/ + int oldValue = cachedLockNode->lInfo_.noOfReaders_; if (cachedLockNode->lInfo_.noOfReaders_ == 0) { //if there are waiters allow then to take the lock if (cachedLockNode->lInfo_.waitWriters_ <0) { - cachedLockNode->lInfo_.noOfReaders_++; - cachedLockNode->lInfo_.waitReaders_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv = OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); + if (trans != NULL) rv=(*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); if (rv !=OK) { - cachedLockNode->lInfo_.noOfReaders_--; - cachedLockNode->lInfo_.waitReaders_++; if (trans != NULL) (*trans)->removeWaitLock(); - return rv; + printError(ErrLockTimeOut, "Unable to add to hasList. TimeOut : Retry.."); + return ErrLockTimeOut; + + } + //cachedLockNode->lInfo_.noOfReaders_++; + int ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.noOfReaders_, + 0,cachedLockNode->lInfo_.noOfReaders_+1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to take S lock. TimeOut : Retry.."); + if (trans != NULL) (*trans)->removeWaitLock(); + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + return ErrLockTimeOut; } + //cachedLockNode->lInfo_.waitReaders_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitReaders_, + cachedLockNode->lInfo_.waitReaders_, + cachedLockNode->lInfo_.waitReaders_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitReaders. Timeout : Retry.."); + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getSharedLock End"); return OK; @@ -284,29 +374,44 @@ DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans) { if (trans !=NULL && (*trans)->findInHasList(systemDatabase_, cachedLockNode)) { - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getSharedLock End"); return OK; } } else { - cachedLockNode->lInfo_.noOfReaders_++; - cachedLockNode->lInfo_.waitReaders_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv =OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); if (rv !=OK) { - cachedLockNode->lInfo_.noOfReaders_--; - cachedLockNode->lInfo_.waitReaders_++; + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to add to hasList. Timeout : Retry.."); + return ErrLockTimeOut; + } + //cachedLockNode->lInfo_.noOfReaders_++; + int ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.noOfReaders_, + oldValue, oldValue+1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to take S lock. Timeout : Retry.."); + if (trans != NULL) (*trans)->removeWaitLock(); + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + return ErrLockTimeOut; + } + //cachedLockNode->lInfo_.waitReaders_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitReaders_, + cachedLockNode->lInfo_.waitReaders_, + cachedLockNode->lInfo_.waitReaders_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to dec waitReaders timeout : Retry.."); + //return ErrLockTimeOut; } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getSharedLock End"); - return rv; + return OK; } - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); os::select(0, 0, 0, 0, &timeout); tries++; printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",cachedLockNode, tries); @@ -329,32 +434,38 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) //to acquire lock so for sure we will get it. Bucket *bucket = getLockBucket(tuple); - int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + /*int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); if (lockRet != 0) { printDebug(DM_Lock, "Unable to acquire bucket mutex:May be deadlock"); printError(ErrLockTimeOut, "Unable to acquire bucket mutex"); return ErrLockTimeOut; - } + }*/ LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_; if (NULL == lockNode) { DbRetVal rv = OK; LockHashNode *node = allocLockNode(linfo, tuple, &rv); - if (NULL == node) - { - printError(rv, "Could not allocate Lock node"); - return rv; + if (NULL == node) return rv; + rv =OK; + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, node); + if (rv !=OK) { + printError(ErrLockTimeOut, "Unable to add to hasList. Timeout: retry..."); + deallocLockNode(node); + return ErrLockTimeOut; } printDebug(DM_Lock, "No head. So new lock node allocated:%x",node); - bucket->bucketList_ = (void*)node; //make it as head - bucket->mutex_.releaseLock(systemDatabase_->procSlot); - rv =OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, node); - if (rv !=OK) linfo.noOfReaders_ = 0; + //bucket->bucketList_ = (void*)node; //make it as head + int ret = Mutex::CASL((long*)&bucket->bucketList_, 0 , (long)node); + if (ret != 0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + printError(ErrLockTimeOut, "Unable to set Lock Bucket. Timeout: retry...%x", tuple); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); - return rv; + return OK; } LockHashNode *cachedLockNode = NULL; @@ -367,8 +478,16 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) { if (iter->lInfo_.noOfReaders_ != 0) { - iter->lInfo_.waitWriters_++; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //iter->lInfo_.waitWriters_++; + int ret = Mutex::CAS((int*)&iter->lInfo_.waitWriters_, + iter->lInfo_.waitWriters_, + iter->lInfo_.waitWriters_+1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to inc waitWriters. Timeout : Retry.."); + return ErrLockTimeOut; + } + + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->updateWaitLock(iter); cachedLockNode = iter; printDebug(DM_Lock, "Either some one has exclusive or shared lock:%x",iter); @@ -376,12 +495,20 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) } else { - iter->lInfo_.noOfReaders_ = -1; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv =OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, iter); - if (rv != OK) iter->lInfo_.noOfReaders_ = 0; + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, iter); + if (rv != OK) { + printError(ErrLockTimeOut, "Unable to add to hasList. Timeout : Retry.."); + return ErrLockTimeOut; + } + //iter->lInfo_.noOfReaders_ = -1; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, 0, -1); + if (ret !=0) { + if (trans!= NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + printError(ErrLockTimeOut, "Unable to take X lock on tuple. Timeout : Retry.."); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return rv; } @@ -395,21 +522,56 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) LockHashNode *node = allocLockNode(linfo, tuple, &rv); if (NULL == node) { - bucket->mutex_.releaseLock(systemDatabase_->procSlot); - if (trans != NULL) (*trans)->updateWaitLock(NULL); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); + if (trans != NULL) (*trans)->removeWaitLock(); printError(rv, "Could not allocate Lock node"); return rv; } printDebug(DM_Lock, "Not Found:Creating new lock node:%x",node); - LockHashNode *it = lockNode; - while (NULL != it->next_) it = it->next_; - it->next_ = node; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); rv = OK; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, node); - if (rv != OK) linfo.noOfReaders_ = 0; - if (trans != NULL) (*trans)->removeWaitLock(); + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, node); + if (rv != OK) { + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to add to hasList. Timeout : Retry.."); + return ErrLockTimeOut; + } + int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + if (lockRet != 0) + { + printError(ErrLockTimeOut, "Unable to acquire bucket mutex"); + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + return ErrLockTimeOut; + } + LockHashNode *it = (LockHashNode*) bucket->bucketList_; + if (NULL == it) { + int ret = Mutex::CASL((long*)&bucket->bucketList_, 0 , (long)node); + if (ret != 0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to set Lock Bucket. Timeout: retry..."); + return ErrLockTimeOut; + } + + + } else { + while (NULL != it->next_) it = it->next_; + //it->next_ = node; + int ret = Mutex::CASL((long*)&it->next_, 0, (long)node); + if (ret !=0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + deallocLockNode(node); + if (trans != NULL) (*trans)->removeWaitLock(); + bucket->mutex_.releaseLock(systemDatabase_->procSlot); + printError(ErrLockTimeOut, "Unable to add to lock list. Timeout : Retry.."); + return ErrLockTimeOut; + } + } + bucket->mutex_.releaseLock(systemDatabase_->procSlot); + if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return rv; } @@ -422,20 +584,42 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) while (tries < Conf::config.getLockRetries()) { - lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + /*lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); if (lockRet != 0) { printError(ErrLockTimeOut, "Unable to get bucket mutex"); return ErrLockTimeOut; - } + }*/ + int oldValue = cachedLockNode->lInfo_.noOfReaders_; if (cachedLockNode->lInfo_.noOfReaders_ == 0) { - cachedLockNode->lInfo_.noOfReaders_ = -1; - cachedLockNode->lInfo_.waitWriters_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); DbRetVal rv ; - if (trans != NULL) - rv = (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); + if (trans != NULL) rv = (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode); + if (rv != OK) { + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to add to hasList: Timeout: Retry.."); + return ErrLockTimeOut; + } + //cachedLockNode->lInfo_.noOfReaders_ = -1; + int ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.noOfReaders_, + 0, -1); + if (ret !=0) { + if (trans != NULL) (*trans)->removeFromHasList(systemDatabase_, tuple); + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to take X lock: Timeout: Retry.."); + return ErrLockTimeOut; + } + + //cachedLockNode->lInfo_.waitWriters_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitWriters. TimeOut : Retry.. waitWriters:%d",cachedLockNode->lInfo_.waitWriters_); + //do not do error return as this is OK to continue. + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return rv; @@ -446,9 +630,25 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) printDebug(DM_Lock, "upgrading shared to exclusive lock:%x", cachedLockNode); //upgrade it to exclusive lock - cachedLockNode->lInfo_.noOfReaders_ = -1; - cachedLockNode->lInfo_.waitWriters_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //cachedLockNode->lInfo_.noOfReaders_ = -1; + int ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.noOfReaders_, + 1, -1); + if (ret !=0) { + if (trans != NULL) (*trans)->removeWaitLock(); + printError(ErrLockTimeOut, "Unable to upgrade lock. Timeout : Retry.."); + return ErrLockTimeOut; + } + + //cachedLockNode->lInfo_.waitWriters_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitWriters:Timeout : Retry.. waitwriters:%d", cachedLockNode->lInfo_.waitWriters_); + //do not do error return as this is OK to contine + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return OK; @@ -458,9 +658,25 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) printDebug(DM_Lock, "upgrading shared to exclusive lock:%x", cachedLockNode); //upgrade it to exclusive lock - cachedLockNode->lInfo_.noOfReaders_ = -1; - cachedLockNode->lInfo_.waitWriters_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //cachedLockNode->lInfo_.noOfReaders_ = -1; + int ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.noOfReaders_, + 1, -1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to upgrade lock. Timeout : Retry.."); + if (trans != NULL) (*trans)->removeWaitLock(); + return ErrLockTimeOut; + } + + //cachedLockNode->lInfo_.waitWriters_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitWriters:Timeout : Retry.. waitwriters:%d", cachedLockNode->lInfo_.waitWriters_); + //do not do error return as this is OK to contine + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return OK; @@ -471,8 +687,16 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) { printDebug(DM_Lock, "You already have exclusive lock:%x", cachedLockNode); - cachedLockNode->lInfo_.waitWriters_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //cachedLockNode->lInfo_.waitWriters_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitWriters:Timeout : Retry.. waitwriters:%d", cachedLockNode->lInfo_.waitWriters_); + //do not do error return as this is OK to contine + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return OK; @@ -481,14 +705,22 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) { printDebug(DM_Lock, "You already have exclusive lock:%x", cachedLockNode); - cachedLockNode->lInfo_.waitWriters_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //cachedLockNode->lInfo_.waitWriters_--; + ret = Mutex::CAS((int*)&cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_, + cachedLockNode->lInfo_.waitWriters_-1); + if (ret !=0) { + printError(ErrLockTimeOut, "Fatal:Unable to dec waitWriters:Timeout : Retry.. waitwriters:%d", cachedLockNode->lInfo_.waitWriters_); + //do not do error return as this is OK to contine + //return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); if (trans != NULL) (*trans)->removeWaitLock(); printDebug(DM_Lock, "LockManager::getExclusiveLock End"); return OK; } } - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); os::select(0, 0, 0, 0, &timeout); tries++; printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",cachedLockNode, tries); @@ -501,53 +733,69 @@ DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans) DbRetVal LockManager::releaseLock(void *tuple) { - LockInfo linfo; - linfo.noOfReaders_ = 0; - //keeping it ready for the allocation, because when - //lock node is not present in the list, then it means we are the first - //to acquire lock so for sure we will get it. printDebug(DM_Lock, "LockManager:releaseLock Start"); Bucket *bucket = getLockBucket(tuple); printDebug(DM_Lock,"Bucket is %x", bucket); - int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + /*int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); if (lockRet != 0) { printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock"); printDebug(DM_Lock, "LockManager:releaseLock End"); printError(ErrLockTimeOut, "Unable to get bucket mutex"); return ErrLockTimeOut; - } + }*/ LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_; if (NULL == lockNode) { - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "LockManager:releaseLock End"); - printError(ErrSysFatal, "Lock Element Not found: Probable Data Corruption.\n"); + //printError(ErrSysFatal, "Fatal:Lock Bucket and Element Not found for tuple: %x:", tuple); + printStackTrace(); + printError(ErrSysFatal, "Fatal:Lock Bucket and Element Not found for tuple: %x:%d", tuple, *(int*)tuple); return ErrSysFatal; } - + DbRetVal rv = OK; LockHashNode *iter = lockNode; //Iterate though the list and find the element's lock info while(iter != NULL) { if(iter->ptrToTuple_ == tuple) { - + int oldValue = iter->lInfo_.noOfReaders_; if (iter->lInfo_.noOfReaders_ == -1) { - iter->lInfo_.noOfReaders_ = 0; + //iter->lInfo_.noOfReaders_ = 0; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, + -1, 0); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to release X lock taken : Retry.."); + return ErrLockTimeOut; + } + if (iter->lInfo_.waitWriters_ == 0 || iter->lInfo_.waitReaders_ ==0) { - deallocLockNode(iter, bucket); - bucket->mutex_.releaseLock(systemDatabase_->procSlot); - printDebug(DM_Lock, "Releasing exclusive lock and dealloc node:%x", - iter); - printDebug(DM_Lock, "LockManager:releaseLock End"); - return OK; + //TODO::above condition is not atomic + //put waitReaders_, WaitReaders in one integer + int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + if (lockRet == 0) { + int tries = Conf::config.getMutexRetries(); + do { + rv = deallocLockNode(iter, bucket); + if (tries == 0) { + printError(ErrWarning, "Fatal:Leak: Unable to dealloc lock node %d tries", Conf::config.getMutexRetries()); + break; + } + tries--; + }while (rv == ErrLockTimeOut); + bucket->mutex_.releaseLock(systemDatabase_->procSlot); + } + printDebug(DM_Lock, "Releasing exclusive lock and dealloc node:%x", iter); + printDebug(DM_Lock, "LockManager:releaseLock End"); + return OK; } else { - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "Releasing exclusive lock"); printDebug(DM_Lock, "LockManager:releaseLock End"); return OK; @@ -555,20 +803,50 @@ DbRetVal LockManager::releaseLock(void *tuple) } else if (iter->lInfo_.noOfReaders_ == 1) { - iter->lInfo_.noOfReaders_ = 0; + //iter->lInfo_.noOfReaders_ = 0; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, + 1, 0); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to release S lock taken. Timeout : Retry.."); + return ErrLockTimeOut; + } if (iter->lInfo_.waitWriters_ == 0 || iter->lInfo_.waitReaders_ ==0) { - deallocLockNode(iter, bucket); + int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + if (lockRet == 0) { + int tries = Conf::config.getMutexRetries(); + do { + rv = deallocLockNode(iter, bucket); + if (tries == 0) { + printError(ErrWarning, "Fatal:Leak:Unable to dealloc lock node"); + } + tries--; + }while (rv == ErrLockTimeOut); bucket->mutex_.releaseLock(systemDatabase_->procSlot); - printDebug(DM_Lock, "Releasing read lock and dealloc node:%x",iter); + } + printDebug(DM_Lock, "Releasing read lock and dealloc node:%x",iter); + printDebug(DM_Lock, "LockManager:releaseLock End"); + return OK; + } + else + { + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); + printDebug(DM_Lock, "Releasing read lock"); printDebug(DM_Lock, "LockManager:releaseLock End"); return OK; } } else { - iter->lInfo_.noOfReaders_--; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //iter->lInfo_.noOfReaders_--; + int ret = Mutex::CAS((int*)&iter->lInfo_.noOfReaders_, + oldValue, + oldValue - 1); + if (ret !=0) { + printError(ErrLockTimeOut, "Unable to release S lock taken : Retry.."); + return ErrLockTimeOut; + } + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); printDebug(DM_Lock, "Decrementing read lock:%x",iter); printDebug(DM_Lock, "LockManager:releaseLock End"); return OK; @@ -578,8 +856,8 @@ DbRetVal LockManager::releaseLock(void *tuple) printDebug(DM_Lock, "Finding the lock node. iter:%x",iter); iter = iter->next_; } - bucket->mutex_.releaseLock(systemDatabase_->procSlot); - printError(ErrSysFatal, "Lock Element Not found: Probable Data Corruption"); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); + printError(ErrSysFatal, "Fatal:Lock Element Not found for tuple:%x", tuple); return ErrSysFatal; } @@ -594,14 +872,14 @@ DbRetVal LockManager::isExclusiveLocked(void *tuple, Transaction **trans, bool & status = false; return OK; } - int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); + /*int lockRet = bucket->mutex_.getLock(systemDatabase_->procSlot); if (lockRet != 0) { printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock"); printDebug(DM_Lock, "LockManager:releaseLock End"); printError(ErrLockTimeOut, "Unable to get bucket mutex"); return ErrLockTimeOut; - } + }*/ LockHashNode *iter = lockNode; //Iterate though the list and find the element's lock info @@ -619,14 +897,18 @@ DbRetVal LockManager::isExclusiveLocked(void *tuple, Transaction **trans, bool & } else status = true; - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); return OK; } } printDebug(DM_Lock, "Finding the lock node. iter:%x",iter); + if (iter == iter->next_) { + printError(ErrSysFatal, "Fatal:Unable to find lock node. cyclic list found"); + return ErrSysFatal; + } iter = iter->next_; } - bucket->mutex_.releaseLock(systemDatabase_->procSlot); + //bucket->mutex_.releaseLock(systemDatabase_->procSlot); status = false; return OK; } @@ -635,10 +917,24 @@ LockHashNode* LockManager::allocLockNode(LockInfo &info, void *tuple, DbRetVal * { //allocate lock node Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId); - LockHashNode *node = (LockHashNode*)chunk->allocate(systemDatabase_, rv); + LockHashNode *node = NULL; //(LockHashNode*)chunk->allocate(systemDatabase_, rv); + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) + { + *rv = OK; + node= (LockHashNode*)chunk->allocate(systemDatabase_, rv); + if (node !=NULL) break; + if (*rv != ErrLockTimeOut) + { + printError(*rv, "Unable to allocate hash index node"); + return NULL; + } + tries++; + } if (NULL == node) { - printError(*rv, "Could not allocate Lock node"); + printError(*rv, "Unable to allocate lock node after %d retry", tries); return NULL; } node->ptrToTuple_ = tuple; @@ -646,33 +942,55 @@ LockHashNode* LockManager::allocLockNode(LockInfo &info, void *tuple, DbRetVal * node->next_ = NULL; return node; } - -void LockManager::deallocLockNode(LockHashNode *node, Bucket *bucket) +void LockManager::deallocLockNode(LockHashNode *node) +{ + Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId); + chunk->free(systemDatabase_, node); + return; +} +DbRetVal LockManager::deallocLockNode(LockHashNode *node, Bucket *bucket) { Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId); LockHashNode *nodeList = (LockHashNode*) bucket->bucketList_; LockHashNode *iter = nodeList, *prev = nodeList; if (NULL == nodeList) { - printError(ErrSysFatal, "Lock Bucket corrupted"); - return; + printError(ErrSysFatal, "Fatal:Lock Bucket is NULL"); + return ErrSysFatal; } //If it is the first node, then make the bucket point to the next node //in the list if (nodeList == node) { - bucket->bucketList_ = node->next_; + //bucket->bucketList_ = node->next_; + if ( 0 != Mutex::CASL((long*)&bucket->bucketList_, (long)node, + (long)node->next_)) { + printError(ErrLockTimeOut, "Unable to remove lock node and set lock list head\n"); + return ErrLockTimeOut; + } chunk->free(systemDatabase_, node); - return; + return OK; } + void *val = NULL; while(iter != node) { + if (iter == NULL) { + printError(ErrSysFatal, "Fatal: Lock node not found in bucket"); + printStackTrace(); + return ErrSysFatal; + } prev = iter; + val = prev->next_; iter = iter->next_; } //delete the node by making previous element point to the next element //of the deleted element in the list - prev->next_ = iter->next_; + //prev->next_ = iter->next_; + if ( 0 != Mutex::CASL((long*)&prev->next_, (long)val, + (long)iter->next_)) { + printError(ErrLockTimeOut, "Unable to remove lock node \n"); + return ErrLockTimeOut; + } chunk->free(systemDatabase_, node); - return ; + return OK; } diff --git a/src/storage/Logger.cxx b/src/storage/Logger.cxx index 7e9b854d..901475b5 100644 --- a/src/storage/Logger.cxx +++ b/src/storage/Logger.cxx @@ -42,7 +42,7 @@ void Logger::rollOverIfRequired() int fileSize = os::getFileSize(fileName); char cmd[MAX_FILE_LEN]; int ret =0; - int tries=0, totalTries=3; + int tries=0, totalTries=Conf::config.getMutexRetries(); while (tries < totalTries) { ret = os::lockFile(fdLog); if (ret ==0) break; @@ -57,7 +57,11 @@ void Logger::rollOverIfRequired() if (fileSize > LOG_ROLLOVER_SIZE) { time_t cnow = ::time(NULL); +#ifdef SOLARIS + struct std::tm *tmval = localtime(&cnow); +#else struct tm *tmval = localtime(&cnow); +#endif sprintf(cmd, "cp %s %s.%d-%d-%d:%d:%d:%d", fileName, fileName, tmval->tm_year+1900, tmval->tm_mon+1, tmval->tm_mday, tmval->tm_hour, @@ -91,7 +95,7 @@ int Logger::log(LogLevel level, char* filename, } char *buffer = new char[MAX_TRACE_LOG_LENGTH]; createLogRecord(level, filename, lineNo, mesgBuf, &buffer); - int tries=0, totalTries=3; + int tries=0, totalTries=Conf::config.getMutexRetries(); while (tries < totalTries) { ret = os::lockFile(fdLog); if (ret ==0) break; @@ -127,7 +131,11 @@ DbRetVal Logger::startLogger(char *filename, bool isCreate) if (::access(filename, F_OK) == 0 ) { //move the existing log file with timestamp and create new file time_t cnow = ::time(NULL); +#ifdef SOLARIS + struct std::tm *tmval = localtime(&cnow); +#else struct tm *tmval = localtime(&cnow); +#endif sprintf(cmd, "cp %s %s.%d-%d-%d:%d:%d:%d", filename, filename, tmval->tm_year+1900, tmval->tm_mon+1, tmval->tm_mday, tmval->tm_hour, diff --git a/src/storage/Makefile.am b/src/storage/Makefile.am index 67a547c9..84985c6d 100644 --- a/src/storage/Makefile.am +++ b/src/storage/Makefile.am @@ -1,9 +1,11 @@ INCLUDES = -I$(top_srcdir)/include $(all_includes) METASOURCES = AUTO lib_LTLIBRARIES = libcsql.la -libcsql_la_LDFLAGS = -avoid-version -module -libcsql_la_SOURCES = BucketIter.cxx TreeIter.cxx BucketList.cxx CatalogTables.cxx Chunk.cxx Util.cxx TableConfig.cxx\ +libcsql_la_LDFLAGS = -version-info 2:4:0 -module +libcsql_la_SOURCES = Util.cxx FixedHeapAllocator.cxx VarHeapAllocator.cxx Config.cxx HashMap.cxx \ + BucketIter.cxx TreeIter.cxx BucketList.cxx CatalogTables.cxx Chunk.cxx TableConfig.cxx\ ChunkIterator.cxx Condition.cxx Connection.cxx Database.cxx DatabaseManagerImpl.cxx DataType.cxx \ Debug.cxx FieldList.cxx Index.cxx LockListIter.cxx LockManager.cxx Logger.cxx Mutex.cxx os.cxx \ PageInfo.cxx PredicateImpl.cxx SessionImpl.cxx TableDef.cxx TableImpl.cxx Transaction.cxx \ - TransactionManager.cxx TupleIterator.cxx UserManagerImpl.cxx HashIndex.cxx TreeIndex.cxx Config.cxx Process.cxx AggTableImpl.cxx JoinTableImpl.cxx Expression.cxx + TransactionManager.cxx TupleIterator.cxx UserManagerImpl.cxx HashIndex.cxx TreeIndex.cxx \ + Process.cxx AggTableImpl.cxx JoinTableImpl.cxx Expression.cxx OrderTableImpl.cxx OrderByTree.cxx diff --git a/src/storage/Mutex.cxx b/src/storage/Mutex.cxx index 0bf31b05..7f616adf 100644 --- a/src/storage/Mutex.cxx +++ b/src/storage/Mutex.cxx @@ -21,7 +21,6 @@ #include Mutex::Mutex() { - noOfRead = -1; #if defined(sparc) || defined(i686) || defined (x86_64) lock =0; #else @@ -34,7 +33,6 @@ Mutex::Mutex() int Mutex::init() { - noOfRead = -1; #if defined(sparc) || defined(i686) || defined (x86_64) lock = 0; #else @@ -115,13 +113,71 @@ int TSL(Lock *lock) #elif defined (SOLARIS) Lock res; - res = atomic_cas_32(lock, 0, 1); + res = atomic_cas_32((unsigned*)lock, 0, 1); return (res); #endif } #endif +int Mutex::tryShareLock(int tryTimes, int waitmsecs,bool share, bool isDelete) +{ + int ret=0; + int oldValue = (int)lock; + if (oldValue >= 0 && share){ + ret = CAS((int*)&lock, oldValue, oldValue+1); + }else if ((oldValue == 1 && isDelete ) || ( !share && oldValue == 0) ){ + ret = CAS((int*)&lock, oldValue, -1); + }else { ret = 1;} + if (0 == ret) return 0; + int tries = 1; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = waitmsecs; + if (tryTimes == 0 && waitmsecs == 0) + { + timeout.tv_sec = Conf::config.getMutexSecs(); + timeout.tv_usec = Conf::config.getMutexUSecs(); + tryTimes = Conf::config.getMutexRetries(); + } + int cnt=0; + while (tries < tryTimes) + { +#if defined(sparc) || defined(i686) || defined (x86_64) + if (Conf::config.getNoOfProcessors() >1) { + cnt=0; + while(true) { + oldValue = (int)lock; + if (oldValue >= 0 && share) { + ret = CAS((int*)&lock, oldValue, oldValue+1); + }else if ((oldValue == 1 && isDelete ) || (!share && oldValue == 0) ) { + ret = CAS((int*)&lock, oldValue, -1); + }else { ret = 1; } + + if(0 == ret ) return 0; + cnt++; + if (cnt == tryTimes * 100) break; + } + }else { + oldValue = (int)lock; + if (oldValue >= 0 && share) { + ret = CAS((int*)&lock, oldValue, oldValue+1); + }else if ((oldValue == 1 && isDelete ) || (!share && oldValue == 0) ){ + ret = CAS((int*)&lock, oldValue, -1); + } else { ret =1;} + if(ret==0) return 0; + } +#else + ret = pthread_mutex_trylock(&mutex_); + if (EBUSY != ret) return 0; -int Mutex::tryLock(int tryTimes, int waitmsecs,bool share) +#endif + os::select(0, 0, 0, 0, &timeout); + tries++; + } + printError(ErrLockTimeOut, "Unable to get the mutex %s, tried %d times", name,tries); + return 1; +} + +int Mutex::tryLock(int tryTimes, int waitmsecs) { if (TSL(&lock) == 0) { @@ -142,45 +198,39 @@ int Mutex::tryLock(int tryTimes, int waitmsecs,bool share) while (tries < tryTimes) { #if defined(sparc) || defined(i686) || defined (x86_64) - if (Conf::config.getNoOfProcessors() >1) { - cnt=0; - while(true) { + if (Conf::config.getNoOfProcessors() >1) { + cnt=0; + while(true) { if (TSL(&lock) == 0) { return 0; } cnt++; if (cnt == tryTimes * 100) break; - } - }else { - if (TSL(&lock) == 0) return 0; - } + } + }else { + if (TSL(&lock) == 0) return 0; + } #else - ret = pthread_mutex_trylock(&mutex_); - if (EBUSY != ret) return 0; + ret = pthread_mutex_trylock(&mutex_); + if (EBUSY != ret) return 0; #endif os::select(0, 0, 0, 0, &timeout); tries++; } - if(share && noOfRead != -1) { - noOfRead++; - return 2; - } - printError(ErrLockTimeOut, "Unable to get the mutex , tried %d times", tries); + printError(ErrLockTimeOut, "Unable to get the mutex %s, val:%d tried %d times", name, lock, tries); return 1; } - -int Mutex::getLock(int procSlot, bool procAccount,bool share) +int Mutex::getLock(int procSlot, bool procAccount) { int ret=0; #if defined(sparc) || defined(i686) || defined (x86_64) - ret = tryLock(0,0,share); + ret = tryLock(); //add it to the has_ of the ThreadInfo if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot); - if(share & noOfRead == -1 && ret == 0 ) noOfRead ++; - if(ret == 2) return 0; + return ret; #else ret = pthread_mutex_lock(&mutex_); @@ -190,9 +240,8 @@ int Mutex::getLock(int procSlot, bool procAccount,bool share) return 1; } -int Mutex::releaseLock(int procSlot, bool procAccount,bool share) +int Mutex::releaseLock(int procSlot, bool procAccount) { - if (noOfRead > 0 && share){ noOfRead--; return 0;} int ret=0; #if defined(sparc) || defined(i686) || defined (x86_64) /*int *lw = &lock; @@ -203,13 +252,92 @@ int Mutex::releaseLock(int procSlot, bool procAccount,bool share) "eax"); */ lock = 0; + //TEMP::PRABA:TODO::CHANGE IT TO CAS #else ret = pthread_mutex_unlock(&mutex_); #endif if (ret == 0 && procAccount) { ProcessManager::removeMutex(this, procSlot); - if( noOfRead == 0 && share) noOfRead--; + return ret; + } + else + return 1; +} + +int Mutex::getShareLock(int procSlot, bool procAccount) +{ + int ret=0; +#if defined(sparc) || defined(i686) || defined (x86_64) + ret = tryShareLock(0,0,true,false); + //add it to the has_ of the ThreadInfo + if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot); + return ret; +#else + ret = pthread_mutex_lock(&mutex_); +#endif + if (ret == 0) return 0; + else + return 1; +} + +int Mutex::getExclusiveLock(int procSlot, bool procAccount, bool isDelete) +{ + int ret=0; +#if defined(sparc) || defined(i686) || defined (x86_64) + ret = tryShareLock(0,0,false,isDelete); + //add it to the has_ of the ThreadInfo + if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot); + return ret; +#else + ret = pthread_mutex_lock(&mutex_); +#endif + if (ret == 0) return 0; + else + return 1; +} + +int Mutex::releaseShareLock(int procSlot, bool procAccount) +{ + int ret=0; +#if defined(sparc) || defined(i686) || defined (x86_64) + int oldValue = (int)lock; + if( oldValue > 1) + { + ret = CAS((int*)&lock, oldValue, oldValue-1 ); + } + if( oldValue == 1 || oldValue == -1 ) + { + ret = CAS((int*)&lock, oldValue, 0 ); + } + if( ret != 0) + { + int tries = 1; + struct timeval timeout; + timeout.tv_sec = Conf::config.getMutexSecs(); + timeout.tv_usec = Conf::config.getMutexUSecs(); + int tryTimes = Conf::config.getMutexRetries(); + while (tries < tryTimes) + { + oldValue = (int)lock; + if( oldValue > 1){ + ret = CAS((int*)&lock, oldValue, (*(int*)&lock)-1 ); + if(ret == 0) break; + } + if( oldValue == 1 || oldValue == -1 ) + { + ret = CAS((int*)&lock, oldValue, 0 ); + if(ret == 0) break; + } + tries++; + } + } +#else + ret = pthread_mutex_unlock(&mutex_); +#endif + if (ret == 0 && procAccount ) + { + ProcessManager::removeMutex(this, procSlot); return ret; } else @@ -246,7 +374,7 @@ int Mutex::recoverMutex() int Mutex::CASL(long *ptr, long oldVal, long newVal) { #ifdef SOLARIS -#ifdef x86_64 //or sparc64 +#if defined(__sparcv9) || defined(x86_64) || defined (__x86_64) unsigned long res = atomic_cas_64((unsigned long*)ptr, (unsigned long) oldVal, (unsigned long) newVal); if (res == oldVal) return 0; else return 1; diff --git a/src/storage/OrderByTree.cxx b/src/storage/OrderByTree.cxx new file mode 100644 index 00000000..cdbe9bc4 --- /dev/null +++ b/src/storage/OrderByTree.cxx @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2007 by www.databasecache.com * + * Contact: praba_tuty@databasecache.com * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * ***************************************************************************/ +#include + +//Used for float type field and individual order by clause +void OrderByTree::insertSpecialCaseDataNode(void *data) +{ + if(dataNode.size() == 0){ dataNode.append(data); return;} + ListIterator iter = dataNode.getIterator(); + ListIterator fldIter = orderByList.getIterator(); + iter.reset(); + int ret=0; + void *insertedData = NULL; + void *prevIter = iter.getCurrentListNode(); + void *prev = prevIter; + bool shouldInsertHappenAtMiddle=false; + OrderByFldDef *oFldDef = NULL; + int offset=0; + char *fldData=NULL, *fldInsertData=NULL; + bool result=false; + while (iter.hasElement()) + { + bool shoudInsertHere=false; + bool isPrevEqual=false; + offset=0; + insertedData = iter.nextElement(); + fldIter.reset(); + while (fldIter.hasElement()) + { + oFldDef = (OrderByFldDef*) fldIter.nextElement(); + fldData = ((char*)data)+offset; + fldInsertData = ((char*)insertedData)+offset; + offset += oFldDef->length; + result=AllDataType::compareVal(fldData, fldInsertData, OpEquals,oFldDef->type, oFldDef->length); + if(result) + { + shoudInsertHere = true; + isPrevEqual = true; + continue; + } + else + { + result=AllDataType::compareVal(fldData, fldInsertData, OpGreaterThan,oFldDef->type, oFldDef->length); + if(result) + { + if(oFldDef->isDesc) + { + shoudInsertHere = true; + isPrevEqual = false; + continue; + } + else{ + if(shoudInsertHere && !isPrevEqual) { isPrevEqual = false; continue;} + shoudInsertHere=false; break; + } + }else + { + //dataisDesc) + { + shoudInsertHere = true; + isPrevEqual = false; + continue; + } + else{ + if(shoudInsertHere && !isPrevEqual ) { isPrevEqual = false; continue;} + shoudInsertHere=false; break; + } + } + } + }//inner while ends here + if(shoudInsertHere){ + if(shouldInsertHappenAtMiddle) + dataNode.addAtMiddle(data, prevIter); + else + dataNode.addAtBegin(data); + return; + } + prevIter = prev; + prev = iter.getCurrentListNode(); + shouldInsertHappenAtMiddle=true; + } + dataNode.append(data); +} + +DbRetVal OrderByTree::insertDataNode(void *data) +{ + if(!fullOrderBy) { + insertSpecialCaseDataNode(data); + return OK; + } + dataNode.append(data); + projMap.insert(data); + return OK; +} +bool OrderByTree::find(void *data) +{ + void *element = projMap.find(data); + if (element) return true; + return false; +} +int OrderByTree::compare(void *element1,void *element2,int size) +{ + return os::memcmp(element1,element2,size); +} + +ListIterator OrderByTree::getListIterator() +{ + return dataNode.getIterator(); +} +void OrderByTree::removeAll() +{ + dataNode.reset(); + if(fullOrderBy) projMap.removeAll(); + return; +} diff --git a/src/storage/OrderTableImpl.cxx b/src/storage/OrderTableImpl.cxx new file mode 100644 index 00000000..245233ba --- /dev/null +++ b/src/storage/OrderTableImpl.cxx @@ -0,0 +1,452 @@ +/*************************************************************************** + * Copyright (C) 2007 by www.databasecache.com * + * Contact: praba_tuty@databasecache.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +OrderTableImpl::OrderTableImpl() +{ + tableHdl = NULL; + curTuple = NULL; + sortTree.setDistinct(false); + nullValues = 0; + orderBySize =0; + projSize =0; + orderBindBuf= NULL; + orderBuffer = NULL; + isPlanCreated=false; +} +OrderTableImpl::~OrderTableImpl() +{ + //free memory allocated. make sure that field buffers are freed only once. + //for stmts which has more than one agg on same field needs to be handled safely + closeScan(); + + ListIterator oiter = fldOrderByList.getIterator(); + OrderByFldDef *elem = NULL; + while (oiter.hasElement()) + { + elem = (OrderByFldDef*) oiter.nextElement(); + if(!elem->alreadyBinded) free(elem->bindBuf); + delete elem; + } + fldOrderByList.reset(); + + if (tableHdl != NULL) tableHdl->close(); + tableHdl = NULL; + if (orderBuffer) ::free(orderBuffer); +} +void *OrderTableImpl::getBindFldAddr(const char *name) +{ + printError(ErrBadCall, "OrderTableImpl getBindFldAdddr not implemented\n"); + return NULL; +} + +DbRetVal OrderTableImpl::bindFld(const char *name, void *val) +{ + printError(ErrBadCall, "OrderTableImpl bindFld not implemented\n"); + return ErrBadCall; +} +DbRetVal OrderTableImpl::setOrderBy(const char *fldname, bool isDesc) +{ + FieldInfo *info = new FieldInfo(); + DbRetVal rv = tableHdl->getFieldInfo(fldname, info); + if (OK !=rv) { delete info; return rv; } + OrderByFldDef *orderFld=new OrderByFldDef(); + strcpy(orderFld->fldName, fldname); + orderFld->type = info->type; + //orderFld->length = info->length; + orderFld->length = AllDataType::size(info->type, info->length); + orderFld->bindBuf = NULL; + orderFld->isDesc = isDesc; + + ListIterator iter = fldProjList.getIterator(); + FieldValue *elem; + + while (iter.hasElement()) + { + elem = (FieldValue*) iter.nextElement(); + if ((NULL != tableHdl->getName() && + NULL != strstr(elem->fldName, fldname) || + NULL != strstr(fldname, elem->fldName)) || + strcmp(elem->fldName, fldname)==0) + { + orderFld->bindBuf = elem->value; + orderFld->alreadyBinded = true; + break; + } + } + if (!orderFld->bindBuf) + { + orderFld->bindBuf = AllDataType::alloc(orderFld->type, orderFld->length); + rv = tableHdl->bindFld(fldname, orderFld->bindBuf); + if (rv != OK) { + delete info; + ::free(orderFld->bindBuf); + delete orderFld; + return rv; + } + } + + //if underlying tablehandle is TableImpl, then set isNull + orderFld->isNull = true; + if (info->isNull) orderFld->isNull = false; + if (info->isPrimary || info->isDefault || info->isAutoIncrement) { + orderFld->isNull = true; + } + if (NULL == tableHdl->getName()) orderFld->isNull=false; + + + fldOrderByList.append(orderFld); + delete info; + return OK; +} +OrderByType OrderTableImpl::getOrderType() +{ + ListIterator oiter = fldOrderByList.getIterator(); + OrderByFldDef *oFldDef = NULL; + bool isDescending = false; + bool firstIter = true; + while (oiter.hasElement()) + { + oFldDef = (OrderByFldDef*) oiter.nextElement(); + if(firstIter) { + firstIter= false; + isDescending = oFldDef->isDesc; + continue; + } + if (oFldDef->isDesc != isDescending) { isDescending = false; break; } + } + if(isDescending) return Desc; else return Asc; +} + +void OrderTableImpl::checkAndSetSortAlgorithm() +{ + if (sortTree.getDistinct()) sortTree.setFullOrderBy(); + sortTree.setOrderByList(fldOrderByList); + + //set orderby size + orderBySize = computeOrderBySize(); + sortTree.setKeySize(orderBySize + sizeof(int)); + + //set proj size + projSize = 0; + ListIterator iter = fldProjList.getIterator(); + FieldValue *fValue; + while (iter.hasElement()) + { + fValue = (FieldValue*) iter.nextElement(); + projSize = projSize + fValue->length; + } + OrderByFldDef *ordFld=NULL; + bool optGrpIntNoNull= false; + if (orderBySize == sizeof(int)) + { + ListIterator iter = fldOrderByList.getIterator(); + ordFld = (OrderByFldDef*)iter.nextElement(); + if (!ordFld->isNull && ordFld->type == typeInt) + { + optGrpIntNoNull=true; + orderBindBuf = ordFld->bindBuf; + sortTree.setOrdIntNoNull(); + } + } + return; +} +DbRetVal OrderTableImpl::execute() +{ + nullValues = 0; + tableHdl->execute(); + if (!isPlanCreated) { + checkAndSetSortAlgorithm(); + setNullableForProj(); + if (sortTree.getDistinct()) + { + orderBuffer = (char*)malloc(orderBySize + sizeof(int)); + } + isPlanCreated=true; + } + void *tuple = NULL; + while ((tuple = tableHdl->fetch()) != NULL) + { + if (sortTree.getDistinct()) insertDistinct(); else insert(); + } + sortIter = sortTree.getListIterator(); + return OK; +} +int OrderTableImpl::computeOrderBySize() +{ + ListIterator oiter = fldOrderByList.getIterator(); + OrderByFldDef *oFldDef = NULL; + int nodeOffset =0; + while (oiter.hasElement()) + { + oFldDef = (OrderByFldDef*) oiter.nextElement(); + nodeOffset = nodeOffset + oFldDef->length; + } + return nodeOffset; +} +DbRetVal OrderTableImpl::insertDistinct() +{ + char *elem = orderBuffer; + memset(orderBuffer, 0, orderBySize + sizeof(int)); + ListIterator oiter = fldOrderByList.getIterator(); + OrderByFldDef *oFldDef = NULL; + int orderNullValues =0; + int nodeOffset =0; + int i=0; + while ((oFldDef = (OrderByFldDef*) oiter.nextElement()) != NULL) + { + if (oFldDef->isNull && tableHdl->isFldNull(oFldDef->fldName)) + SETBIT(orderNullValues, i); + else + AllDataType::copyVal(elem+nodeOffset, oFldDef->bindBuf, + oFldDef->type, oFldDef->length); + nodeOffset = nodeOffset + oFldDef->length; + i++; + } + AllDataType::copyVal(elem+nodeOffset, &orderNullValues, typeInt, + sizeof(orderNullValues)); + if (sortTree.find(elem)) return OK; + nodeOffset = nodeOffset+ sizeof(orderNullValues); + + int nodeSize = orderBySize + projSize; + nodeSize = nodeSize + sizeof(int);//to store order by field null values + nodeSize = nodeSize + sizeof(nullValues);//to store proj field null values + char *element = (char*)malloc(nodeSize); + memcpy(element, elem, orderBySize + sizeof(int)); + nullValues = 0; + i=0; + ListIterator iter = fldProjList.getIterator(); + FieldValue *fValue = NULL; + void* ptrToCopyNullValues = element+nodeOffset; + nodeOffset = nodeOffset + sizeof(nullValues); + while ((fValue = (FieldValue*) iter.nextElement()) != NULL) + { + if (fValue->isNullable && tableHdl->isFldNull(fValue->fldName)) + SETBIT(nullValues, i); + else + AllDataType::copyVal(element+nodeOffset, fValue->value, + fValue->type, fValue->length); + nodeOffset = nodeOffset + fValue->length; + i++; + } + AllDataType::copyVal(ptrToCopyNullValues, &nullValues, typeLongLong, + sizeof(nullValues)); + DbRetVal rv = sortTree.insertDataNode(element); + return rv; +} + +DbRetVal OrderTableImpl::insert() +{ + //compute size of projection + int nodeSize = orderBySize + projSize; + nodeSize = nodeSize + sizeof(int);//to store order by field null values + nodeSize = nodeSize + sizeof(nullValues);//to store proj field null values + char *element = (char*)malloc(nodeSize); + //copy values + int nodeOffset =0; + ListIterator oiter = fldOrderByList.getIterator(); + OrderByFldDef *oFldDef = NULL; + int orderNullValues =0; + int i=0; + while ((oFldDef = (OrderByFldDef*) oiter.nextElement()) != NULL) + { + //oFldDef = (OrderByFldDef*) oiter.nextElement(); + if (oFldDef->isNull && tableHdl->isFldNull(oFldDef->fldName)) + SETBIT(orderNullValues, i); + else + AllDataType::copyVal(element+nodeOffset, oFldDef->bindBuf, + oFldDef->type, oFldDef->length); + nodeOffset = nodeOffset + oFldDef->length; + i++; + } + AllDataType::copyVal(element+nodeOffset, &orderNullValues, typeInt, + sizeof(orderNullValues)); + nodeOffset = nodeOffset+ sizeof(orderNullValues); + nullValues = 0; + i=0; + ListIterator iter = fldProjList.getIterator(); + FieldValue *fValue = NULL; + void* ptrToCopyNullValues = element+nodeOffset; + nodeOffset = nodeOffset + sizeof(nullValues); + while ((fValue = (FieldValue*) iter.nextElement()) != NULL) + { + //fValue = (FieldValue*) iter.nextElement(); + if (fValue->isNullable && tableHdl->isFldNull(fValue->fldName)) + SETBIT(nullValues, i); + else + AllDataType::copyVal(element+nodeOffset, fValue->value, + fValue->type, fValue->length); + nodeOffset = nodeOffset + fValue->length; + i++; + } + AllDataType::copyVal(ptrToCopyNullValues, &nullValues, typeLongLong, + sizeof(nullValues)); + DbRetVal rv = sortTree.insertDataNode(element); + if (rv == ErrUnique) ::free (element); + return OK; +} +void* OrderTableImpl::fetch() +{ + void *elem = sortIter.nextElement(); + if (NULL == elem) return NULL; + copyValuesToBindBuffer(elem); + return elem; + +} +void* OrderTableImpl::fetch(DbRetVal &rv) +{ + rv = OK; + return fetch(); +} + +void* OrderTableImpl::fetchNoBind() +{ + void *elem = sortIter.nextElement(); + if (NULL == elem) return NULL; + copyValuesToBindBuffer(elem); + return elem; +} + +void* OrderTableImpl::fetchNoBind(DbRetVal &rv) +{ + rv = OK; + return fetchNoBind(); +} +DbRetVal OrderTableImpl::setOrderByList(List oList) +{ + ListIterator fIter = oList.getIterator(); + FieldValue *def; + while (fIter.hasElement()) + { + def = (FieldValue*) fIter.nextElement(); + setOrderBy(def->fldName); + } + return OK; +} +DbRetVal OrderTableImpl::copyValuesToBindBuffer(void *elem) +{ + //Iterate through the bind list and copy the value here + ListIterator fIter = fldProjList.getIterator(); + FieldValue *def; + char *colPtr= (char*) elem + orderBySize; + colPtr = colPtr + sizeof(int); + nullValues = *(long long*) colPtr; + colPtr = colPtr + sizeof (nullValues); + while (fIter.hasElement()) + { + def = (FieldValue*) fIter.nextElement(); + if (NULL != def->value) { + AllDataType::copyVal(def->value, colPtr, def->type, def->length); + colPtr = colPtr + def->length; + } + } + return OK; +} +void OrderTableImpl::setNullableForProj() +{ + ListIterator fIter = fldProjList.getIterator(); + FieldValue *def; + FieldInfo *info = new FieldInfo(); + while (fIter.hasElement()) + { + def = (FieldValue*) fIter.nextElement(); + tableHdl->getFieldInfo(def->fldName, info); + def->isNullable = true; + if (info->isNull || info->isPrimary || + info->isDefault || info->isAutoIncrement) { + def->isNullable = false; + } + if (NULL == tableHdl->getName()) def->isNullable=true; + } + delete info; + return; +} +bool OrderTableImpl::isFldNull(const char *fldName) +{ + int pos = 0; + ListIterator fIter = fldProjList.getIterator(); + FieldValue *def; + while (fIter.hasElement()) + { + def = (FieldValue*) fIter.nextElement(); + if (strcmp(fldName, def->fldName) == 0) { + break; + } + pos++; + } + return isFldNull(pos); +} +bool OrderTableImpl::isFldNull(int projPos) +{ + if (BITSET(nullValues, projPos)) return true; + return false; +} + +long OrderTableImpl::numTuples() +{ + return tableHdl->numTuples(); +} +DbRetVal OrderTableImpl::closeScan() +{ + sortIter.reset(); + ListIterator iter = sortTree.getListIterator(); + void *elem= NULL; + while(iter.hasElement()) { + elem = iter.nextElement(); + free(elem); + } + sortTree.removeAll(); + if (tableHdl) tableHdl->closeScan(); + return OK; +} + +DbRetVal OrderTableImpl::close() +{ + nullValues = 0; + closeScan(); + delete this; + return OK; +} +void OrderTableImpl::printPlan(int space) +{ + char spaceBuf[IDENTIFIER_LENGTH]; + memset(spaceBuf, 32, IDENTIFIER_LENGTH); + spaceBuf[space] = '\0'; + printf("%s \n", spaceBuf); + printf("%s \n", spaceBuf); + ListIterator giter = fldOrderByList.getIterator(); + OrderByFldDef *fldDef=NULL; + while ((fldDef = (OrderByFldDef*)giter.nextElement()) != NULL) + { + if (fldDef->isDesc) \ + printf("%s %s DESC \n", spaceBuf, + fldDef->fldName); + else + printf("%s %s ASC \n", spaceBuf, + fldDef->fldName); + } + printf("%s \n", spaceBuf); + if (sortTree.getDistinct()) + printf("%s true \n", spaceBuf); + printf("%s \n", spaceBuf); + if (tableHdl) tableHdl->printPlan(space+2); + return; +} + diff --git a/src/storage/PageInfo.cxx b/src/storage/PageInfo.cxx index 88447634..5e50b7e7 100644 --- a/src/storage/PageInfo.cxx +++ b/src/storage/PageInfo.cxx @@ -16,21 +16,61 @@ #include #include #include +#include +void PageInfo::setPageAsFree() +{ + //isUsed_ = 0; + int ret = Mutex::CAS(&isUsed_, isUsed_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //hasFreeSpace_ = 0; + ret = Mutex::CAS(&hasFreeSpace_ , hasFreeSpace_, 0);; + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //nextPage_ = NULL; + ret = Mutex::CASL((long*)&nextPage_, (long)nextPage_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //nextPageAfterMerge_ = NULL; + ret = Mutex::CASL((long*)&nextPageAfterMerge_, (long)nextPageAfterMerge_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + return; +} void PageInfo::setPageAsUsed(size_t offset) { - isUsed_ = 1; - hasFreeSpace_ = 1; - nextPage_ = NULL; - if (PAGE_SIZE > offset) - nextPageAfterMerge_ = NULL; - else - nextPageAfterMerge_ = ((char*)this)+ offset; + //isUsed_ = 1; + int ret = Mutex::CAS(&isUsed_, isUsed_,1); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //hasFreeSpace_ = 1; + ret = Mutex::CAS(&hasFreeSpace_ , hasFreeSpace_, 1);; + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //nextPage_ = NULL; + ret = Mutex::CASL((long*)&nextPage_, (long)nextPage_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + if (PAGE_SIZE > offset) { + //nextPageAfterMerge_ = NULL; + ret = Mutex::CASL((long*)&nextPageAfterMerge_, (long)nextPageAfterMerge_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + } else { + //nextPageAfterMerge_ = ((char*)this)+ offset; + ret = Mutex::CASL((long*)&nextPageAfterMerge_, + (long) nextPageAfterMerge_ , + (long)(((char*)this)+ offset)); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + } + return; } void PageInfo::setFirstPageAsUsed() { - isUsed_ = 1; - hasFreeSpace_ = 1; - nextPageAfterMerge_ = NULL; - nextPage_ = NULL; + //isUsed_ = 1; + int ret = Mutex::CAS(&isUsed_, 0,1); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //hasFreeSpace_ = 1; + ret = Mutex::CAS(&hasFreeSpace_ , hasFreeSpace_, 1);; + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //nextPageAfterMerge_ = NULL; + ret = Mutex::CASL((long*)&nextPageAfterMerge_, (long)nextPageAfterMerge_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + //nextPage_ = NULL; + ret = Mutex::CASL((long*)&nextPage_, (long)nextPage_, 0); + if (ret != 0) printError(ErrSysFatal, "Fatal:CAS Failed"); + return; } diff --git a/src/storage/PredicateImpl.cxx b/src/storage/PredicateImpl.cxx index 62acfa16..66d62b1f 100644 --- a/src/storage/PredicateImpl.cxx +++ b/src/storage/PredicateImpl.cxx @@ -23,10 +23,15 @@ #include #include #include +static char aggNames[][10] = +{ + "MIN", "MAX", "SUM", "AVG", "COUNT", "" +}; + PredicateImpl::~PredicateImpl() { - if (lhs) {delete lhs; lhs = NULL; } - if (rhs) { delete rhs; rhs = NULL; } +// if (lhs) {delete lhs; lhs = NULL; } +// if (rhs) { delete rhs; rhs = NULL; } } void PredicateImpl::print(int space) { @@ -35,15 +40,28 @@ void PredicateImpl::print(int space) spaceBuf[space] = '\0'; printf("%s \n", spaceBuf); - printf("%s %s \n", spaceBuf, fldName1); - printf("%s %s \n", spaceBuf, fldName2); - printf("%s %s \n", spaceBuf, CompOpNames[compOp]); - printf("%s %s \n", spaceBuf, LogOpNames[logicalOp]); - printf("%s %x \n", spaceBuf, operand); - printf("%s %x \n", spaceBuf, operandPtr); - printf("%s %s \n", spaceBuf, CompOpNames[comp2Op]); - printf("%s %x \n", spaceBuf, operand2); - printf("%s %x \n", spaceBuf, operand2Ptr); + if (0 != strcmp(fldName1, "")) { + if (aggType == AGG_UNKNOWN) + printf("%s %s \n", spaceBuf, fldName1); + else + printf("%s %s(%s) \n", spaceBuf, + aggNames[aggType-1], fldName1); + } + if (0 != strcmp(fldName2, "")) + printf("%s %s \n", spaceBuf, fldName2); + if (compOp != OpInvalidComparisionOp) + printf("%s %s \n", spaceBuf, CompOpNames[compOp]); + if (logicalOp != OpInvalidLogicalOp) + printf("%s %s \n", spaceBuf, LogOpNames[logicalOp]); + if (operand) printf("%s VALUE \n", spaceBuf); + if (operandPtr) printf("%s VALUE \n", spaceBuf); + if (comp2Op != OpInvalidComparisionOp) + printf("%s %s \n", spaceBuf, CompOpNames[comp2Op]); + if (operand2) printf("%s VALUE \n", spaceBuf); + if (operand2Ptr) printf("%s VALUE \n", spaceBuf); + //TEMP + //printf(" %d \n", isPushedDown); + if (lhs) { printf("%s \n", spaceBuf); lhs->print(space+2); @@ -99,6 +117,19 @@ void PredicateImpl::setTerm(const char* fName1, ComparisionOp op, void *opnd) operand2 =NULL; operand2Ptr = NULL; } +void PredicateImpl::setTerm(const char* fName1, ComparisionOp op,bool nullFlag) +{ + strcpy(fldName1, fName1); + compOp = op; + isNull = nullFlag; + lhs = rhs = NULL; + operandPtr = NULL; + operand = NULL; + logicalOp = OpInvalidLogicalOp; + comp2Op = OpInvalidComparisionOp; + operand2 =NULL; + operand2Ptr = NULL; +} void PredicateImpl::setTerm(const char* fName1, ComparisionOp op, void **opnd) { @@ -113,6 +144,21 @@ void PredicateImpl::setTerm(const char* fName1, ComparisionOp op, void **opnd) operand2 =NULL; operand2Ptr = NULL; } +void PredicateImpl::setTerm(const char* fName1, ComparisionOp op, void **opnd, AggType aType) +{ + strcpy(fldName1, fName1); + compOp = op; + operand = NULL; + operandPtr = opnd; + lhs = rhs = NULL; + parent = NULL; + aggType = aType; + logicalOp = OpInvalidLogicalOp; + comp2Op = OpInvalidComparisionOp; + operand2 =NULL; + operand2Ptr = NULL; +} + void PredicateImpl::setTerm(const char* fName1, ComparisionOp op, void **opnd, ComparisionOp op2, void **opnd2) { @@ -155,10 +201,10 @@ void PredicateImpl::setTerm(Predicate *p1, LogicalOp op, Predicate *p2 ) void PredicateImpl::setTable(Table *tbl) { if (NULL != lhs) - lhs->setTable((TableImpl*)tbl); + lhs->setTable(tbl); if (NULL != rhs) - rhs->setTable((TableImpl*)tbl); - table = (TableImpl*)tbl; + rhs->setTable(tbl); + table = tbl; } void PredicateImpl::setIfNoLeftRight() { @@ -176,7 +222,6 @@ void PredicateImpl::setTuple(void *tpl) tuple=tpl; return; } - //if (isPushedDown) return; if (NULL != lhs) lhs->setTuple(tpl); if (NULL != rhs) @@ -224,7 +269,24 @@ bool PredicateImpl::appendIfSameFld(char *fName, ComparisionOp op, void *buf) } return false; } - +bool PredicateImpl::isIsNullInvolved() +{ + bool lhsResult = true, rhsResult = true; + if (NULL != lhs) + { + lhsResult = lhs->isIsNullInvolved(); + } + if (NULL != rhs) + { + rhsResult = rhs->isIsNullInvolved(); + } + if (NULL != lhs) + { + if (lhsResult || rhsResult) return true; + if(compOp == isNull) return true; + } + return false; +} bool PredicateImpl::isNotOrInvolved() { bool lhsResult = true, rhsResult = true; @@ -285,6 +347,78 @@ DbRetVal PredicateImpl::evaluateLogical(bool &result) } return OK; } + +DbRetVal PredicateImpl::evaluateForHaving(bool &result, AggTableImpl *aImpl, void *aggElement) +{ + bool rhsResult = false, lhsResult=false; + DbRetVal retCode =OK; + result = false; + if (NULL != lhs) + { + retCode = lhs->evaluateForHaving(lhsResult, aImpl, aggElement); + if (retCode != OK) return ErrInvalidExpr; + }else lhsResult = true; + if (NULL != rhs) + { + retCode = rhs->evaluateForHaving(rhsResult, aImpl, aggElement); + if (retCode != OK) return ErrInvalidExpr; + } else rhsResult = true; + if (NULL != lhs) + { + if (OpAnd == logicalOp) { + if (lhsResult && rhsResult) result = true; + }else if (OpOr == logicalOp) { + if (lhsResult || rhsResult) result = true; + }else if (OpNot == logicalOp){ + if (lhsResult) result = false; else result = true; + } + printDebug(DM_Predicate, "result is %d", result); + return OK; + } + + void *val1 = NULL, *val2 =NULL; + int offset = aImpl->getAggOffset(fldName1, aggType); + val1 = (void*)((char*)aggElement + offset); + if (!isBindBufSet) { + //sets the type and length when it is called first time + FieldInfo *info = new FieldInfo(); + DbRetVal rv = aImpl->getFieldInfo(fldName1, info); + if (aggType == AGG_AVG) { + type = typeDouble; + length = sizeof(double); + } else if (aggType == AGG_COUNT) { + type = typeInt; + length = sizeof(int); + } else { + type = info->type; + length = info->length; + } + delete info; + isBindBufSet = true; + } + if(operand != NULL && operandPtr == NULL) + { + val2 = (char*) operand; + } + else if(operand == NULL && operandPtr != NULL) + { + val2 = *(char**)operandPtr; + } + if (aggType == AGG_AVG) { + double dVal2 = 0; + AllDataType::convertToDouble(&dVal2, val2, type); + result = AllDataType::compareVal(val1, &dVal2, compOp, typeDouble, length); + } + else if (aggType == AGG_COUNT) { + int dVal2 = 0; + AllDataType::convertToInt(&dVal2, val2, type); + result = AllDataType::compareVal(val1, &dVal2, compOp, typeInt, length); + } + else + result = AllDataType::compareVal(val1, val2, compOp, type, length); + return OK; +} + DbRetVal PredicateImpl::evaluateLogicalForTable(bool &result, char *tuple) { bool rhsResult = false, lhsResult=false; @@ -343,11 +477,23 @@ void PredicateImpl::evaluateForTable(bool &result, char *tuple) } } //Table null check of condition - table->setCurTuple(tuple); - if(table->isFldNull(fldName1)) - { - result=false; - return ; + if (isNullable) { + TableImpl *tImpl = (TableImpl*) table; + tImpl->setCurTuple(tuple); + bool isValueNull = table->isFldNull(fldPos); + if(compOp == OpIsNull) + { + if( (isValueNull && isNull) || (!isValueNull && !isNull) ) + result = true; + else + result = false; + return; + } + if(isValueNull) + { + result=false; + return; + } } //the below code works only for single table val1= tuple + offset1; @@ -358,7 +504,14 @@ void PredicateImpl::evaluateForTable(bool &result, char *tuple) //Note:Perf: Do not change the order below if(operand == NULL && operandPtr != NULL) { - val2 = *(char**)operandPtr; + val2 = *(char**)operandPtr; + if (compOp == OpLike) { + char *c = (char *)val2; + //OPT:If LIKE has only %, then no need to evaluate + if (*c == '%' && *(c+1) == '\0') {result=true; return;} + Util::changeWildcardChar(val2); + } + } else if (operand == NULL && operandPtr == NULL) { if(offset2 != -1) @@ -366,6 +519,11 @@ void PredicateImpl::evaluateForTable(bool &result, char *tuple) } else if(operand != NULL && operandPtr == NULL) { val2 = (char*) operand; + if (compOp == OpLike) { + char *c = (char *)val2; + if (*c == '%' && *(c+1) == '\0') {result=true; return;} + Util::changeWildcardChar(val2); + } } if(operand2 == NULL && operand2Ptr != NULL) { @@ -376,11 +534,15 @@ void PredicateImpl::evaluateForTable(bool &result, char *tuple) } isBindBufSet = true; } + result = true; if(val3) { //printf(" val1 %d val3 %d\n", *(int*)val1, *(int*)val3); result = AllDataType::compareVal(val1, val3, comp2Op, type,length); if(result==false) return; } + if (isPushedDown) { + return; + } //printf(" val1 %d val2 %d\n", *(int*)val1, *(int*)val2); result = AllDataType::compareVal(val1, val2, compOp, type,length); //if (!result && val3) AllDataType::copyVal(val3, @@ -438,7 +600,6 @@ void* PredicateImpl::getVal2IfBetweenOnInt(int &offset) } DbRetVal PredicateImpl::evaluate(bool &result) { - //if (isPushedDown) { result = true; return OK; } if (!isNoLeftRight) { bool rhsResult = false, lhsResult=false; DbRetVal retCode =OK; @@ -446,12 +607,12 @@ DbRetVal PredicateImpl::evaluate(bool &result) if (NULL != lhs) { retCode = lhs->evaluate(lhsResult); - if (retCode != OK) return ErrInvalidExpr; + if (retCode < OK) return ErrInvalidExpr; }else lhsResult = true; if (NULL != rhs) { retCode = rhs->evaluate(rhsResult); - if (retCode != OK) return ErrInvalidExpr; + if (retCode < OK) return ErrInvalidExpr; } else rhsResult = true; if (NULL != lhs) { @@ -462,12 +623,12 @@ DbRetVal PredicateImpl::evaluate(bool &result) if (lhsResult || rhsResult) result = true; }else if (OpNot == logicalOp){ if (lhsResult) result = false; else result = true; + if ( ErrNullValues == retCode) result = false; } printDebug(DM_Predicate, "result is %d", result); return OK; } } - //Means it is relational expression //first operand is always field identifier //get the value in the tuple @@ -530,6 +691,12 @@ DbRetVal PredicateImpl::evaluate(bool &result) } isBindBufSet = true; } + JoinTableImpl *jTable = (JoinTableImpl*) table; + if (jTable->isFldNullInt(fldName1) || jTable->isFldNullInt(fldName2)) + { + result=false; + return ErrNullValues; + } result = AllDataType::compareVal(val1, val2, compOp, type, length); return OK; @@ -561,6 +728,48 @@ DbRetVal PredicateImpl::evaluate(bool &result) result = AllDataType::compareVal(val1, val2, compOp, type,length); return OK; } + +void PredicateImpl::solveForProjList(Table *tab) +{ + if (NULL != lhs) + { + lhs->solveForProjList(tab); + } + if (NULL != rhs) + { + rhs->solveForProjList(tab); + } + table = tab; + if (NULL != lhs) return ; + bool isExist1=false; + bool isExist2=false; + if (projList) + { + ListIterator fIter = projList->getIterator(); + JoinProjFieldInfo *def; + while (fIter.hasElement()) + { + def = (JoinProjFieldInfo*) fIter.nextElement(); + if (!isExist1 && 0 == strcmp(fldName1, def->tabFieldName)) + { + isExist1=true; + } + if (!isExist2 && 0 == strcmp(fldName2, def->tabFieldName) ) + { + isExist2=true; + } + } + if (!isExist1) + { + tab->bindFld(fldName1, NULL); + } + if (!isExist2 && strcmp(fldName2, "")!=0) + { + tab->bindFld(fldName2, NULL); + } + } +} + void PredicateImpl::setOffsetAndType() { if (NULL != lhs) @@ -577,17 +786,27 @@ void PredicateImpl::setOffsetAndType() memset(fieldName2, 0, IDENTIFIER_LENGTH); Table::getFieldNameAlone(fldName1, fieldName1); Table::getFieldNameAlone(fldName2, fieldName2); - + //this function is called only from TableImpl + TableImpl *tImpl = (TableImpl*) table; if(fieldName1){ - offset1 = table->getFieldOffset(fieldName1); - type = table->getFieldType(fieldName1); - length = table->getFieldLength(fieldName1); + FieldInfo *info = new FieldInfo(); + tImpl->getFieldInfo(fieldName1, info); + offset1 = tImpl->getFieldOffset(fieldName1); + fldPos = tImpl->getFldPos(fieldName1); + type = info->type; + length = info->length; + isNullable = true; + if (info->isNull || info->isPrimary || + info->isDefault || info->isAutoIncrement) + isNullable = false; + //printf("isNullable is set to %d\n", isNullable); + delete info; } if(fieldName2){ - offset2 = table->getFieldOffset(fieldName2); + offset2 = tImpl->getFieldOffset(fieldName2); if(typeUnknown == type) - type = table->getFieldType(fieldName2); + type = tImpl->getFieldType(fieldName2); } } @@ -610,7 +829,7 @@ bool PredicateImpl::pointLookupInvolved(const char *fname) { case OpAnd: //return lhsResult; - if (lhsResult && rhsResult) return true; else return false; + if (lhsResult || rhsResult) return true; else return false; break; case OpOr: return false; @@ -662,7 +881,7 @@ bool PredicateImpl::isBetweenInvolved(const char *fname) } char fieldName1[IDENTIFIER_LENGTH]; Table::getFieldNameAlone(fldName1, fieldName1); - if ( OpLessThanEquals == compOp || OpGreaterThanEquals == compOp) + if ( OpGreaterThan == compOp || OpGreaterThanEquals == compOp) { if(0 == strcmp(fieldName1, fname)) { @@ -717,17 +936,17 @@ bool PredicateImpl::rangeQueryInvolved(const char *fname) } -void* PredicateImpl::valPtrForIndexField(const char *fname) +void* PredicateImpl::valPtrForIndexField(const char *fname, bool isUnique) { void *lhsRet=NULL, *rhsRet=NULL; if (NULL != lhs) { - lhsRet = lhs->valPtrForIndexField(fname); + lhsRet = lhs->valPtrForIndexField(fname, isUnique); if ( lhsRet != NULL) return lhsRet; } if (NULL != rhs) { - rhsRet = rhs->valPtrForIndexField(fname); + rhsRet = rhs->valPtrForIndexField(fname, isUnique); if ( rhsRet != NULL) return rhsRet; } char fieldName1[IDENTIFIER_LENGTH]; @@ -738,7 +957,8 @@ void* PredicateImpl::valPtrForIndexField(const char *fname) { if(0 == strcmp(fieldName1, fname)) { - isPushedDown = true; + if (isUnique && compOp != OpLessThan && + compOp != OpLessThanEquals) isPushedDown = true; if (operand) return operand; else return *(void**)operandPtr; } } diff --git a/src/storage/Process.cxx b/src/storage/Process.cxx index 718456ac..b70f9001 100644 --- a/src/storage/Process.cxx +++ b/src/storage/Process.cxx @@ -71,7 +71,7 @@ DbRetVal ProcessManager::registerThread() DbRetVal rv = systemDatabase->getProcessTableMutex(false); if (OK != rv) { - printError(rv,"Unable to get process table mutex"); + printError(rv,"Unable to get mutex for registering"); printError(rv,"Recovery may be going on. Retry after some time."); mutex.getLock(-1, false); noThreads--; @@ -144,18 +144,22 @@ DbRetVal ProcessManager::deregisterThread(int procSlot) { printError(ErrWarning, "Transaction is still running\n"); } + trans->status_ = TransNotUsed; } if (pInfo->want_ != NULL) { printError(ErrSysFatal, "Probable data corruption.wants_ is not null\n"); + systemDatabase->releaseProcessTableMutex(false); return ErrSysFatal; } for (int muti = 0 ;muti < MAX_MUTEX_PER_THREAD; muti++) { if (pInfo->has_[muti] != NULL) { - printError(ErrSysFatal, "Probable data corruption.some mutexes are not freed %x \n", pInfo->has_[muti]); + printError(ErrSysFatal, "Probable data corruption.some mutexes are not freed %x \n", pInfo->has_[muti] ); + pInfo->has_[muti]->print(); pInfo->has_[muti]->releaseLock(procSlot); + systemDatabase->releaseProcessTableMutex(false); return ErrSysFatal; } } @@ -197,6 +201,12 @@ DbRetVal ProcessManager::addMutex(Mutex *mut, int pslot) } } printError(ErrSysInternal, "All slots are full. Reached per thread mutex limit."); + //printStackTrace(); + for (int i = 0 ;i < MAX_MUTEX_PER_THREAD; i++) + { + printError(ErrWarning, "mutex %d %x", i, pInfo->has_[i]); + pInfo->has_[i]->print(); + } return ErrSysInternal; } @@ -231,10 +241,6 @@ DbRetVal ProcessManager::removeMutex(Mutex *mut, int pslot) } } printError(ErrSysInternal, "Mutex could not be found in the list %s", mut->name); - void *array[10]; - size_t size; - size = backtrace(array, 10); - backtrace_symbols_fd(array, size, 2); return ErrSysInternal; } @@ -271,30 +277,8 @@ DbRetVal ProcessManager::setThreadTransaction(Transaction *trans, int pslot) Transaction* ProcessManager::getThreadTransaction(int pslot) { - pid_t pid = os::getpid(); - pthread_t thrid = os::getthrid(); - if (systemDatabase == NULL) - { - return NULL; - } - ThreadInfo* pInfo = systemDatabase->getThreadInfo(pslot); - int i=0; - - for (i = 0; i < MAX_THREADS_PER_PROCESS; i++) - { - if (pInfo->thrTrans_[i].pid_ == pid && pInfo->thrTrans_[i].thrid_ == thrid) break; - } - if (i == MAX_THREADS_PER_PROCESS) - { - printDebug(DM_Process, "Thread specific trans could not be found in list"); - return NULL; - } - - printDebug(DM_Process, "procSlot %d: pid: %d thrid: %lu is returning trans %x\n", pslot, - pid, thrid, pInfo->thrTrans_[i].trans_); - //pInfo->trans_ = trans; - return pInfo->thrTrans_[i].trans_; + return pInfo->thrTrans_[0].trans_; } Transaction** ProcessManager::getThreadTransAddr(int pslot) diff --git a/src/storage/SessionImpl.cxx b/src/storage/SessionImpl.cxx index 9c95867b..25d7549b 100644 --- a/src/storage/SessionImpl.cxx +++ b/src/storage/SessionImpl.cxx @@ -29,6 +29,8 @@ DbRetVal SessionImpl::initSystemDatabase() { + long value=0; + DbRetVal rv = OK; rv = readConfigFile(); if (rv != OK) @@ -37,11 +39,12 @@ DbRetVal SessionImpl::initSystemDatabase() return ErrSysInit; } - Conf::config.print(); + // Conf::config.print(); dbMgr = new DatabaseManagerImpl(); rv = dbMgr->createDatabase(SYSTEMDB, Conf::config.getMaxSysDbSize()); if (OK != rv) return rv; + dbMgr->setSysDb(dbMgr->db()); dbMgr->setDb(NULL); @@ -59,6 +62,13 @@ DbRetVal SessionImpl::initSystemDatabase() //create the default dba user CatalogTableUSER cUser(db); + rv = cUser.insert(I_USER, I_PASS); + if (OK != rv) + { + db->releaseDatabaseMutex(); + return rv; + } + rv = cUser.insert(DBAUSER, DBAPASS); if (OK != rv) { @@ -74,9 +84,9 @@ DbRetVal SessionImpl::initSystemDatabase() printError(ErrSysInit, "Allocation of Lock buckets failed"); return ErrSysInit; } - db->releaseDatabaseMutex(); - printf("sysdb size %ld dbsize %ld\n", Conf::config.getMaxSysDbSize(), Conf::config.getMaxDbSize()); + + printf("Sys_DB [Size=%4.4ldMB] \nUser_DB [Size=%4.4ldMB]\n", Conf::config.getMaxSysDbSize()/1048576, Conf::config.getMaxDbSize()/1048576); //create user database rv = dbMgr->createDatabase("userdb", Conf::config.getMaxDbSize()); if (OK != rv) return rv; @@ -150,8 +160,9 @@ DbRetVal SessionImpl::authenticate(const char *username, const char *password) DbRetVal rv = dbMgr->sysDb()->getDatabaseMutex(false); if (OK != rv) { - printError(rv,"Unable to get database mutex"); - return rv; + printError(ErrLockTimeOut,"System under recovery or DDL operation going on."); + printError(ErrLockTimeOut,"Unable to get the database mutex.Retry..."); + return ErrLockTimeOut; } CatalogTableUSER cUser(dbMgr->sysDb()); cUser.authenticate(username, password, isAuthenticated, isDba); @@ -280,8 +291,14 @@ DbRetVal SessionImpl::readConfigFile() char *confFilename = os::getenv("CSQL_CONFIG_FILE"); if (confFilename == NULL) { - printError(ErrSysInit, "CSQL_CONFIG_FILE environment variable should be set."); - return ErrSysInit; + if (os::fileExists(DEFAULT_CONFIG_FILE)) { + confFilename = DEFAULT_CONFIG_FILE; + } + else { + printError(ErrSysInit, "CSQL_CONFIG_FILE environment variable " + "should be set."); + return ErrSysInit; + } } int rv = Conf::config.readAllValues(confFilename); diff --git a/src/storage/TableConfig.cxx b/src/storage/TableConfig.cxx dissimilarity index 76% index 1f0a6d08..9a5852fd 100644 --- a/src/storage/TableConfig.cxx +++ b/src/storage/TableConfig.cxx @@ -1,953 +1,502 @@ -/*************************************************************************** - * Copyright (C) 2007 by www.databasecache.com * - * Contact: praba_tuty@databasecache.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - ***************************************************************************/ -#include -#include -#include - -TableConfig TableConf::config; - -char *TableConfig::getConditionVal(char *condition) -{ - char str[124]; - int i=0; - char *ptr, *ptr1 = str; - while(condition[i]!='\0') - { - if(condition[i] == ' ') - { - ptr = (condition+(i+1)); - if(strncasecmp(ptr,"and ",4)==0) { - *ptr1='#';ptr1++; strncpy(ptr1,ptr,3); ptr1+=3; - *ptr1='#';ptr1++; i+=4; - } - else if(strncasecmp(ptr,"or ",3)==0) { - *ptr1='#';ptr1++;strncpy(ptr1,ptr,2); ptr1+=2; - *ptr1='#';ptr1++; i+=3; - } - else if(strncasecmp(ptr,"between ",8)==0) { - *ptr1='#';ptr1++;strncpy(ptr1,ptr,7); ptr1+=7; - *ptr1='#';ptr1++; i+=8; - } - else if(strncasecmp(ptr,"in ",3)==0) { - *ptr1='#'; ptr1++; strncpy(ptr1,ptr,2); ptr1+=2; - *ptr1='#';ptr1++; i+=3; - } - i++; - }else{ - *ptr1 = condition[i++]; - ptr1++; - } - } - *ptr1='\0'; - strcpy(condition,str); -// printf("Condition %s\n",condition); - return condition; -} - -char *TableConfig::getRealConditionFromFile(char *condition) -{ - char str[124]; - int i=0; - char *ptr = str; - while(condition[i]!='\0') - { - if(condition[i]=='#'){ - *ptr=' '; - ptr++;i++; - }else{ - *ptr=condition[i]; - ptr++; - i++; - } - } - *ptr='\0'; - strcpy(condition,str); -// printf("Condition %s\n",condition); - return condition; -} - -DbRetVal TableConfig::addToCacheTableFile(bool isDirect) -{ - FILE *fp; - fp = fopen(Conf::config.getTableConfigFile(),"a"); - if( fp == NULL ) { - printError(ErrSysInit, "Invalid path/filename in TABLE_CONFIG_FILE.\nTable will not be" - "recovered in case of crash"); - return ErrSysInit; - } - //TODO::if already table present in the file, it means that the - //table is replicated. in this case change mode from - //2 to 3 (repl to replcache) - if( strcmp(fieldName,"")==0 ){ strcpy(fieldName,"NULL"); } - if(isDirect) - { - if((strcmp(conditionVal,"")!=0)&&(strcmp(fieldlistVal,"")!=0)) - { - fprintf(fp,"%d:%s %s %s %s\n",6,tableName,fieldName,getConditionVal(conditionVal),fieldlistVal); - } - else if((strcmp(conditionVal,"")!=0)&&(strcmp(fieldlistVal,"")==0)) - { - strcpy(fieldlistVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",6,tableName,fieldName,getConditionVal(conditionVal),fieldlistVal); - } - else if((strcmp(conditionVal,"")==0)&&(strcmp(fieldlistVal,"")!=0)) - { - strcpy(conditionVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",6,tableName,fieldName,conditionVal,fieldlistVal); - } - else - { - strcpy(fieldlistVal,"NULL"); - strcpy(conditionVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",5,tableName,fieldName,conditionVal,fieldlistVal); - } - } - else - { - if((strcmp(conditionVal,"")!=0)&&(strcmp(fieldlistVal,"")!=0)) - { - fprintf(fp,"%d:%s %s %s %s\n",2,tableName,fieldName,getConditionVal(conditionVal),fieldlistVal); - } - else if((strcmp(conditionVal,"")!=0)&&(strcmp(fieldlistVal,"")==0)) - { - strcpy(fieldlistVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",2,tableName,fieldName,getConditionVal(conditionVal),fieldlistVal); - } - else if((strcmp(conditionVal,"")==0)&&(strcmp(fieldlistVal,"")!=0)) - { - strcpy(conditionVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",2,tableName,fieldName,conditionVal,fieldlistVal); - } - else - { - strcpy(fieldlistVal,"NULL"); - strcpy(conditionVal,"NULL"); - fprintf(fp,"%d:%s %s %s %s\n",1,tableName,fieldName,conditionVal,fieldlistVal); - } - - } - fclose(fp); - return OK; -} - -DbRetVal TableConfig::removeFromCacheTableFile() -{ - FILE *fp, *tmpfp; - char tmpFileName[MAX_FILE_PATH_LEN]; - sprintf(tmpFileName, "%s.tmp", Conf::config.getTableConfigFile()); - tmpfp = fopen(tmpFileName,"w"); - if( tmpfp == NULL ) { - printError(ErrSysInit, "Invalid path/filename in TABLE_CONFIG_FILE.\n"); - return ErrSysInit; - } - fp = fopen(Conf::config.getTableConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "csqltable.conf file does not exist"); - return ErrSysInit; - } - char tablename[IDENTIFIER_LENGTH]; - char fieldname[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - while(!feof(fp)) - { - fscanf(fp, "%d:%s %s %s %s\n", &mode, tablename,fieldname,condition,field); - if (strcmp (tablename, tableName) == 0) continue; - fprintf(tmpfp, "%d:%s %s %s %s\n", mode, tablename,fieldname,condition,field); - } - fclose(tmpfp); - fclose(fp); - char sysCommand[MAX_FILE_PATH_LEN * 2]; - sprintf(sysCommand, "mv %s %s", tmpFileName, Conf::config.getTableConfigFile()); - int ret = system(sysCommand); - if (ret != 0) - { - printError(ErrSysInit, "Check csqltable.conf file permission. unable to remove %s from file", tableName); - return ErrSysInit; - } - return OK; -} - -// new function is added by: Jitendra -DbRetVal TableConfig :: isTablePresent() -{ - DbRetVal rv = OK; - FILE *fp; - Connection conn; - rv = conn.open(userName,password); - if(rv !=OK) return ErrSysInit; - // check for CACHE_TABLE variable - - - fp = fopen(Conf :: config.getTableConfigFile(),"r"); - if(fp == NULL) - { - printError(ErrSysInit, "cachetable.conf file does not exist"); - return OK; - } - conn.close(); - - char tablename[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char fieldname[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - - while(!feof(fp)) - { - tablename[0] = '\0'; condition[0] = '\0'; - fscanf(fp,"%d:%s %s %s %s\n",&mode,tablename,fieldname,condition,field); - - if(strcmp(tableName,tablename)==0) - { - fclose(fp); - return OK; - } - } - fclose(fp); - return ErrNotExists; -} - -/* - -DbRetVal CacheTableLoader::load(bool tabDefinition) -{ - Connection conn; - DbRetVal rv = conn.open(userName, password); - if (rv != OK) return ErrSysInit; - // check for CACHE_TABLE variable - - - DatabaseManager *dbMgr = (DatabaseManager*) conn.getDatabaseManager(); - if (dbMgr == NULL) { printError(ErrSysInit, "Auth failed\n"); return ErrSysInit; } - if (tabDefinition == false) { - Table *tbl = dbMgr->openTable(tableName); - if (tbl == NULL) { - conn.close(); - return ErrNotExists; - } - if (tbl->numTuples()) { - printError(ErrNotEmpty, "The table '\%s\' is not empty", tableName); - dbMgr->closeTable(tbl); - conn.close(); - return ErrNotEmpty; - } - } - conn.startTransaction(); - rv = load(dbMgr, tabDefinition); - conn.commit(); - conn.close(); - return rv; -} - -DbRetVal CacheTableLoader::load(DatabaseManager *dbMgr, bool tabDefinition) -{ - char dsn[72]; - if( strcmp(Conf::config.getUser(),"") != 0 && strcmp(Conf::config.getPassword(),"") != 0 ) - { - sprintf(dsn, "DSN=%s;UID=%s;PWD=%s;", Conf::config.getDSN(),Conf::config.getUser(),Conf::config.getPassword()); - }else{ - sprintf(dsn, "DSN=%s;", Conf::config.getDSN()); - } - //printf("UID=%s;PWD=%s;\n",Conf::config.getUser(),Conf::config.getPassword()); - SQLCHAR outstr[1024]; - SQLSMALLINT outstrlen; - DbRetVal rv = OK; - int retValue =0; - SQLHENV henv; - SQLHDBC hdbc; - SQLHSTMT hstmt; - retValue = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); - if (retValue) {printError(ErrSysInit, "Unable to allocate ODBC handle \n"); return ErrSysInit; } - SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - retValue = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc); - if (retValue) {printError(ErrSysInit, "Unable to allocate ODBC handle \n"); return ErrSysInit; } - retValue = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)dsn, SQL_NTS, - outstr, sizeof(outstr), &outstrlen, - SQL_DRIVER_NOPROMPT); - if (SQL_SUCCEEDED(retValue)) { - printDebug(DM_Gateway, "Connected to target database using dsn = %s\n", dsn); - } else { - fprintf(stderr, "Failed to connect to target database\n"); - return ErrSysInit; - } - - retValue=SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt); - if (retValue) {printError(ErrSysInit, "Unable to allocate ODBC handle \n"); return ErrSysInit; } - char stmtBuf[1024]; - - if(((strcmp(conditionVal,"")==0) || (strcmp(conditionVal,"NULL")==0)) && ((strcmp(fieldlistVal,"")==0) || (strcmp(fieldlistVal,"NULL")==0))) - { - sprintf(stmtBuf, "SELECT * FROM %s;", tableName); - } - else if(((strcmp(conditionVal,"")!=0) || (strcmp(conditionVal,"NULL")!=0)) && ((strcmp(fieldlistVal,"")==0) || (strcmp(fieldlistVal,"NULL")==0))) - { - sprintf(stmtBuf,"SELECT * FROM %s where %s;",tableName,conditionVal); - - } - else if(((strcmp(conditionVal,"")==0) || (strcmp(conditionVal,"NULL")==0)) && ((strcmp(fieldlistVal,"")!=0) || (strcmp(fieldlistVal,"NULL")!=0))) - { - sprintf(stmtBuf,"SELECT %s FROM %s;",fieldlistVal,tableName); - } - else - sprintf(stmtBuf,"SELECT %s FROM %s where %s;",fieldlistVal,tableName,conditionVal); - - retValue = SQLPrepare (hstmt, (unsigned char *) stmtBuf, SQL_NTS); - if (retValue) {printError(ErrSysInit, "Unable to Prepare ODBC statement \n"); return ErrSysInit; } - - if (tabDefinition) { - short totalFields=0; - retValue = SQLNumResultCols (hstmt, &totalFields); - if (retValue) {printError(ErrSysInit, "Unable to retrieve ODBC total columns\n"); return ErrSysInit; } - UWORD icol; - UCHAR colName[IDENTIFIER_LENGTH]; - SWORD colNameMax; - SWORD nameLength; - SWORD colType; - SQLULEN colLength; - SWORD scale; - SWORD nullable; - TableDef tabDef; - icol = 1; colNameMax = IDENTIFIER_LENGTH; - char columnname[IDENTIFIER_LENGTH]; - char indexname[IDENTIFIER_LENGTH]; - short type; short unique; - SQLHSTMT hstmtmeta; - retValue=SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmtmeta); - if (retValue) - { - printError(ErrSysInit, "Unable to allocate ODBC handle \n"); - return ErrSysInit; - } - retValue=SQLPrimaryKeys(hstmtmeta, NULL, SQL_NTS, NULL, SQL_NTS, (SQLCHAR*) tableName, SQL_NTS); - retValue = SQLBindCol(hstmtmeta, 4, SQL_C_CHAR,columnname, 129,NULL); - HashIndexInitInfo *inf = new HashIndexInitInfo(); - bool isPriIndex=false; - char indname[IDENTIFIER_LENGTH]; - if(SQLFetch( hstmtmeta ) == SQL_SUCCESS) - { - Util::str_tolower(columnname); - inf->list.append(columnname); - while( SQLFetch( hstmtmeta ) == SQL_SUCCESS ) - { - Util::str_tolower(columnname); - inf->list.append(columnname); - } - inf->indType = hashIndex; - inf->bucketSize = 10007; - inf->isUnique = true; inf->isPrimary = true; - strcpy(inf->tableName, tableName); - strcpy(indexname,"PRIMARY"); - sprintf(indname, "%s_%s", tableName, indexname); - isPriIndex=true; - } - char *name = NULL; - bool iskeyfieldExist=true; - if(isPriIndex && (strcmp(fieldlistVal,"")!=0) && (strcmp(fieldlistVal,"NULL")!=0)) - { - inf->list.resetIter(); - while ((name=inf->list.nextFieldName())!=NULL) - { - iskeyfieldExist=isFieldExist(name); - if(!iskeyfieldExist) { break; } - } - }else if(!isPriIndex){iskeyfieldExist = false;} - if(((strcmp(fieldName,"")!=0) && (strcmp(fieldName,"NULL")!=0)) && !(isFieldExist(fieldName))) - { - if(Conf::config.useTwoWayCache() && (strcmp(fieldlistVal,"")!=0) && (strcmp(fieldlistVal,"NULL")!=0)) - { - printError(ErrSysInit, "Bidirectonal caching fail for no primary key in %s \n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - - if(!iskeyfieldExist && ((strcmp(fieldName,"")==0) || (strcmp(fieldName,"NULL")==0))) - { - if(Conf::config.useTwoWayCache()) - { - printError(ErrSysInit, "Bidirectonal caching fail for no primary key in %s \n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - bool isKeyFld=false; - bool isNullfld=false; - while (icol <= totalFields) { - retValue = SQLDescribeCol(hstmt, icol, colName, colNameMax, - &nameLength, &colType, &colLength, - &scale, &nullable); - if (retValue) { - printError(ErrSysInit, "Unable to retrieve ODBC column info\n"); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - Util::str_tolower((char*)colName); - printDebug(DM_Gateway, "Describe Column %s %d %d \n", colName, colType, colLength); - icol++; - if(strcmp((char*)colName,fieldName)== 0) - { - isKeyFld=true; - isNullfld=true; - } - bool isPriFld=false; - if (nullable) { - inf->list.resetIter(); - while ((name=inf->list.nextFieldName())!=NULL) - { - if(0==strcmp((char*)colName,name)) - { - tabDef.addField((char*)colName, AllDataType::convertFromSQLType(colType,colLength), colLength +1, NULL, true); - isPriFld=true; - break; - } - } - if(!isPriFld) { - if(!isNullfld) - tabDef.addField((char*)colName, AllDataType::convertFromSQLType(colType,colLength), colLength +1); - else{ - tabDef.addField((char*)colName, AllDataType::convertFromSQLType(colType,colLength), colLength +1, NULL, true); - isNullfld=false; - } - } - } - else - tabDef.addField((char*)colName, AllDataType::convertFromSQLType(colType,colLength), colLength +1, NULL, true); - } - if(((strcmp(fieldName,"")!=0) && (strcmp(fieldName,"NULL")!=0))&& !isKeyFld) - { - printError(ErrSysInit, "Unable to cache Table for %s with key field %s\n", tableName,fieldName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - rv = dbMgr->createTable(tableName, tabDef); - if (rv != OK) - { - printError(ErrSysInit, "Table creation failed in csql for %s\n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - if(isPriIndex ){ - rv = dbMgr->createIndex(indname, inf); - if (rv != OK) - { - printError(ErrSysInit, "Index creation failed in csql for %s\n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - else - { - if(Conf::config.useTwoWayCache() && iskeyfieldExist) - { - printError(ErrSysInit, "Bidirectonal caching fail for no primary key in %s \n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - retValue = SQLCloseCursor(hstmtmeta); - isKeyFld= false; - retValue = SQLStatistics(hstmtmeta, NULL, 0, NULL, SQL_NTS, - (SQLCHAR*) tableName, SQL_NTS, SQL_INDEX_ALL, SQL_QUICK); - retValue = SQLBindCol(hstmtmeta, 4, SQL_C_SHORT, - &unique, 2, NULL); - retValue = SQLBindCol(hstmtmeta, 6, SQL_C_CHAR, - indexname, 129, NULL); - retValue = SQLBindCol(hstmtmeta, 7, SQL_C_SHORT, - &type, 2, NULL); - retValue = SQLBindCol(hstmtmeta, 9, SQL_C_CHAR, - columnname, 129,NULL); - while ((retValue = SQLFetch(hstmtmeta)) == SQL_SUCCESS) - { //if (type != SQL_TABLE_STAT) - { - printDebug(DM_Gateway, "Column: %-18s Index Name: %-18s unique:%hd type:%hd\n", - columnname, indexname, unique, type); - } - if(0 == strcmp(columnname,fieldName)){isKeyFld=true;} - bool isPrimary=false; - inf->list.resetIter(); - while ((name=inf->list.nextFieldName())!=NULL) - { - if(0==strcmp(columnname,name)) - { - isPrimary=true; - break; - } - } - if(isPrimary){continue;} - if (type == 3) { - HashIndexInitInfo *info = new HashIndexInitInfo(); - info->indType = hashIndex; - info->bucketSize = 10007; - info->list.append(columnname); - if (!unique) {info->isUnique = true; info->isPrimary = false;} - strcpy(info->tableName, tableName); - char indname[128]; - sprintf(indname, "%s_%s", tableName, indexname); - rv = dbMgr->createIndex(indname, info); - if (rv != OK) - { - printError(ErrSysInit, "Index creation failed in csql for %s\n", tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - delete info; - } else { - printError(ErrSysInit,"CSQL does not support this index type\n"); - dbMgr->dropTable(tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - }// while meta data fetch for index creation - SQLCloseCursor (hstmtmeta); - SQLFreeHandle (SQL_HANDLE_STMT, hstmtmeta); - if( !isKeyFld && ((strcmp(fieldName,"")!=0) && (strcmp(fieldName,"NULL")!=0))) - { - if(shouldForce){ - HashIndexInitInfo *info = new HashIndexInitInfo(); - info->indType = hashIndex; - info->bucketSize = 10007; - info->list.append(fieldName); - info->isUnique = true; - info->isPrimary = false; - strcpy(info->tableName, tableName); - char indname[128]; - sprintf(indname, "%s_%s", tableName, "keyInd"); - rv = dbMgr->createIndex(indname, info); - if (rv != OK) - { - printError(ErrSysInit, "Index creation failed in csql for %s\n", tableName); - dbMgr->dropTable(tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - delete info; - - }else{ - printError(ErrSysInit, "Unable to cache Table for %s with key field %s\n", tableName,fieldName); - dbMgr->dropTable(tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - } - Table *table = dbMgr->openTable(tableName); - if (table == NULL) { - printError(ErrSysInit,"unable to open table %s\n", tableName); - dbMgr->closeTable(table); - if (tabDefinition) dbMgr->dropTable(tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - table->setUndoLogging(true); - //rv = table->lock(false); //no need to release this lock as it is upgrade from S to X - if (rv != OK) - { - dbMgr->closeTable(table); - if (tabDefinition) dbMgr->dropTable(tableName); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - List fNameList = table->getFieldNameList(); - ListIterator fNameIter = fNameList.getIterator(); - FieldInfo *info = new FieldInfo(); - int fcount =1; void *valBuf; int fieldsize=0; - Identifier *elem = NULL; - - BindBuffer *bBuf; - List valBufList; - SQLINTEGER len[IDENTIFIER_LENGTH]; - while (fNameIter.hasElement()) { - elem = (Identifier*) fNameIter.nextElement(); - table->getFieldInfo((const char*)elem->name, info); - valBuf = AllDataType::alloc(info->type, info->length); - table->bindFld(elem->name, valBuf); - os::memset(valBuf,0,info->length); - fieldsize=0; - switch( info->type) - { - case typeString: - fieldsize = info->length; - break; - case typeDate: - bBuf = new BindBuffer(); - bBuf->csql = valBuf; - bBuf->type = typeDate; - fieldsize = sizeof(DATE_STRUCT); - bBuf->targetdb = malloc(fieldsize); - valBuf = bBuf->targetdb; - valBufList.append(bBuf); - break; - case typeTime: - bBuf = new BindBuffer(); - bBuf->csql = valBuf; - bBuf->type = typeTime; - fieldsize = sizeof(TIME_STRUCT); - bBuf->targetdb = malloc(fieldsize); - valBuf = bBuf->targetdb; - valBufList.append(bBuf); - break; - case typeTimeStamp: - bBuf = new BindBuffer(); - bBuf->csql = valBuf; - bBuf->type = typeTimeStamp; - fieldsize = sizeof(TIMESTAMP_STRUCT); - bBuf->targetdb = malloc(fieldsize); - valBuf = bBuf->targetdb; - valBufList.append(bBuf); - break; - } - os::memset(valBuf,0,fieldsize); - retValue = SQLBindCol (hstmt, fcount, AllDataType::convertToSQLType(info->type), - valBuf, fieldsize, &len[fcount]); - fcount++; - if (retValue) { - printError(ErrSysInit, "Unable to bind columns in ODBC\n"); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - } - delete info; - retValue = SQLExecute (hstmt); - if (retValue) { - printError(ErrSysInit, "Unable to execute ODBC statement\n"); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - return ErrSysInit; - } - int fldpos=0; - while(true) - { - retValue = SQLFetch (hstmt); - if (retValue) break; - ListIterator bindIter = valBufList.getIterator(); - while (bindIter.hasElement()) { - bBuf = (BindBuffer*) bindIter.nextElement(); - switch (bBuf->type) { - case typeDate: { - Date *dtCSQL = (Date*) bBuf->csql; - DATE_STRUCT *dtTarget = (DATE_STRUCT*) bBuf->targetdb; - dtCSQL->set(dtTarget->year,dtTarget->month,dtTarget->day); - break; - } - case typeTime: { - Time *dtCSQL = (Time*) bBuf->csql; - TIME_STRUCT *dtTarget = (TIME_STRUCT*) bBuf->targetdb; - dtCSQL->set(dtTarget->hour,dtTarget->minute,dtTarget->second); - break; - } - case typeTimeStamp: { - TimeStamp *dtCSQL = (TimeStamp*) bBuf->csql; - TIMESTAMP_STRUCT *dtTarget = (TIMESTAMP_STRUCT*) bBuf->targetdb; - dtCSQL->setDate(dtTarget->year,dtTarget->month,dtTarget->day); - dtCSQL->setTime(dtTarget->hour,dtTarget->minute,dtTarget->second, dtTarget->fraction); - break; - } - } - } - fldpos=0; - table->resetNullinfo(); - while(fldpos < fcount-1) - { - if(len[++fldpos] == SQL_NULL_DATA){ - table->markFldNull(fldpos); - } - } - - table->insertTuple(); - } - //TODO::leak:: valBufList and its targetdb buffer - valBufList.reset(); - dbMgr->closeTable(table); - SQLCloseCursor (hstmt); - SQLFreeHandle (SQL_HANDLE_STMT, hstmt); - SQLDisconnect (hdbc); - SQLFreeHandle (SQL_HANDLE_DBC, hdbc); - SQLFreeHandle (SQL_HANDLE_ENV, henv); - - //add the content to the chkpt file if durability mode is set - if (Conf::config.useDurability()) { - char dbChkptFileName[1024]; - char cmd[1024]; - sprintf(dbChkptFileName, "%s/csql.db.chkpt", Conf::config.getDbFile()); - sprintf(cmd, "csqldump -T %s >> %s",tableName, dbChkptFileName); - int ret = system(cmd); - if (ret != 0) { - printError(ErrWarning, "Unable to append cache table to checkpoint file\n"); - } - } - return OK; -} - -DbRetVal CacheTableLoader::reload() -{ - DbRetVal rv = unload(false); - if (rv != OK) return rv; - rv = load(false); - return rv; -} - -DbRetVal CacheTableLoader::unload(bool tabDefinition) -{ - Connection conn; - DbRetVal rv = conn.open(userName, password); - if (rv != OK) return ErrSysInit; - - if (CacheTableLoader::isTableCached(tableName) != OK) { - printError(ErrNotCached, "The table \'%s\' is not cached", tableName); - return ErrNotCached; - } - DatabaseManager *dbMgr = (DatabaseManager*) conn.getDatabaseManager(); - if (dbMgr == NULL) { printError(ErrSysInit, "Auth failed\n"); return ErrSysInit; } - if (!tabDefinition) - { - Table *table = dbMgr->openTable(tableName); - if (table == NULL) { conn.close(); return ErrBadCall; } - rv = conn.startTransaction(); - if (rv != OK) { dbMgr->closeTable(table); conn.close(); return ErrBadCall; } - table->truncate(); - conn.commit(); - dbMgr->closeTable(table); - } - else - { - rv = dbMgr->dropTable(tableName); - } - conn.close(); - - return rv; -} - -DbRetVal CacheTableLoader::refresh() -{ - return OK; -} - -DbRetVal CacheTableLoader::recoverAllCachedTables() -{ - FILE *fp; - Connection conn; - DbRetVal rv = conn.open(userName, password); - if(rv !=OK) return ErrSysInit; - - //Note: if connection is not open, configuration veriables may be incorrect - - fp = fopen(Conf::config.getTableConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "cachetable.conf file does not exist"); - return OK; - } - conn.close(); - //TODO::take exclusive lock on database - char tablename[IDENTIFIER_LENGTH]; - char fieldname[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - rv = OK; - while(!feof(fp)) - { - fscanf(fp, "%d:%s %s %s %s\n", &mode, tablename,fieldname,condition,field); - //if (mode ==2 ) //just replicated table and not cached - //continue; - printDebug(DM_Gateway, "Recovering Table from target db: %s\n", tablename); - setCondition(getRealConditionFromFile(condition)); - setTable(tablename); - setFieldName(fieldname); - setFieldListVal(field); - printf("Recovering table %s %s %s\n", tablename,condition,field); - rv = load(); - if (rv != OK) return rv; - } - fclose(fp); - return OK; -} -*/ - -DbRetVal TableConfig::isTableCached(char *tabName) -{ - FILE *fp; - char tmpFileName[MAX_FILE_PATH_LEN]; - Conf::config.readAllValues(os::getenv("CSQL_CONFIG_FILE")); - fp = fopen(Conf::config.getTableConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "csqltable.conf file does not exist"); - return ErrSysInit; - } - char tablename[IDENTIFIER_LENGTH]; - char fieldname[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - while(!feof(fp)) - { - fscanf(fp, "%d:%s %s %s %s\n", &mode, tablename,fieldname,condition,field); - if (strcmp (tablename, tabName) == 0) { - fclose(fp); - return OK; - } - } - fclose(fp); - return ErrNotExists; -} - -int TableConfig::getTableMode(char *tabname) -{ - FILE *fp; - fp = fopen(Conf::config.getTableConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "cachetable.conf file does not exist"); - fclose(fp); - return 0; - } - char tablename[IDENTIFIER_LENGTH]; - char fieldname[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - while(!feof(fp)) - { - fscanf(fp,"%d:%s %s %s %s\n",&mode,tablename,fieldname,fieldname,condition); - if(0==strcmp(tabname,tablename)){ - fclose(fp); - return mode; - } - } - fclose(fp); - return 0; -} - - -bool TableConfig::isFieldExist(char *fieldname) -{ - char tmpfieldname[IDENTIFIER_LENGTH]; - int i=0,j=0; - while(fieldlistVal[j]!=0) - { - if(fieldlistVal[j] != ',') - tmpfieldname[i++]=fieldlistVal[j++]; - else - { - tmpfieldname[i]='\0'; - if(strcmp(fieldname,tmpfieldname)==0) - return true; - else { i=0; j++; } - } - } - tmpfieldname[i]='\0'; - if(strcmp(fieldname,tmpfieldname)==0) - return true; - else - return false; -} -DbRetVal TableConfig::CacheInfo(bool isTabPresent) -{ - FILE *fp; - fp = fopen(Conf::config.getTableConfigFile(),"r"); - if( fp == NULL ) { - printError(ErrSysInit, "cachetable.conf file does not exist"); - fclose(fp); - return OK; - } - - char tablename[IDENTIFIER_LENGTH]; - char pkfield[IDENTIFIER_LENGTH]; - char condition[IDENTIFIER_LENGTH]; - char field[IDENTIFIER_LENGTH]; - int mode; - printf("\n=================================================================================================================\n"); - printf("|\tMode\t|\tTable Name\t|\tPrimary Key\t|\tCondition\t|\tField List\t|\n"); - printf("=================================================================================================================\n"); - while(!feof(fp)) - { - fscanf(fp,"%d:%s %s %s %s\n",&mode,tablename,pkfield,condition,field); - if((mode<1) || (mode >6)) - {return ErrNotFound;} - - if(isTabPresent) - { - if(strcmp(tableName,tablename)==0) - { - printf("|%8d\t|%16s\t|%16s\t|%16s\t|%16s\t|\n",mode,tablename,pkfield,getRealConditionFromFile(condition),field); - printf("-----------------------------------------------------------------------------------------------------------------\n\n"); - fclose(fp); - return OK; - } - } - else - { - printf("|%8d\t|%16s\t|%16s\t|%16s\t|%16s\t|\n",mode,tablename,pkfield,getRealConditionFromFile(condition),field); - printf("-----------------------------------------------------------------------------------------------------------------\n"); - } - } - printf("\n"); - fclose(fp); - return OK; -} +/*************************************************************************** + * Copyright (C) 2007 by www.databasecache.com * + * Contact: praba_tuty@databasecache.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ +#include +#include +#include + +TableConfig TableConf::config; + +char *TableConfig::getConditionVal(char *condition) +{ + char str[124]; + int i=0; + char *ptr, *ptr1 = str; + while(condition[i]!='\0') + { + if(condition[i] == ' ') + { + ptr = (condition+(i+1)); + if(strncasecmp(ptr,"and ",4)==0) { + *ptr1='#';ptr1++; strncpy(ptr1,ptr,3); ptr1+=3; + *ptr1='#';ptr1++; i+=4; + } + else if(strncasecmp(ptr,"or ",3)==0) { + *ptr1='#';ptr1++;strncpy(ptr1,ptr,2); ptr1+=2; + *ptr1='#';ptr1++; i+=3; + } + else if(strncasecmp(ptr,"between ",8)==0) { + *ptr1='#';ptr1++;strncpy(ptr1,ptr,7); ptr1+=7; + *ptr1='#';ptr1++; i+=8; + } + else if(strncasecmp(ptr,"in ",3)==0) { + *ptr1='#'; ptr1++; strncpy(ptr1,ptr,2); ptr1+=2; + *ptr1='#';ptr1++; i+=3; + } + i++; + }else{ + *ptr1 = condition[i++]; + ptr1++; + } + } + *ptr1='\0'; + strcpy(condition,str); +// printf("Condition %s\n",condition); + return condition; +} + +char *TableConfig::getRealConditionFromFile(char *condition) +{ + char str[124]; + int i=0; + char *ptr = str; + while(condition[i]!='\0') + { + if(condition[i]=='#'){ + *ptr=' '; + ptr++;i++; + }else{ + *ptr=condition[i]; + ptr++; + i++; + } + } + *ptr='\0'; + strcpy(condition,str); +// printf("Condition %s\n",condition); + return condition; +} + +DbRetVal TableConfig::addToCacheTableFile(bool isDirect) +{ + FILE *fp; + fp = fopen(Conf::config.getTableConfigFile(),"a"); + if( fp == NULL ) { + printError(ErrSysInit, "Invalid path/filename in TABLE_CONFIG_FILE.\nTable will not be recovered in case of crash"); + return ErrSysInit; + } + unsigned int mode = 0; + bool isFldName = strcmp(fieldName,"") != 0; + bool isCondVal = strcmp(conditionVal,"") != 0; + bool isFldListVal = strcmp(fieldlistVal,"") != 0; + bool isDsn = strcmp(dsnName,"") != 0; + + if (!isCondVal && !isFldListVal && !isDirect) + mode |= SIMPLE_CACHE; + if (isCondVal) mode |= CONDNL_CACHE; + if (isDirect) mode |= DIRECT_CACHE; + if (isFldListVal) mode |= FLDLVL_CACHE; + + if (!isFldName) strcpy(fieldName,"NULL"); + bool isCached = isTableCached(mode); + if (!isCached) strcpy(dsnName, "NULL"); + else if (!isDsn && isCached) strcpy(dsnName, Conf::config.getDSN()); + + if (isCondVal && isFldListVal) { + fprintf(fp,"%d %s %s %s %s %s \n", mode, tableName, fieldName, + getConditionVal(conditionVal), fieldlistVal, dsnName); + } + else if (isCondVal && !isFldListVal) { + strcpy(fieldlistVal,"NULL"); + fprintf(fp,"%d %s %s %s %s %s \n", mode, tableName, fieldName, + getConditionVal(conditionVal), fieldlistVal, dsnName); + } + else if (!isCondVal && isFldListVal) { + strcpy(conditionVal,"NULL"); + fprintf(fp,"%d %s %s %s %s %s \n", mode, tableName, fieldName, + conditionVal, fieldlistVal, dsnName); + } else { + strcpy(fieldlistVal,"NULL"); + strcpy(conditionVal,"NULL"); + fprintf(fp,"%d %s %s %s %s %s \n", mode, tableName, fieldName, + conditionVal, fieldlistVal, dsnName); + } + fclose(fp); + return OK; +} + +DbRetVal TableConfig::removeFromCacheTableFile() +{ + FILE *fp, *tmpfp; + char tmpFileName[MAX_FILE_PATH_LEN]; + sprintf(tmpFileName, "%s.tmp", Conf::config.getTableConfigFile()); + tmpfp = fopen(tmpFileName,"w"); + if( tmpfp == NULL ) { + printError(ErrSysInit, "Invalid path/filename in TABLE_CONFIG_FILE.\n"); + return ErrSysInit; + } + fp = fopen(Conf::config.getTableConfigFile(),"r"); + if( fp == NULL ) { + printError(ErrSysInit, "csqltable.conf file does not exist"); + return ErrSysInit; + } + char tablename[IDENTIFIER_LENGTH]; + char fieldname[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + + unsigned int mode; + while(!feof(fp)) + { + fscanf(fp, "%d %s %s %s %s %s \n", &mode, tablename,fieldname,condition,field,dsnName); + if (strcmp (tablename, tableName) == 0) continue; + fprintf(tmpfp, "%d %s %s %s %s %s \n", mode, tablename,fieldname,condition,field,dsnName); + } + fclose(tmpfp); + fclose(fp); + char sysCommand[MAX_FILE_PATH_LEN * 2]; + sprintf(sysCommand, "mv %s %s", tmpFileName, Conf::config.getTableConfigFile()); + int ret = system(sysCommand); + if (ret != 0) + { + printError(ErrSysInit, "Check csqltable.conf file permission. unable to remove %s from file", tableName); + return ErrSysInit; + } + ret = unlink(tmpFileName); + return OK; +} + +DbRetVal TableConfig::updateIntoCacheTableFile(bool upgrade, bool isDirect) +{ + FILE *fp, *tmpfp; + char tmpFileName[MAX_FILE_PATH_LEN]; + sprintf(tmpFileName, "%s.tmp", Conf::config.getTableConfigFile()); + tmpfp = fopen(tmpFileName,"w"); + if( tmpfp == NULL ) { + printError(ErrSysInit, "Invalid path/filename in TABLE_CONFIG_FILE.\n"); + return ErrSysInit; + } + fp = fopen(Conf::config.getTableConfigFile(),"r+"); + if( fp == NULL ) { + printError(ErrSysInit, "csqltable.conf file does not exist"); + return ErrSysInit; + } + + unsigned int mode = 0; + bool isFldName = strcmp(fieldName,"") != 0; + bool isCondVal = strcmp(conditionVal,"") != 0; + bool isFldListVal = strcmp(fieldlistVal,"") != 0; + bool isDsn = strcmp(dsnName,"") != 0; + + char tablename[IDENTIFIER_LENGTH]; + char fieldname[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + + char updtablename[IDENTIFIER_LENGTH]; + char updfieldname[IDENTIFIER_LENGTH]; + char updcondition[IDENTIFIER_LENGTH]; + char updfield[IDENTIFIER_LENGTH]; + char upddsnName[IDENTIFIER_LENGTH]; + + unsigned int tblMode = 0; + unsigned int modeToUpd = 0; + bool found = false; + //if (mode == 1 && upgrade) updMode = 8; + //else if (mode == 8 && !upgrade) updMode = -8; + //else if( mode == 1 && !upgrade) updMode = -1; + while(!feof(fp)) + { + fscanf(fp, "%d %s %s %s %s %s \n", &tblMode, tablename,fieldname,condition,field,dsnName); + if (strcmp (tablename, tableName) == 0) { + modeToUpd = tblMode; + strcpy(updtablename, tablename); + strcpy(updfieldname, fieldname); + strcpy(updcondition, condition); + strcpy(updfield, field); + strcpy(upddsnName, dsnName); + //else strcpy(upddsnName, "NULL"); + found = true; + continue; + } + fprintf(tmpfp, "%d %s %s %s %s %s \n", tblMode, tablename,fieldname,condition,field,dsnName); + } + if (found) { + bool isCached = isTableCached(modeToUpd); + if (isCached) { + unsetCacheMode(&modeToUpd); + strcpy(updfieldname, "NULL"); + strcpy(updcondition, "NULL"); + strcpy(updfield, "NULL"); + strcpy(upddsnName, "NULL"); + } + + fprintf(tmpfp, "%d %s %s %s %s %s\n", modeToUpd, updtablename, + updfieldname, updcondition, updfield, upddsnName); + fclose(tmpfp); + fclose(fp); + char sysCommand[MAX_FILE_PATH_LEN * 2]; + sprintf(sysCommand, "mv %s %s", tmpFileName, + Conf::config.getTableConfigFile()); + int ret = system(sysCommand); + if (ret != 0) + { + printError(ErrSysInit, "Check csqltable.conf file permission. unable to remove %s from file", tableName); + return ErrSysInit; + } + } else { fclose (fp); fclose(tmpfp); } + unlink(tmpFileName); + return OK; +} + +// new function is added by: Jitendra +DbRetVal TableConfig :: isTablePresent() +{ + DbRetVal rv = OK; + FILE *fp; + Connection conn; + rv = conn.open(userName,password); + if(rv !=OK) return ErrSysInit; + // check for CACHE_TABLE variable + + + fp = fopen(Conf :: config.getTableConfigFile(),"r"); + if(fp == NULL) + { + printError(ErrSysInit, "cachetable.conf file does not exist"); + return OK; + } + conn.close(); + + char tablename[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char fieldname[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + int mode; + + while(!feof(fp)) + { + tablename[0] = '\0'; condition[0] = '\0'; + fscanf(fp,"%d %s %s %s %s %s \n",&mode,tablename,fieldname,condition,field,dsnName); + + if(strcmp(tableName,tablename)==0) + { + fclose(fp); + return OK; + } + } + fclose(fp); + return ErrNotExists; +} + + +DbRetVal TableConfig::isTableCached(char *tabName) +{ + FILE *fp; + char tmpFileName[MAX_FILE_PATH_LEN]; + Conf::config.readAllValues(os::getenv("CSQL_CONFIG_FILE")); + fp = fopen(Conf::config.getTableConfigFile(),"r"); + if( fp == NULL ) { + printError(ErrSysInit, "csqltable.conf file does not exist"); + return ErrSysInit; + } + char tablename[IDENTIFIER_LENGTH]; tablename[0]='\0'; + char fieldname[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + unsigned int tabMode = 0; + + while(!feof(fp)) + { + fscanf(fp, "%d %s %s %s %s %s \n", &tabMode, tablename,fieldname, + condition,field,dsnName); + if (strcmp (tablename, tabName) == 0) { + fclose(fp); + bool isCached = isTableCached(tabMode); + if (isCached) return OK; + else return ErrNotCached; + } + } + fclose(fp); + return ErrNotCached; +} + + +unsigned int TableConfig::getTableMode(char *tabname) +{ + FILE *fp; + fp = fopen(Conf::config.getTableConfigFile(),"r"); + if( fp == NULL ) { + printError(ErrSysInit, "cachetable.conf file does not exist"); + fclose(fp); + return 0; + } + char tablename[IDENTIFIER_LENGTH]; tablename[0] = '\0'; + char fieldname[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + unsigned int tabMode=0; + while(!feof(fp)) { + fscanf(fp,"%d %s %s %s %s %s \n",&tabMode,tablename,fieldname, + fieldname,condition,dsnName); + if (0 == strcmp(tabname,tablename)) { + fclose(fp); + return tabMode; + } + } + fclose(fp); + return 0; +} + + +bool TableConfig::isFieldExist(char *fieldname) +{ + char tmpfieldname[IDENTIFIER_LENGTH]; + int i=0,j=0; + while(fieldlistVal[j]!=0) + { + if(fieldlistVal[j] != ',') + tmpfieldname[i++]=fieldlistVal[j++]; + else + { + tmpfieldname[i]='\0'; + if(strcmp(fieldname,tmpfieldname)==0) + return true; + else { i=0; j++; } + } + } + tmpfieldname[i]='\0'; + if(strcmp(fieldname,tmpfieldname)==0) + return true; + else + return false; +} +DbRetVal TableConfig::CacheInfo(bool isTabPresent) +{ + FILE *fp; + fp = fopen(Conf::config.getTableConfigFile(),"r"); + if( fp == NULL ) { + printError(ErrSysInit, "cachetable.conf file does not exist"); + fclose(fp); + return OK; + } + + char tablename[IDENTIFIER_LENGTH]; + char pkfield[IDENTIFIER_LENGTH]; + char condition[IDENTIFIER_LENGTH]; + char field[IDENTIFIER_LENGTH]; + char dsnName[IDENTIFIER_LENGTH]; + unsigned int mode = 0; + + printf("\n=================================================================================================================\n"); + printf("|Mode|\tTable Name\t|\tPrimary Key\t|\tCondition\t|\tField List\t|\tDSN\t|\n"); + printf("=================================================================================================================\n"); + while(!feof(fp)) + { + fscanf(fp,"%d %s %s %s %s %s \n",&mode,tablename,pkfield,condition,field,dsnName); + if(!mode) { + printf("| Cached table does not exist. |\n"); + printf("=================================================================================================================\n"); + return OK; + } + + if(isTabPresent) + { + if(strcmp(tableName,tablename)==0) + { + printf("|%2d |%16s\t|%16s\t|%16s\t|%16s\t|%10s\t|\n",mode,tablename,pkfield,getRealConditionFromFile(condition),field,dsnName); + printf("-----------------------------------------------------------------------------------------------------------------\n\n"); + fclose(fp); + return OK; + } + } + else + { + + printf("|%2d |%16s\t|%16s\t|%16s\t|%16s\t|%10s\t|\n",mode,tablename,pkfield,getRealConditionFromFile(condition),field,dsnName); + printf("-----------------------------------------------------------------------------------------------------------------\n"); + } + } + printf("\n"); + fclose(fp); + return OK; +} + +DbRetVal TableConfig::getDsnAndTdb(char *dsn,char *newdsn, char *tdb) +{ + char dsnId[IDENTIFIER_LENGTH]; dsnId[0]='\0'; + char user[IDENTIFIER_LENGTH]; user[0] = '\0'; + char passwd[IDENTIFIER_LENGTH]; passwd[0] = '\0'; + char tdbname[IDENTIFIER_LENGTH]; tdbname[0]='\0'; + FILE *fp=NULL; + bool isDSNExist=false; + fp = fopen(Conf :: config.getDsConfigFile(),"r"); + if(fp==NULL) + { + printError(ErrSysInit, "csqlds.conf file does not exist"); + return ErrSysInit; + } + while(!feof(fp)) { + fscanf(fp,"%s %s %s %s\n",dsnId,user,passwd,tdbname); + if(strcmp(dsnId,dsn)==0) { + if( strcmp(user,"NULL")!=0 && strcmp(passwd,"NULL")!=0) { + sprintf(newdsn,"DSN=%s;UID=%s;PWD=%s;",dsn,user,passwd);isDSNExist=true; break; + } + else + { + sprintf(newdsn,"DSN=%s;",dsn); isDSNExist=true;break; + } + } + } + + fclose(fp); + if(isDSNExist) + { + strcpy(tdb, tdbname); + return OK; + } + else + { + printError(ErrNotExists,"dsn is not present in the csqlds.conf file\n"); + return ErrNotExists; + } +} + +//get the DSN for respective cached table. +//This function is used in "SqlGwStatement.cxx:prepare()" +DbRetVal TableConfig::getDsnForTable(char *tab, char *dsnname) +{ + FILE *fp; + fp = fopen(Conf::config.getTableConfigFile(),"r"); + if( fp == NULL){ + printError(ErrSysInit, "cachetable.conf file does not exist"); + fclose(fp); + return ErrOS; + } + char tablename[IDENTIFIER_LENGTH];tablename[0]='\0'; + char pkfield[IDENTIFIER_LENGTH];pkfield[0]='\0'; + char condition[IDENTIFIER_LENGTH];condition[0]='\0'; + char field[IDENTIFIER_LENGTH];field[0]='\0'; + char dsnName[IDENTIFIER_LENGTH];dsnName[0]='\0'; + int mode; + char *dsn=NULL; + + while(!feof(fp)){ + fscanf(fp,"%d %s %s %s %s %s \n",&mode,tablename,pkfield,condition,field,dsnName); + if(strcmp(tab,tablename)==0){ + strcpy(dsnname, dsnName); + fclose(fp); + return OK; + } + + } + fclose(fp); + return ErrNotFound; +} diff --git a/src/storage/TableDef.cxx b/src/storage/TableDef.cxx index 918a6895..75621e40 100644 --- a/src/storage/TableDef.cxx +++ b/src/storage/TableDef.cxx @@ -31,7 +31,7 @@ int TableDef::addField(const char *name, DataType type, size_t length, const void *defaultValue, bool notNull, bool autoIn) { if (name == NULL) return (int)ErrBadArg; - if(strlen(name)>64) + if(strlen(name)>IDENTIFIER_LENGTH) { printError(ErrBadRange,"Field name should not exceed 64 character"); return (int)ErrBadRange; @@ -46,11 +46,16 @@ int TableDef::addField(const char *name, DataType type, size_t length, return (int) ErrAlready; } } + + if (!Util::isIdentifier((char*)name)) { + printError(ErrBadArg, "fieldname contains invalid characters"); + return (int) ErrBadArg; + } FieldDef fldDef; strcpy(fldDef.fldName_, name); fldDef.fldName_[IDENTIFIER_LENGTH] = '\0'; fldDef.type_ = type; - fldDef.length_ = os::align(length); + fldDef.length_ = AllDataType::size(type, length); fldDef.bindVal_=NULL; if (defaultValue != NULL) { @@ -72,11 +77,12 @@ int TableDef::addField(const char *name, DataType type, size_t length, os::memset(fldDef.defaultValueBuf_,0, DEFAULT_VALUE_BUF_LENGTH); } fldDef.isNull_ = notNull; - fldDef.isAutoIncrement_= autoIn; + fldDef.isAutoIncrement_ = autoIn; + //os::memset(fldDef.autoVal_,0, DEFAULT_VALUE_BUF_LENGTH); switch(type) { case typeString : - case typeBinary: + case typeBinary : fldDef.length_ = os::align(length); break; default: @@ -108,7 +114,7 @@ size_t TableDef::getTupleSize() while (iter.hasElement()) { FieldDef *def = iter.nextElement(); - length = length + os::align(def->length_); + length = length + def->length_; } return length; } diff --git a/src/storage/TableImpl.cxx b/src/storage/TableImpl.cxx index 71a49405..8bd05b7d 100644 --- a/src/storage/TableImpl.cxx +++ b/src/storage/TableImpl.cxx @@ -65,6 +65,9 @@ DbRetVal TableImpl::bindFld(const char *name, void *val) bool TableImpl::isFldNull(const char *name){ if (name[0] == '*') return false; + if ( strncasecmp(name,"COUNT",5) == 0 || strncasecmp(name,"AVG",3) == 0 || + strncasecmp(name,"MIN",3) == 0 || strncasecmp(name,"MAX",3) == 0 || + strncasecmp(name,"SUM",3) == 0 ) return false; char fieldName[IDENTIFIER_LENGTH]; getFieldNameAlone((char*)name, fieldName); int colpos = fldList_.getFieldPosition(fieldName); @@ -81,6 +84,10 @@ int TableImpl::getFldPos(char *name) { return fldList_.getFieldPosition(name); } +void TableImpl::setAliasName(char *name) +{ + strcpy(aliasName, name); +} bool TableImpl::isFldNull(int colpos) { if (!curTuple_) return false; @@ -90,7 +97,7 @@ bool TableImpl::isFldNull(int colpos) if (BITSET(nullVal, colpos)) return true; } else { - char *nullOffset = (char*)curTuple_ - os::align(numFlds_); + char *nullOffset = (char*)curTuple_ + (length_ - os::align(numFlds_)); if (nullOffset[colpos-1]) return true; } return false; @@ -102,7 +109,7 @@ void TableImpl::resetNullinfo() } else { int i=0; - while(i < numFlds_) { cNullInfo[0] = 0;} + while(i < numFlds_) { cNullInfo[i++] = 0;} } } DbRetVal TableImpl::markFldNull(char const* name) @@ -133,7 +140,7 @@ DbRetVal TableImpl::markFldNull(int fldpos) } } else { - if (!BITSET(iNotNullInfo, fldpos)) cNullInfo[fldpos-1] = 1; + if (!cNotNullInfo[fldpos-1]) cNullInfo[fldpos-1] = 1; else { printError(ErrNullViolation, "NOT NULL constraint violation"); return ErrNullViolation; @@ -150,7 +157,6 @@ void TableImpl::clearFldNull(const char *name) printError(ErrNotExists, "Field %s does not exist", name); return; } - clearFldNull(colpos); } @@ -210,7 +216,7 @@ void TableImpl::addPredicate(char *fName, ComparisionOp op, void *buf) PredicateImpl *pred = (PredicateImpl*) pred_; PredicateImpl *newPred = new PredicateImpl(); newPred->setTerm(fName, op, buf); - if (NULL == pred) { pred_ = newPred; return; } + if (NULL == pred) { pred_ = newPred; predList.append(newPred); return; } if (pred->isSingleTerm()) { bool res = pred->appendIfSameFld(fName, op, buf); @@ -221,6 +227,7 @@ void TableImpl::addPredicate(char *fName, ComparisionOp op, void *buf) } PredicateImpl *bothPred = new PredicateImpl(); bothPred->setTerm(pred, OpAnd, newPred); + predList.append(bothPred); pred_ = bothPred; } @@ -235,32 +242,37 @@ DbRetVal TableImpl::optimize() pred->setProjectionList(NULL); pred->setOffsetAndType(); } - return createPlan(); + DbRetVal rv = createPlan(); + if (rv != OK) return rv; + if (iter) { iter->close(); delete iter; iter = NULL; } + if (useIndex_ >= 0) + iter = new TupleIterator(pred_, scanType_, idxInfo[useIndex_], chunkPtr_, sysDB_->procSlot,isBetween,isPointLook,shouldNullSearch); + else if (scanType_ == fullTableScan) + iter = new TupleIterator(pred_, scanType_, NULL, chunkPtr_, sysDB_->procSlot,isBetween,isPointLook,shouldNullSearch); + else + { + printError(ErrSysFatal,"Unable to create tuple iterator"); + //should never happen + return ErrSysFatal; + } + iter->setPlan(); + return OK; } DbRetVal TableImpl::execute() { - if (NULL != iter) + if (iter && !iter->isIterClosed()) { //printError(ErrAlready,"Scan already open:Close and re execute"); return ErrAlready; } DbRetVal ret = OK; - ret = optimize(); + if (!isPlanCreated) ret = optimize(); if (OK != ret) { printError(ErrSysInternal,"Unable to create the plan"); return ErrSysInternal; } - if (useIndex_ >= 0) - iter = new TupleIterator(pred_, scanType_, idxInfo[useIndex_], chunkPtr_, sysDB_->procSlot,isBetween,isPointLook); - else if (scanType_ == fullTableScan) - iter = new TupleIterator(pred_, scanType_, NULL, chunkPtr_, sysDB_->procSlot,isBetween,isPointLook); - else - { - printError(ErrSysFatal,"Unable to create tuple iterator");//should never happen - return ErrSysFatal; - } ret = iter->open(); if (OK != ret) { @@ -288,6 +300,7 @@ DbRetVal TableImpl::createPlan() if (NULL != def->bindVal_) bindList_.append(def); } numBindFlds_ = bindList_.size(); + if (bindListArray_) { ::free(bindListArray_); bindListArray_ = NULL; } bindListArray_ = (void **) malloc(numBindFlds_ * sizeof (void *)); void *elem = NULL; int i = 0; @@ -302,9 +315,17 @@ DbRetVal TableImpl::createPlan() isPlanCreated = true; return OK; } + //If serching for IS NULL or IS NOT NULL then fullscan if (NULL != indexPtr_) { PredicateImpl *pred = (PredicateImpl*)pred_; + if(pred->isIsNullInvolved()) + { + scanType_ = fullTableScan; + isPlanCreated = true; + shouldNullSearch=true; + return OK; + } printDebug(DM_Predicate, "predicate does not involve NOT , OR operator"); if (!pred->isNotOrInvolved()) { @@ -389,48 +410,71 @@ void* TableImpl::fetchNoBind() return NULL; } DbRetVal lockRet = OK; - if(!loadFlag) { - if ((*trans)->isoLevel_ == READ_COMMITTED) - { - //if iso level is read committed, operation duration lock is sufficent so release it here itself. - int tries = 5; - struct timeval timeout; - timeout.tv_sec = Conf::config.getMutexSecs(); - timeout.tv_usec = Conf::config.getMutexUSecs(); - - bool status = false; - while(true) { - lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status); - if (OK != lockRet) - { - printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); - curTuple_ = prevTuple; - return NULL; - } - if (!status) break; - tries--; - if (tries == 0) break; - os::select(0, 0, 0, 0, &timeout); - } - if (tries == 0) - { - printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); - curTuple_ = prevTuple; - return NULL; - } - } - else if ((*trans)->isoLevel_ == READ_REPEATABLE) { - lockRet = lMgr_->getSharedLock(curTuple_, trans); + if (!loadFlag) { + if ((*trans)->isoLevel_ == READ_COMMITTED) + { + //if iso level is read committed, operation duration lock is sufficent + //so release it here itself. + int tries = Conf::config.getMutexRetries(); + struct timeval timeout; + timeout.tv_sec = Conf::config.getMutexSecs(); + timeout.tv_usec = Conf::config.getMutexUSecs(); + + bool status = false; + while(true) { + lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status); if (OK != lockRet) { printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); curTuple_ = prevTuple; return NULL; } + if (!status) break; + tries--; + if (tries == 0) break; + os::select(0, 0, 0, 0, &timeout); + } + if (tries == 0) + { + printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); + curTuple_ = prevTuple; + return NULL; } - } + } + else if ((*trans)->isoLevel_ == READ_REPEATABLE) { + if (OK != trySharedLock(curTuple_, trans)) + { + printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); + curTuple_ = prevTuple; + return NULL; + } + + } + } return curTuple_; } +DbRetVal TableImpl::trySharedLock(void *curTuple, Transaction **trans) +{ + DbRetVal lockRet = OK; + int tries = Conf::config.getMutexRetries(); + while((lockRet = lMgr_->getSharedLock(curTuple_, trans)) == ErrLockTimeOut) + { + tries--; + if (tries <=0) break; + } + return lockRet; +} +DbRetVal TableImpl::tryExclusiveLock(void *curTuple, Transaction **trans) +{ + DbRetVal lockRet = OK; + int tries = Conf::config.getMutexRetries(); + while((lockRet = lMgr_->getExclusiveLock(curTuple_, trans)) == ErrLockTimeOut) + { + tries--; + if (tries <=0) break; + } + return lockRet; +} void* TableImpl::fetchNoBind(DbRetVal &rv) { @@ -448,52 +492,54 @@ void* TableImpl::fetchNoBind(DbRetVal &rv) return NULL; } DbRetVal lockRet = OK; - if(!loadFlag) { - if ((*trans)->isoLevel_ == READ_REPEATABLE) { - lockRet = lMgr_->getSharedLock(curTuple_, trans); + if (!loadFlag) { + if ((*trans)->isoLevel_ == READ_REPEATABLE) { + lockRet = lMgr_->getSharedLock(curTuple_, trans); + if (OK != lockRet) + { + printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); + rv = ErrLockTimeOut; + curTuple_ = prevTuple; + return NULL; + } + + } + else if ((*trans)->isoLevel_ == READ_COMMITTED) + { + //if iso level is read committed, operation duration lock is sufficent + //so release it here itself. + int tries = Conf::config.getMutexRetries(); + //struct timeval timeout; + //timeout.tv_sec = Conf::config.getMutexSecs(); + //timeout.tv_usec = Conf::config.getMutexUSecs(); + + bool status = false; + while(true) { + lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status); if (OK != lockRet) { printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); - rv = ErrLockTimeOut; curTuple_ = prevTuple; + rv = ErrLockTimeOut; return NULL; } + if (!status) break; + tries--; + if (tries == 0) break; + //os::select(0, 0, 0, 0, &timeout); } - else if ((*trans)->isoLevel_ == READ_COMMITTED) + if (tries == 0) { - //if iso level is read committed, operation duration lock is sufficent so release it here itself. - int tries = 5; - struct timeval timeout; - timeout.tv_sec = Conf::config.getMutexSecs(); - timeout.tv_usec = Conf::config.getMutexUSecs(); - - bool status = false; - while(true) { - lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status); - if (OK != lockRet) - { - printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); - curTuple_ = prevTuple; - rv = ErrLockTimeOut; - return NULL; - } - if (!status) break; - tries--; - if (tries == 0) break; - os::select(0, 0, 0, 0, &timeout); - } - if (tries == 0) - { - printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); - curTuple_ = prevTuple; - rv = ErrLockTimeOut; - return NULL; - } + printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_); + curTuple_ = prevTuple; + rv = ErrLockTimeOut; + return NULL; } } + } return curTuple_; } -DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) +DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf, bool &noRec) { FieldInfo *info = new FieldInfo(); DbRetVal rv = getFieldInfo(fldName, info); @@ -506,7 +552,14 @@ DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) if (AGG_MIN == aType) { HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos]; CINDEX *iptr = (CINDEX*) hInfo->indexPtr; - TreeIter *iter = new TreeIter((TreeNode*)iptr->hashNodeChunk_); + TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_; + TreeIter *iter=NULL; + if(fstNode!=NULL){ + TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode))); + iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot); + }else{ + iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot); + } char *tuple = (char*) iter->getFirstElement(); if (tuple != NULL) { AllDataType::copyVal(buf,(void*)(tuple+info->offset), @@ -514,82 +567,143 @@ DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) delete iter; return OK; } - delete iter; + delete iter; iter = NULL; } else if (AGG_MAX == aType) { HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos]; CINDEX *iptr = (CINDEX*) hInfo->indexPtr; - TreeIter *iter = new TreeIter((TreeNode*)iptr->hashNodeChunk_); + TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_; + TreeIter *iter=NULL; + if(fstNode!=NULL){ + TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode))); + iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot); + }else{ + iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot); + } char *tuple = (char*) iter->getLastElement(); if (tuple != NULL) { AllDataType::copyVal(buf,(void*)(tuple+info->offset), info->type, info->length); - delete iter; + delete iter; iter = NULL; return OK; } - delete iter; + delete iter; iter=NULL; } } + }else if (AGG_COUNT == aType) { + (*(int*)buf) = 0; } + DataType type = info->type; int length = info->length; int offset = info->offset; - - if (NULL == pred_ && typeInt == type) + int colPos = fldList_.getFieldPosition(fldName); + bool isNullable= true; + if (info->isNull || info->isPrimary || info->isDefault || info->isAutoIncrement) { + isNullable = false; + } + int nullOffset = length_-4; + if (aType == AGG_COUNT) { + length = sizeof(int); + type = typeInt; + } + if (NULL == pred_ && typeInt == type && aType != AGG_AVG) { //perf opt ChunkIterator cIter = ((Chunk*)chunkPtr_)->getIterator(); char *tuple =(char*)cIter.nextElement(); - if (NULL == tuple) return OK; + if (NULL == tuple) { + *(int *) buf = 0; + noRec = true; + return OK; + } int count =1; - AllDataType::copyVal(buf, (void*) (tuple+offset), type, length); - while(1) { - tuple = (char*)cIter.nextElement(); - if (NULL == tuple) break; - switch(aType) { - case AGG_MIN: - { - if (*(int*)buf >= *((int*)(tuple+offset))) - *(int*)buf = *((int*)(tuple+offset)); - break; - } - case AGG_MAX: - { - if (*(int*)buf <= *((int*)(tuple+offset))) - *(int*)buf = *((int*)(tuple+offset)); - break; - } - case AGG_SUM: - { - *(int*)buf = *(int*)buf + *((int*)(tuple+offset)); - break; - } - case AGG_AVG: - { - *(int*)buf = *(int*)buf + *((int*)(tuple+offset)); - count++; - break; - } - case AGG_COUNT: - { - count++; - break; - } + if (isNullable) { + if (isIntUsedForNULL) { + if (BITSET(*(int*)(tuple+nullOffset), colPos)) count =0; } - } - if( AGG_AVG == aType) AllDataType::divVal(buf, &count, type); - else if (AGG_COUNT == aType) (*(int*)buf) = count; - delete info; - return OK; + else { + curTuple_= tuple; + if(isFldNull(colPos)) count =0; + } + } + if (aType != AGG_COUNT) + AllDataType::copyVal(buf, (void*) (tuple+offset), type, length); + void *prev=NULL; + prev = curTuple_; + cIter.pageSize = PAGE_SIZE; + while(1) + { + tuple = (char*)cIter.nextElementInt(); + if (NULL == tuple) break; + if (isNullable) { + if (isIntUsedForNULL) { + if (BITSET(*(int*)(tuple+nullOffset), colPos)) continue; + } + else { + curTuple_= tuple; + if(isFldNull(colPos)) continue; + } + } + if (aType == AGG_MIN) + { + if (*(int*)buf >= *((int*)(tuple+offset))) + *(int*)buf = *((int*)(tuple+offset)); + } + else if (aType == AGG_MAX) + { + if (*(int*)buf <= *((int*)(tuple+offset))) + *(int*)buf = *((int*)(tuple+offset)); + } + else if (aType == AGG_SUM) + { + *(int*)buf += *((int*)(tuple+offset)); + } + else if (aType == AGG_AVG) + { + *(int*)buf = *(int*)buf + *((int*)(tuple+offset)); + count++; + } + else if (aType == AGG_COUNT) + { + count++; + } + } + curTuple_= prev; + if( AGG_AVG == aType) AllDataType::divVal(buf, &count, type); + else if (AGG_COUNT == aType) (*(int*)buf) = count; + delete info; + return OK; } char *tuple = (char*) fetchNoBind(rv); - if ( NULL == tuple) return OK; + if ( NULL == tuple) { noRec = true; return OK; } int count =1; - AllDataType::copyVal(buf, (void*) (tuple+offset), type, length); + + while(isFldNull(colPos)) { + tuple= (char*) fetchNoBind(rv); + if (aType == AGG_COUNT) count++; + if (tuple) break; + } + if ( NULL == tuple) { noRec = true; return OK; } + + if (aType == AGG_AVG) { + AllDataType::convertToDouble(buf, (void*) (tuple+offset), type); + } else if (aType != AGG_COUNT) { + AllDataType::copyVal(buf, (void*) (tuple+offset), type, length); + } while(1) { tuple = (char*) fetchNoBind(rv); if (NULL == tuple) break; + if (isNullable) { + if (isIntUsedForNULL) { + if (BITSET(*(int*)(tuple+nullOffset), colPos)) continue; + } + else { + curTuple_= tuple; + if(isFldNull(colPos)) continue; + } + } switch(aType) { case AGG_MIN: { @@ -617,8 +731,9 @@ DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) } case AGG_AVG: { - AllDataType::addVal(buf, (void*) (tuple+offset), - type); + double tmpBuf=0.0; + AllDataType::convertToDouble(&tmpBuf, (void*) (tuple+offset), type); + AllDataType::addVal(buf, &tmpBuf, typeDouble); count++; break; } @@ -632,7 +747,7 @@ DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) switch(aType) { case AGG_AVG: { - AllDataType::divVal(buf, &count,type); + AllDataType::divVal((double *)buf, count, type); break; } case AGG_COUNT: @@ -647,30 +762,59 @@ DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf) DbRetVal TableImpl::insertTuple() { DbRetVal ret =OK; - void *tptr = ((Chunk*)chunkPtr_)->allocate(db_, &ret); + void *tptr = NULL;// ((Chunk*)chunkPtr_)->allocate(db_, &ret); + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) + { + ret = OK; + tptr = ((Chunk*)chunkPtr_)->allocate(db_, &ret); + if (tptr !=NULL) break; + if (ret != ErrLockTimeOut) + { + printError(ret, "Unable to allocate record from chunk"); + return ret; + } + tries++; + } if (NULL == tptr) { - printError(ret, "Unable to allocate record from chunk"); + printError(ret, "Unable to allocate record from chunk after %d retries", tries); return ret; } - if (!loadFlag) { - ret = lMgr_->getExclusiveLock(tptr, trans); - if (OK != ret) - { - ((Chunk*)chunkPtr_)->free(db_, tptr); - printError(ret, "Could not get lock for the insert tuple %x", tptr); - return ErrLockTimeOut; + curTuple_ = tptr; + if(isFkTbl){ + TableImpl *fkTbl =NULL; + ListIterator tblIter = tblList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + bool pkRec = isPkTableHasRecord(fkTbl->getName(),fkTbl,true); + if(!pkRec){ + printError(ErrForeignKeyInsert, "Unable to insert into foreign Key table.Check PK table"); + ((Chunk*)chunkPtr_)->free(db_, tptr); + return ErrForeignKeyInsert; + } } + tblIter.reset(); } - curTuple_ = tptr; - + if (!loadFlag) { + //ret = lMgr_->getExclusiveLock(tptr, trans); + if (OK != tryExclusiveLock(tptr, trans)) + { + ((Chunk*)chunkPtr_)->free(db_, tptr); + printError(ret, "Could not get lock for the insert tuple %x", tptr); + return ErrLockTimeOut; + } + } + ret = copyValuesFromBindBuffer(tptr); if (ret != OK) { printError(ret, "Unable to copy values from bind buffer"); - if (!loadFlag) { + if (!loadFlag) { (*trans)->removeFromHasList(db_, tptr); - lMgr_->releaseLock(tptr); + lMgr_->releaseLock(tptr); } ((Chunk*)chunkPtr_)->free(db_, tptr); return ret; @@ -695,20 +839,19 @@ DbRetVal TableImpl::insertTuple() for (i = 0; i < numIndexes_ ; i++) { ret = insertIndexNode(*trans, indexPtr_[i], idxInfo[i], tptr); - if (ret != OK) { printError(ret, "Error in inserting to index"); break;} + if (ret != OK) { printError(ret, "Error in inserting to index %x", tptr); break;} } - if (i != numIndexes_ ) + if ( ret != OK) { for (int j = 0; j < i ; j++) { - printError(ErrWarning, "Deleting index node"); + printError(ErrWarning, "Undo:Deleting index node"); deleteIndexNode(*trans, indexPtr_[j], idxInfo[j], tptr); } if (!loadFlag) { - (*trans)->removeFromHasList(db_, tptr); - lMgr_->releaseLock(tptr); + (*trans)->removeFromHasList(db_, tptr); + lMgr_->releaseLock(tptr); } ((Chunk*)chunkPtr_)->free(db_, tptr); - printError(ret, "Unable to insert index node for tuple %x ", tptr); return ret; } } @@ -721,8 +864,8 @@ DbRetVal TableImpl::insertTuple() deleteIndexNode(*trans, indexPtr_[j], idxInfo[j], tptr); } if (!loadFlag) { - (*trans)->removeFromHasList(db_, tptr); - lMgr_->releaseLock(tptr); + (*trans)->removeFromHasList(db_, tptr); + lMgr_->releaseLock(tptr); } ((Chunk*)chunkPtr_)->free(db_, tptr); } @@ -736,12 +879,27 @@ DbRetVal TableImpl::deleteTuple() printError(ErrNotOpen, "Scan not open: No Current tuple"); return ErrNotOpen; } + if(isPkTbl){ + TableImpl *fkTbl =NULL; + ListIterator tblIter = tblFkList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + bool pkRec = isFkTableHasRecord(fkTbl->getName(),fkTbl); + if(pkRec){ + printError(ErrForeignKeyDelete, "A Relation Exists. Delete from child table first"); + return ErrForeignKeyDelete; + } + } + tblIter.reset(); + } DbRetVal ret = OK; - if (!loadFlag) { - ret = lMgr_->getExclusiveLock(curTuple_, trans); - if (OK != ret) + if (!loadFlag) { + //ret = lMgr_->getExclusiveLock(curTuple_, trans); + if (OK != tryExclusiveLock(curTuple_, trans)) { - printError(ret, "Could not get lock for the delete tuple %x", curTuple_); + printError(ret, "Could not get lock for the delete tuple %x", + curTuple_); return ErrLockTimeOut; } } @@ -757,9 +915,10 @@ DbRetVal TableImpl::deleteTuple() } if (i != numIndexes_ ) { + printError(ErrWarning, "Inserting back index node"); for (int j = 0; j < i ; j++) insertIndexNode(*trans, indexPtr_[j], idxInfo[j], curTuple_); - if (!loadFlag) { + if (!loadFlag) { lMgr_->releaseLock(curTuple_); (*trans)->removeFromHasList(db_, curTuple_); } @@ -767,9 +926,21 @@ DbRetVal TableImpl::deleteTuple() return ret; } } - ((Chunk*)chunkPtr_)->free(db_, curTuple_); if (!loadFlag) - ret = (*trans)->appendUndoLog(sysDB_, DeleteOperation, curTuple_, length_); + ret = (*trans)->appendUndoLog(sysDB_, DeleteOperation, curTuple_, 0); + if (ret != OK) { + printError(ret, "Unable to create undo log for %x ", curTuple_); + for (int j = 0; j < numIndexes_ ; j++) { + printError(ErrWarning, "Inserting back index node"); + insertIndexNode(*trans, indexPtr_[j], idxInfo[j], curTuple_); + } + if (!loadFlag) { + (*trans)->removeFromHasList(db_, curTuple_); + lMgr_->releaseLock(curTuple_); + } + } + ((Chunk*)chunkPtr_)->free(db_, curTuple_); + iter->prev(); return ret; } @@ -823,14 +994,29 @@ DbRetVal TableImpl::updateTuple() printError(ErrNotOpen, "Scan not open: No Current tuple"); return ErrNotOpen; } - DbRetVal ret = OK; - if (!loadFlag) { - ret = lMgr_->getExclusiveLock(curTuple_, trans); - if (OK != ret) - { - printError(ret, "Could not get lock for the update tuple %x", curTuple_); - return ErrLockTimeOut; + if(isFkTbl){ + TableImpl *fkTbl =NULL; + ListIterator tblIter = tblList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + bool pkRec = isPkTableHasRecord(fkTbl->getName(),fkTbl,false); + if(!pkRec){ + printError(ErrForeignKeyInsert, "Unable to insert into foreign Key table.Check PK table"); + return ErrForeignKeyInsert; + } } + tblIter.reset(); + } + + DbRetVal ret=OK; + if (!loadFlag) { + //ret = lMgr_->getExclusiveLock(curTuple_, trans); + if (OK != tryExclusiveLock(curTuple_, trans)) + { + printError(ret, "Could not get lock for the update tuple %x", curTuple_); + return ErrLockTimeOut; + } } if (NULL != indexPtr_) { @@ -844,8 +1030,8 @@ DbRetVal TableImpl::updateTuple() if (ret != OK) { if (!loadFlag) { - lMgr_->releaseLock(curTuple_); - (*trans)->removeFromHasList(db_, curTuple_); + lMgr_->releaseLock(curTuple_); + (*trans)->removeFromHasList(db_, curTuple_); } printError(ret, "Unable to update index node for tuple %x", curTuple_); return ret; @@ -854,7 +1040,13 @@ DbRetVal TableImpl::updateTuple() } if (!loadFlag) ret = (*trans)->appendUndoLog(sysDB_, UpdateOperation, curTuple_, length_); - if (ret != OK) return ret; + if (ret != OK) { + if (!loadFlag) { + lMgr_->releaseLock(curTuple_); + (*trans)->removeFromHasList(db_, curTuple_); + } + return ret; + } int addSize = 0; int iNullVal=iNullInfo; if (numFlds_ < 31){ @@ -886,8 +1078,15 @@ DbRetVal TableImpl::updateTuple() { addSize = os::align(numFlds_); //TODO::Do not do blind memcpy. It should OR each and every char + int i=0; + char *null=(char*)(curTuple_) + (length_-addSize); + while(i < numFlds_) { + if(cNullInfo[i]) null[i] |= cNullInfo[i]; + i++; + } //os::memcpy(((char*)(curTuple_) + (length_-addSize)), cNullInfo, addSize); + } return OK; } @@ -938,7 +1137,7 @@ DbRetVal TableImpl::copyValuesFromBindBuffer(void *tuplePtr, bool isInsert) } if (def->isNull_ && !def->isDefault_ && NULL == def->bindVal_ && isInsert) { - printError(ErrNullViolation, "NOT NULL constraint violation for field %s\n", def->fldName_); + printError(ErrNullViolation, "NOT NULL constraint violation for field %s", def->fldName_); return ErrNullViolation; } if (def->isDefault_ && NULL == def->bindVal_ && isInsert) @@ -957,7 +1156,7 @@ DbRetVal TableImpl::copyValuesFromBindBuffer(void *tuplePtr, bool isInsert) if (NULL != def->bindVal_) { if(!isInsert && isFldNull(fldpos)){clearNullBit(fldpos);} - strcpy((char*)colPtr, (char*)def->bindVal_); + strncpy((char*)colPtr, (char*)def->bindVal_, def->length_); *(((char*)colPtr) + (def->length_-1)) = '\0'; } else if (!def->isNull_ && !def->bindVal_ && isInsert) setNullBit(fldpos); @@ -1013,13 +1212,13 @@ DbRetVal TableImpl::copyValuesToBindBuffer(void *tuplePtr) } //-1 index not supported -DbRetVal TableImpl::insertIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple, bool loadFlag) +DbRetVal TableImpl::insertIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple) { CINDEX *iptr = (CINDEX*)indexPtr; DbRetVal ret = OK; printDebug(DM_Table, "Inside insertIndexNode type %d", iptr->indexType_); Index* idx = Index::getIndex(iptr->indexType_); - ret = idx->insert(this, tr, indexPtr, info, tuple, loadFlag); + ret = idx->insert(this, tr, indexPtr, info, tuple,loadFlag); return ret; } @@ -1031,19 +1230,41 @@ DbRetVal TableImpl::deleteIndexNode(Transaction *tr, void *indexPtr, IndexInfo * ret = idx->remove(this, tr, indexPtr, info, tuple, loadFlag); return ret; } -void TableImpl::printSQLIndexString() +void TableImpl::printSQLIndexString(FILE *fp, int fd) { + if (fp == NULL) fp = stdout; CatalogTableINDEXFIELD cIndexField(sysDB_); char fName[IDENTIFIER_LENGTH]; - char *fldName = fName; char idxName[IDENTIFIER_LENGTH]; + char *fldName = fName; DataType type; for (int i = 0; i < numIndexes_ ; i++) { CINDEX *iptr = (CINDEX*) indexPtr_[i]; sprintf(idxName,"%s_idx_Auto_increment",getName()); if(strcmp(iptr->indName_,idxName)==0){ continue; } - printf("CREATE INDEX %s on %s ( ", iptr->indName_, getName()); + if (Conf::config.useDurability()) { + struct Object obj; + strcpy(obj.name, iptr->indName_); + if (iptr->indexType_ == hashIndex) { + obj.type = hIdx; + obj.bucketChunk = ((Chunk *)iptr->chunkPtr_)->getFirstPage(); + obj.firstPage = ((Chunk *)iptr->hashNodeChunk_)->getFirstPage(); + obj.curPage = ((Chunk *)iptr->hashNodeChunk_)->getCurrentPage(); + } else if (iptr->indexType_ == treeIndex) { + obj.type = tIdx; + obj.firstPage = ((Chunk *)iptr->chunkPtr_)->getFirstPage(); + obj.curPage = ((Chunk *)iptr->chunkPtr_)->getCurrentPage(); + long nodes = ((Chunk *)iptr->chunkPtr_)->getTotalDataNodes(); + if(nodes) { + ChunkIterator cIter = ((Chunk *)iptr->chunkPtr_)->getIterator(); + obj.bucketChunk = cIter.nextElement(); + } else obj.bucketChunk = NULL; + } + void *buf = &obj; + write(fd, buf, sizeof(obj)); + } + fprintf(fp, "CREATE INDEX %s on %s ( ", iptr->indName_, getName()); FieldList fldList; cIndexField.getFieldInfo(iptr, fldList); FieldIterator fIter = fldList.getIterator(); @@ -1051,15 +1272,16 @@ void TableImpl::printSQLIndexString() while(fIter.hasElement()) { FieldDef *def = fIter.nextElement(); - if (firstFld) { printf(" %s ", def->fldName_); firstFld = false; } - else printf(" ,%s ", def->fldName_); + if (firstFld) { fprintf(fp, " %s ", def->fldName_); firstFld = false; } + else fprintf(fp, " ,%s ", def->fldName_); } - printf(" ) "); - if (iptr->indexType_ == hashIndex) printf(" HASH "); - else printf(" TREE "); - if (((HashIndexInfo*) idxInfo[i])->isUnique) printf(" UNIQUE"); - if(((HashIndexInfo*) idxInfo[i])->noOfBuckets != 1009 ) printf(" SIZE %d ",((HashIndexInfo*) idxInfo[i])->noOfBuckets ); - printf(";\n"); + fldList.removeAll(); + fprintf(fp, " ) "); + if (iptr->indexType_ == hashIndex) fprintf(fp, " HASH "); + else fprintf(fp, " TREE "); + if (((HashIndexInfo*) idxInfo[i])->isUnique) fprintf(fp, " UNIQUE"); + if(((HashIndexInfo*) idxInfo[i])->noOfBuckets != 1009 ) fprintf(fp, " SIZE %d ",((HashIndexInfo*) idxInfo[i])->noOfBuckets ); + fprintf(fp, ";\n"); } } @@ -1126,9 +1348,31 @@ List TableImpl::getFieldNameList() DbRetVal TableImpl::close() { if (iter) { iter->close(); delete iter; iter = NULL; } + TableImpl *fkTbl =NULL; + ListIterator tblIter = tblList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + fkTbl->close(); + } + tblList.reset(); + tblIter = tblFkList.getIterator(); + tblIter.reset(); + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + fkTbl->close(); + } + tblFkList.reset(); printDebug(DM_Database,"Closing table handle: %x", this); //table->unlock(); - delete pred_; + //delete pred_; + ListIterator pIter = predList.getIterator(); + while (pIter.hasElement()) + { + PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement(); + delete pImpl; + } + predList.reset(); delete this; logFinest(Conf::logger, "Closing Table"); return OK; @@ -1139,10 +1383,7 @@ DbRetVal TableImpl::closeScan() //do not throw scan not open error //this function will be called by table handle if (iter) { - // iter->reset(); - //PRABA::TEMP::otherwise fails.check with kishor - delete iter; - iter = NULL; + iter->close(); } return OK; } @@ -1227,9 +1468,25 @@ bool TableImpl::pushPredicate(Predicate *pred) } return ret; } + +void TableImpl::setCondition(Condition *p) +{ + isPlanCreated = false; + ListIterator pIter = predList.getIterator(); + while (pIter.hasElement()) + { + PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement(); + delete pImpl; + } + predList.reset(); + + if (p) pred_ = p->getPredicate(); else pred_ = NULL; +} + void TableImpl::setPredicate(Predicate *pred) { if (NULL == pred_) { pred_ = pred; return; } + Predicate *curPred = pred_; PredicateImpl *newPred = new PredicateImpl(); newPred->setTerm(curPred, OpAnd, pred); @@ -1249,4 +1506,249 @@ void TableImpl::printPlan(int space) if (pred) pred->print(space+2); printf("%s \n", spaceBuf); } +void TableImpl::printSQLForeignString() +{ + DbRetVal rv=OK; + FieldNameList pkFieldList,fkFieldList; + void *tPkptr =NULL; + void *tFkptr = NULL; + void *chunkPk = NULL; + CatalogTableTABLE cTable(sysDB_); + TableImpl *fkTbl =NULL; + ListIterator tblIter = tblList.getIterator(); + tblIter.reset(); + int firstFK=true; + while (tblIter.hasElement()){ + fkTbl = (TableImpl *) tblIter.nextElement(); + rv = cTable.getChunkAndTblPtr(fkTbl->getName(), chunkPk, tPkptr); + if ( OK != rv){return ;} + rv = cTable.getChunkAndTblPtr(getName(), chunkPk, tFkptr); + if ( OK != rv){return ;} + CatalogTableFK cFk(sysDB_); + rv = cFk.getPkFkFieldInfo(tPkptr,tFkptr,pkFieldList,fkFieldList); + if ( OK != rv){return;} + pkFieldList.resetIter(); + fkFieldList.resetIter(); + char *fldName = NULL; + bool firstField=true; + if(!firstFK) printf(", "); + printf(", FOREIGN KEY ( "); + while((fldName = fkFieldList.nextFieldName())!= NULL) + { + if (firstField) { + printf("%s",fldName); + firstField=false; + } + else + printf(",%s",fldName); + } + printf(" ) REFERENCES %s ( ",fkTbl->getName()); + firstField=true; + while((fldName = pkFieldList.nextFieldName())!= NULL) + { + if (firstField) { + printf("%s",fldName); + firstField=false; + } + else + printf(",%s",fldName); + } + printf(" )"); + firstFK=true; + pkFieldList.removeAll(); + fkFieldList.removeAll(); + } + return; +} +bool TableImpl::isPkTableHasRecord(char *pkTableName, TableImpl *fkTbl,bool isInsert) +{ + DbRetVal rv=OK; + bool isRecExist=false; + FieldNameList pkFieldList,fkFieldList; + void *tPkptr =NULL; + void *tFkptr = NULL; + void *chunkPk = NULL; + CatalogTableTABLE cTable(sysDB_); + rv = cTable.getChunkAndTblPtr(pkTableName, chunkPk, tPkptr); + if ( OK != rv){return false;} + rv = cTable.getChunkAndTblPtr(getName(), chunkPk, tFkptr); + if ( OK != rv){return false;} + CatalogTableFK cFk(sysDB_); + rv = cFk.getPkFkFieldInfo(tPkptr,tFkptr,pkFieldList,fkFieldList); + if ( OK != rv){return false;} + int totFld = pkFieldList.size(); + Condition *condition = new Condition[totFld]; + char *pkFldName = NULL; + char *fkFldName = NULL; + FieldDef *def=NULL; + int i=0; + pkFieldList.resetIter(); + fkFieldList.resetIter(); + void *val=NULL; + while((pkFldName = pkFieldList.nextFieldName())!= NULL) + { + fkFldName = fkFieldList.nextFieldName(); + FieldIterator fIter = fldList_.getIterator(); + while (fIter.hasElement()) + { + def = fIter.nextElement(); + if (strcmp(def->fldName_, fkFldName) == 0) + { + if(NULL == def->bindVal_ && isInsert) { return true; } + if(NULL == def->bindVal_) { + val = (char*)curTuple_+ def->offset_; + } else { + val = def->bindVal_; + } + if(def->type_==typeString) + condition[i].setTerm(pkFldName,OpEquals,&val); + else + condition[i].setTerm(pkFldName,OpEquals,val); + i++; + break; + } + } + } + pkFieldList.removeAll(); + fkFieldList.removeAll(); + Condition *cond = NULL; + if(i == 0 && !isInsert)return true; + if( i > 1){ + cond = new Condition[i-1]; + int totcon = i; + i=0; + int j=0; + for(j=0;jsetCondition(&cond[j-1]); + } + else{ + fkTbl->setCondition(&condition[i-1]); + } + fkTbl->execute(); + if(fkTbl->fetch()){ + fkTbl->closeScan(); + delete[] cond; + delete[] condition; + return true; + } + delete[] cond; + delete[] condition; + return false; +} + +bool TableImpl::isFkTableHasRecord(char *pkTableName, TableImpl *fkTbl) +{ + DbRetVal rv=OK; + FieldNameList pkFieldList,fkFieldList; + void *tPkptr =NULL; + void *tFkptr = NULL; + void *chunkPk = NULL; + CatalogTableTABLE cTable(sysDB_); + rv = cTable.getChunkAndTblPtr(getName(), chunkPk, tPkptr); + if ( OK != rv){return false;} + rv = cTable.getChunkAndTblPtr(pkTableName, chunkPk, tFkptr); + if ( OK != rv){return false;} + CatalogTableFK cFk(sysDB_); + rv = cFk.getPkFkFieldInfo(tPkptr,tFkptr,pkFieldList,fkFieldList); + if ( OK != rv){return false;} + int totFld = pkFieldList.size(); + Condition *condition = new Condition[totFld]; + char *pkFldName = NULL; + char *fkFldName = NULL; + FieldDef *def=NULL; + int i=0; + pkFieldList.resetIter(); + fkFieldList.resetIter(); + while((pkFldName = pkFieldList.nextFieldName())!= NULL) + { + fkFldName = fkFieldList.nextFieldName(); + FieldIterator fIter = fldList_.getIterator(); + while (fIter.hasElement()) + { + def = fIter.nextElement(); + void *val = (char*)curTuple_+ def->offset_; + if (strcmp(def->fldName_, pkFldName) == 0) + { + if(def->type_==typeString) + condition[i].setTerm(fkFldName,OpEquals,&val);//((char*)curTuple_+def->offset_)); + else + condition[i].setTerm(fkFldName,OpEquals,val);//((char*)curTuple_+def->offset_)); + i++; + break; + } + } + } + pkFieldList.removeAll(); + fkFieldList.removeAll(); + if(i == 0 )return true; + Condition *cond = new Condition[i-1]; + i=0; + int j=0; + for(j=0;jsetCondition(&condition[totFld-1]); + else + fkTbl->setCondition(&cond[j-1]); + fkTbl->execute(); + if(fkTbl->fetch()){ + fkTbl->closeScan(); + delete[] cond; + delete[] condition; + return true; + } + delete[] cond; + delete[] condition; + return false; +} +DbRetVal TableImpl::compact() +{ + DbRetVal rv=OK; + int ret =((Chunk*)chunkPtr_)->compact(db_->procSlot); + if(ret!=0){ + return ErrLockTimeOut; + } + if (NULL != indexPtr_) + { + int i; + //it has index + for (i = 0; i < numIndexes_ ; i++) + { + rv = compactIndexNode(indexPtr_[i]); + if (rv != OK) { printError(rv, "Error in compacting index Node"); break;} + } + } + return rv; +} +DbRetVal TableImpl::compactIndexNode( void *indexPtr) +{ + CINDEX *iptr = (CINDEX*)indexPtr; + int ret1=0; + printDebug(DM_Table, "Inside insertIndexNode type %d", iptr->indexType_); + if( hashIndex == (iptr->indexType_) ) + { + ret1 =((Chunk*)iptr->hashNodeChunk_)->compact(db_->procSlot); + if(ret1!=0){ + return ErrLockTimeOut; + } + }else + { + ret1 =((Chunk*)iptr->chunkPtr_)->compact(db_->procSlot); + if(ret1!=0){ + return ErrLockTimeOut; + } + } + return OK; +} diff --git a/src/storage/Transaction.cxx b/src/storage/Transaction.cxx index 296d420e..6d651d22 100644 --- a/src/storage/Transaction.cxx +++ b/src/storage/Transaction.cxx @@ -20,15 +20,30 @@ #include #include +//Code assumes that only one thread can work on a transaction DbRetVal Transaction::insertIntoHasList(Database *sysdb, LockHashNode *node) { //allocate lock node Chunk *chunk = sysdb->getSystemDatabaseChunk(TransHasTableId); DbRetVal rv = OK; - TransHasNode *hasNode = (TransHasNode*)chunk->allocate(sysdb, &rv); + TransHasNode *hasNode = NULL; //(TransHasNode*)chunk->allocate(sysdb, &rv); + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) + { + rv = OK; + hasNode= (TransHasNode*)chunk->allocate(sysdb, &rv); + if (hasNode !=NULL) break; + if (rv != ErrLockTimeOut) + { + printError(rv, "Unable to allocate trans has node"); + return rv; + } + tries++; + } if (NULL == hasNode) { - printError(rv, "Could not allocate Lock node"); + printError(rv, "Could not allocate Trans has node after %d retry", tries); return rv; } printDebug(DM_Transaction, "insertIntoHasList new TransHasNode created:%x", @@ -55,7 +70,7 @@ DbRetVal Transaction::removeFromHasList(Database *sysdb, void *tuple) TransHasNode *iter = hasLockList_, *prev = hasLockList_; if (NULL == iter) { - printError(ErrNotFound, "There are no tuple lock in has list."); + printError(ErrNotFound, "Fatal:HasList is empty"); return ErrNotFound; } while (iter != NULL) @@ -70,7 +85,17 @@ DbRetVal Transaction::removeFromHasList(Database *sysdb, void *tuple) prev = iter; iter = iter->next_; } - printError(ErrNotFound, "There are no tuple lock in has list."); + printStackTrace(); + printError(ErrNotFound, "Fatal:There is no tuple lock in has list for tuple:%x", tuple); + //TEMP::for debugging + iter=hasLockList_; + int cnt=0; + while (iter != NULL) + { + printError(ErrWarning, "Element in hasList: %d %x: %x:%d\n", cnt, iter->node_, iter->node_->ptrToTuple_ , *(int*)iter->node_->ptrToTuple_); + cnt++; + iter = iter->next_; + } return ErrNotFound; } @@ -80,12 +105,13 @@ DbRetVal Transaction::releaseAllLocks(LockManager *lockManager_) Database *sysdb =lockManager_->systemDatabase_; Chunk *chunk = sysdb->getSystemDatabaseChunk(TransHasTableId); TransHasNode *iter = hasLockList_, *prev; + DbRetVal rv = OK; while (NULL != iter) { prev = iter; iter = iter->next_; printDebug(DM_Transaction, "Releasing lock %x",prev->node_->ptrToTuple_); - lockManager_->releaseLock(prev->node_->ptrToTuple_); + rv = lockManager_->releaseLock(prev->node_->ptrToTuple_); chunk->free(sysdb, prev); } hasLockList_ = NULL; @@ -108,7 +134,7 @@ DbRetVal Transaction::appendUndoLog(Database *sysdb, OperationType type, DbRetVal rv =OK; UndoLogInfo *logInfo = createUndoLog(sysdb, type, data, size, &rv); if (logInfo == NULL) return rv; - os::memcpy((char*)logInfo + sizeof(UndoLogInfo), data, size); + if (size) os::memcpy((char*)logInfo + sizeof(UndoLogInfo), data, size); addAtBegin(logInfo); printDebug(DM_Transaction, "creating undo log and append %x optype:%d", logInfo, type); @@ -140,15 +166,42 @@ DbRetVal Transaction::appendLogicalHashUndoLog(Database *sysdb, OperationType ty printDebug(DM_Transaction, "creating logical undo log and append %x optype:%d", logInfo, type); return rv; } +DbRetVal Transaction::appendLogicalTreeUndoLog(Database *sysdb, OperationType type, void *data, size_t size) +{ + DbRetVal rv = OK; + TreeUndoLogInfo *hInfo = (TreeUndoLogInfo *) data; + UndoLogInfo *logInfo = createUndoLog(sysdb, type, hInfo->tuple_, size, &rv); + if (logInfo == NULL) return rv; + memcpy((char*)logInfo + sizeof(UndoLogInfo), data, sizeof(TreeUndoLogInfo)); + addAtBegin(logInfo); + printDebug(DM_Transaction, "creating logical undo log and append %x optype:%d", logInfo, type); + return rv; +} UndoLogInfo* Transaction::createUndoLog(Database *sysdb, OperationType type, void *data, size_t size, DbRetVal *rv) { Chunk *chunk = sysdb->getSystemDatabaseChunk(UndoLogTableID); - UndoLogInfo *logInfo = (UndoLogInfo*)chunk->allocate(sysdb, - size + sizeof(UndoLogInfo), rv); + int reqSize = size + sizeof(UndoLogInfo); + UndoLogInfo *logInfo = NULL; + int tries=0; + int totalTries = Conf::config.getMutexRetries(); + while (tries < totalTries) + { + *rv = OK; + logInfo= (UndoLogInfo*)chunk->allocate(sysdb, reqSize, rv); + if (logInfo !=NULL) break; + if (*rv != ErrLockTimeOut) + { + printError(*rv, "Unable to allocate undo log"); + return NULL; + } + //printError (ErrWarning, Undo Log Alloc: LockTimeOut Retry:%d", tries); + tries++; + } + if (logInfo == NULL) { - printError(*rv, "Unable to allocate undo log record\n"); + printError(*rv, "Unable to allocate undo log record after %d retries", tries); return NULL; } logInfo->opType_ = type; @@ -253,7 +306,7 @@ DbRetVal Transaction::applyUndoLogs(Database *sysdb) { case InsertOperation: { - int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1); + int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1); if (*isUsed == 0) { printError(ErrSysFatal, "Fatal: Row is already not in use"); } @@ -264,7 +317,6 @@ DbRetVal Transaction::applyUndoLogs(Database *sysdb) sizeof(UndoLogInfo), logInfo->size_); break; } - break; case DeleteOperation: { int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1); @@ -272,15 +324,15 @@ DbRetVal Transaction::applyUndoLogs(Database *sysdb) printError(ErrSysFatal, "Fatal: Row is already in use"); } *isUsed = 1; - os::memcpy(logInfo->ptrToTuple_, (char*) logInfo + - sizeof(UndoLogInfo), logInfo->size_); + /*os::memcpy(logInfo->ptrToTuple_, (char*) logInfo + + sizeof(UndoLogInfo), logInfo->size_);*/ break; } case UpdateOperation: { int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1); if (*isUsed == 0) { - printError(ErrSysFatal, "Fatal: Row is not in use"); + printError(ErrSysFatal, "Fatal: Row is not in use during update rollback"); } os::memcpy(logInfo->ptrToTuple_, (char*) logInfo + sizeof(UndoLogInfo), logInfo->size_); @@ -298,6 +350,14 @@ DbRetVal Transaction::applyUndoLogs(Database *sysdb) HashIndex::insertLogicalUndoLog(sysdb, (char *)logInfo + sizeof(UndoLogInfo)); break; + case InsertTreeIndexOperation: + TreeIndex::deleteLogicalUndoLog(sysdb, (char *)logInfo + + sizeof(UndoLogInfo)); + break; + case DeleteTreeIndexOperation: + TreeIndex::insertLogicalUndoLog(sysdb, (char *)logInfo + + sizeof(UndoLogInfo)); + break; } chunk->free(sysdb, logInfo); } diff --git a/src/storage/TransactionManager.cxx b/src/storage/TransactionManager.cxx index dd8415a7..654208ec 100644 --- a/src/storage/TransactionManager.cxx +++ b/src/storage/TransactionManager.cxx @@ -54,7 +54,7 @@ void TransactionManager::printDebugInfo(Database *sysdb) printf("\n"); for (; i < Conf::config.getMaxProcs(); i++) { - if (iter->status_ == TransNotUsed) freeCount++; + if (iter->status_ == TransNotUsed || iter->status_ == TransReserved) freeCount++; else { usedCount++; @@ -83,12 +83,20 @@ DbRetVal TransactionManager::startTransaction(LockManager *lMgr, IsolationLevel Transaction *trans = ProcessManager::getThreadTransaction(sysdb->procSlot); if (NULL != trans) { - if (trans->status_ != TransNotUsed) return ErrAlready; - else { + // + if (trans->status_ != TransReserved) return ErrAlready; + else if (trans->status_ == TransReserved) + { //the previous transaction shall be used again - trans->status_ = TransRunning; + //trans->status_ = TransRunning; + if ( 0 != Mutex::CAS((int*)&trans->status_, + TransReserved, TransRunning)) { + printError(ErrLockTimeOut, "unable to get lock to reuse the transaction"); + return ErrLockTimeOut; + } trans->isoLevel_ = level; printDebug(DM_Transaction, "Using the same transaction slot\n"); + logFinest(Conf::logger, "Transaction Start:Reusing :%x", trans); return OK; } @@ -118,10 +126,17 @@ DbRetVal TransactionManager::startTransaction(LockManager *lMgr, IsolationLevel //Make this free slot, as the current transaction and //set the state trans = iter; - trans->status_ = TransRunning; + //trans->status_ = TransRunning; + if ( 0 != Mutex::CAS((int*)&trans->status_ , + TransNotUsed, TransRunning)) { + printError(ErrLockTimeOut, "Unable to start transaction. Timeout. Retry.."); + sysdb->releaseTransTableMutex(); + return ErrLockTimeOut; + } trans->isoLevel_ = level; - sysdb->releaseTransTableMutex(); ProcessManager::setThreadTransaction(trans, sysdb->procSlot); + sysdb->releaseTransTableMutex(); + logFinest(Conf::logger, "Transaction Start:Using :%x", trans); return OK; } @@ -135,52 +150,36 @@ DbRetVal TransactionManager::commit(LockManager *lockManager) { Database *sysdb = lockManager->systemDatabase_; Transaction *trans = ProcessManager::getThreadTransaction(sysdb->procSlot); + DbRetVal rv = OK; if (NULL == trans) { printError(ErrNotOpen, "No transaction started for this procSlot %d", sysdb->procSlot); return ErrNotOpen; } - DbRetVal rv = sysdb->getTransTableMutex(); - if (OK != rv) - { - printError(rv, "Unable to acquire transtable mutex"); - return rv; - } - - if (trans->status_ != TransRunning) - { - sysdb->releaseTransTableMutex(); - printError(ErrBadCall, "Transaction is not in running state %d\n", trans->status_); - return ErrBadCall; + rv = trans->releaseAllLocks(lockManager); + if (rv != OK) { + printError(ErrSysInternal, "Fatal:Unable to release all the locks\n"); } - trans->status_ = TransCommitting; - sysdb->releaseTransTableMutex(); - - trans->releaseAllLocks(lockManager); if(NULL != trans->waitLock_) { - printError(ErrSysInternal, "Trans WaitLock is not null\n"); - return ErrSysInternal; + printError(ErrSysInternal, "Fatal:Trans WaitLock is not null\n"); } - //TODO::flush all redo logs to disk - //TODO::remove all the logs in memory trans->removeUndoLogs(sysdb); - rv = sysdb->getTransTableMutex(); - if (OK != rv) + if ( 0 != Mutex::CAS((int*)&trans->status_, TransRunning, TransReserved)) { - printError(rv, "Unable to acquire transtable mutex"); - return rv; + printError(ErrSysFatal, "Transaction state corrupted %d\n", trans->status_); + return ErrSysFatal; } - trans->status_ = TransNotUsed; - sysdb->releaseTransTableMutex(); printDebug(DM_Transaction, "Committed transaction:%x",trans); + logFinest(Conf::logger, "Transaction Committed:%x", trans); return OK; } DbRetVal TransactionManager::rollback(LockManager *lockManager, Transaction *t) { Database *sysdb = lockManager->systemDatabase_; - Transaction *trans; + Transaction *trans = NULL; + DbRetVal rv = OK; if (t == NULL) trans = ProcessManager::getThreadTransaction(sysdb->procSlot); else @@ -189,41 +188,32 @@ DbRetVal TransactionManager::rollback(LockManager *lockManager, Transaction *t) { return OK; } - DbRetVal rv= sysdb->getTransTableMutex(); - if (OK != rv) - { - printError(rv, "Unable to acquire transtable mutex"); - return rv; - } if (trans->status_ != TransRunning) { - sysdb->releaseTransTableMutex(); + //sysdb->releaseTransTableMutex(); //will be called during connection disconnect without starting transaction. return OK; } - trans->status_ = TransAborting; - sysdb->releaseTransTableMutex(); trans->applyUndoLogs(sysdb); - //TODO::remove all the logs in memory - trans->releaseAllLocks(lockManager); + rv = trans->releaseAllLocks(lockManager); + if (rv != OK) { + printError(ErrSysInternal, "Fatal:Unable to release all the locks"); + } if(NULL != trans->waitLock_) { - printError(ErrSysInternal, "Trans waitlock is not null"); - return ErrSysInternal; + printError(ErrSysInternal, "Fatal:Trans waitlock is not null"); + //return ErrSysInternal; } - rv = sysdb->getTransTableMutex(); - if (OK != rv) + //trans->status_ = TransNotUsed; + if ( 0 != Mutex::CAS((int*)&trans->status_, TransRunning, TransReserved)) { - //nothing can be done.. go ahead and set it. - //no harm. parallel starttransaction will miss this slot. thats ok - //as it is not leak + printError(ErrSysFatal, "Fatal:Unable to abort transaction %d\n", trans->status_); + return ErrSysFatal; } - trans->status_ = TransNotUsed; - sysdb->releaseTransTableMutex(); printDebug(DM_Transaction, "Aborted transaction:%x",trans); - + logFinest(Conf::logger, "Transaction Aborted:%x", trans); return OK; } diff --git a/src/storage/TreeIndex.cxx b/src/storage/TreeIndex.cxx index 56a86d38..a334ecb7 100644 --- a/src/storage/TreeIndex.cxx +++ b/src/storage/TreeIndex.cxx @@ -21,31 +21,170 @@ #include #include #include +DbRetVal TreeIndex::deleteLogicalUndoLog(Database *sysdb, void *data) +{ + DbRetVal rv = OK; + TreeUndoLogInfo *tUndoInfo = (TreeUndoLogInfo *) data; + Database *db = new Database(); + db->setMetaDataPtr((DatabaseMetaData*) tUndoInfo->metaData_); + db->setProcSlot(sysdb->procSlot); + CINDEX *iptr = (CINDEX*) tUndoInfo->cIndex_; + TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; + //HashIndexInfo populated here + HashIndexInfo *info = new HashIndexInfo(); + info->indexPtr = (char *)iptr; + info->noOfBuckets = iptr->noOfBuckets_; + info->isUnique = iptr->isUnique_; + info->type = ((CFIELD*)(((CINDEXFIELD*)(iptr->fstIndFld_))->fieldPtr))->type_; + info->fldOffset = ((CFIELD*)(((CINDEXFIELD*)(iptr->fstIndFld_))->fieldPtr))->offset_; + info->indType = iptr->indexType_; + TreeIndex *treeInd = (TreeIndex*)Index::getIndex(iptr->indexType_); + int pos=0; + TreeNode *fltnode = start->locateNode(db, start, tUndoInfo->tuple_, info,rv); + if (NULL == fltnode){ + delete db; + delete info; + return rv; + } //First Level Node Not found + TreeNode *iter = start->locateNodeFromFirstLevel(fltnode, info, tUndoInfo->tuple_, &pos); + if (NULL == iter){ + fltnode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + delete db; + delete info; + return OK; + } //element not found + rv = treeInd->removeElement(db, iter, tUndoInfo->tuple_, info); + if( rv != OK ){ + fltnode->mutex_.releaseShareLock(db->procSlot); + printError(rv, "Romove from TreeNode Failed "); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + delete db; + delete info; + return rv; + } + if(0 == iter->noElements_) + { + treeInd->removeNode(db, tUndoInfo->cIndex_, fltnode,iter, pos); + }else { fltnode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + } + delete db; + delete info; + return rv; +} +DbRetVal TreeIndex::insertLogicalUndoLog(Database *sysdb, void *data) +{ + DbRetVal rc = OK; + TreeUndoLogInfo *tUndoInfo = (TreeUndoLogInfo *) data; + Database *db = new Database(); + db->setMetaDataPtr((DatabaseMetaData*) tUndoInfo->metaData_); + db->setProcSlot(sysdb->procSlot); + CINDEX *iptr = (CINDEX*) tUndoInfo->cIndex_;//CINDEX + //HashIndexInfo populated here + HashIndexInfo *info = new HashIndexInfo(); + info->indexPtr = (char *)iptr; + info->noOfBuckets = iptr->noOfBuckets_; + info->isUnique = iptr->isUnique_; + info->type = ((CFIELD*)(((CINDEXFIELD*)(iptr->fstIndFld_))->fieldPtr))->type_; + info->fldOffset = ((CFIELD*)(((CINDEXFIELD*)(iptr->fstIndFld_))->fieldPtr))->offset_; + info->indType = iptr->indexType_; + TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; + int offset = info->fldOffset; + DataType type = info->type; + void *keyPtr =(void*)((char*)tUndoInfo->tuple_ + offset); + if (start == NULL) + { + //Currently Nodes are not deleted + printDebug(DM_TreeIndex, "Inside if - start=NULL create First level "); + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); + if (tnode == NULL) + { + printError(rc, "Exit TreeNode::Insert - 1 tnode=NULL"); + delete info; + return rc; + } + tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); + tnode->min_ = tUndoInfo->tuple_; + tnode->max_ = tUndoInfo->tuple_; + tnode->noElements_ =1; + tnode->next_ = NULL; + tnode->prev_ = NULL; + tnode->balance_ = 0; + char **rec = (char**)((char*) tnode + sizeof(TreeNode)); + //printDebug(DM_TreeIndex, "\nStoring first record at %x\n", rec); + *rec = (char*) tUndoInfo->tuple_; + + printDebug(DM_TreeIndex, "Inside if - start=NULL create second level "); + Chunk *ftchunk = (Chunk*) iptr->chunkPtr_; + TreeNode *ftnode = (TreeNode*) ftchunk->allocate(db, &rc); + if (NULL == ftnode) + { + printError(rc, "Unable to allocate tree node"); + chunk->free(db, tnode); + delete info; + return rc; + } + ftnode->mutex_.init(); + strcpy(ftnode->mutex_.name, "I-Tree"); + ftnode->min_= NULL; + ftnode->max_ = NULL; + ftnode->noElements_ =1; + ftnode->next_ = NULL; + ftnode->prev_ = NULL; + ftnode->balance_ = 0; + char **tn=(char**)((char*) ftnode+sizeof(TreeNode)); + *tn = (char*)tnode; + //iptr->hashNodeChunk_ = ftnode; + if( 0 !=Mutex::CASL((long*)&iptr->hashNodeChunk_, 0, (long)ftnode)) + { + printError(ErrLockTimeOut, "Lock timeout..retry"); + chunk->free(db, tnode); + chunk->free(db, ftnode); + delete info; + return ErrLockTimeOut; + } + }else { + rc = start->insert(db, info, iptr, tUndoInfo->tuple_); + if (rc != OK){ + delete db; delete info; + printError(rc, "Error in tree node insertion\n"); + return rc; + } + } + delete db; + delete info; + return rc; +} DbRetVal TreeIndex::insert(TableImpl *tbl, Transaction *tr, void *indexPtr, IndexInfo *indInfo, void *tuple, bool undoFlag) { - printDebug(DM_TreeIndex, "\nInside TreeNode::Insert - 1"); HashIndexInfo *info = (HashIndexInfo*) indInfo; CINDEX *iptr = (CINDEX*)indexPtr; TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; DbRetVal rc = OK; int offset = info->fldOffset; DataType type = info->type; - printDebug(DM_TreeIndex, "Inserting tree index node for %s", iptr->indName_); void *keyPtr =(void*)((char*)tuple + offset); + //TreeUndoLogInfo Populated here + TreeUndoLogInfo hInfo; + hInfo.metaData_ = tbl->db_->getMetaDataPtr(); + hInfo.tuple_ = tuple; + hInfo.cIndex_= indexPtr; if (start == NULL) { - //TODO::there is chance that two threads can insert first node at - //same time causing the first tree node to leak. - printDebug(DM_TreeIndex, "\nInside if - start=NULL"); + printDebug(DM_TreeIndex, "Inside if - start=NULL create First level "); Chunk *chunk = (Chunk*) iptr->chunkPtr_; TreeNode *tnode = (TreeNode*) chunk->allocate(tbl->db_, &rc); if (tnode == NULL) { - printDebug(DM_TreeIndex, "\nExit TreeNode::Insert - 1 tnode=NULL"); + printError(rc, "Unable to allocate tree node"); return rc; } tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); tnode->min_ = tuple; tnode->max_ = tuple; tnode->noElements_ =1; @@ -53,459 +192,979 @@ DbRetVal TreeIndex::insert(TableImpl *tbl, Transaction *tr, void *indexPtr, Inde tnode->prev_ = NULL; tnode->balance_ = 0; char **rec = (char**)((char*) tnode + sizeof(TreeNode)); - printDebug(DM_TreeIndex, "\nStoring first record at %x\n", rec); + //printDebug(DM_TreeIndex, "\nStoring first record at %x\n", rec); *rec = (char*) tuple; - iptr->hashNodeChunk_ = tnode; + + printDebug(DM_TreeIndex, "Inside if - start=NULL create second level "); + TreeNode *ftnode = (TreeNode*) chunk->allocate(tbl->db_, &rc); + if (NULL == ftnode) + { + printError(rc, "Unable to allocate tree node"); + chunk->free(tbl->db_, tnode); + return rc; + } + ftnode->mutex_.init(); + strcpy(ftnode->mutex_.name, "I-Tree"); + ftnode->min_= NULL; + ftnode->max_ = NULL; + ftnode->noElements_ =1; + ftnode->next_ = NULL; + ftnode->prev_ = NULL; + ftnode->balance_ = 0; + //TODO: Handle when two process try to allocate first node + char **tn=(char**)((char*) ftnode + sizeof(TreeNode)); + *tn = (char*)tnode; + if( 0 !=Mutex::CASL((long*)&iptr->hashNodeChunk_, 0, (long)ftnode)) + { + printError(ErrLockTimeOut, "Lock timeout..retry"); + chunk->free(tbl->db_, tnode); + chunk->free(tbl->db_, ftnode); + return ErrLockTimeOut; + } + }else { rc = start->insert(tbl->db_, indInfo, indexPtr, tuple); - if (rc != OK) - printError(rc, "Error in tree node insertion\n"); + if (rc != OK){ + printError(rc, "Error in tree node insertion for tuple %x", tuple); + return rc; + } } + //start->displayAll(offset); + if(!undoFlag){ + rc = tr->appendLogicalTreeUndoLog(tbl->sysDB_, InsertTreeIndexOperation, &hInfo, sizeof(TreeUndoLogInfo)); + if (rc !=OK) + { + //Reverse back + int pos=0; + start = (TreeNode*) iptr->hashNodeChunk_; + TreeNode *fltnode = start->locateNode(tbl->sysDB_,start, tuple, indInfo,rc); + if (NULL == fltnode) + { + return rc; + } //First Level Node Not found + TreeNode *iter = start->locateNodeFromFirstLevel(fltnode, indInfo, tuple, &pos); + if (NULL == iter){ + fltnode->mutex_.releaseShareLock(tbl->sysDB_->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + return OK; + } //element not found + rc = removeElement(tbl->getDB(), iter, tuple, info); + if( rc != OK ) + { + fltnode->mutex_.releaseShareLock(tbl->sysDB_->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + printError(rc, "Romove from TreeNode Failed "); + return rc; + } + if(0 == iter->noElements_) + { + removeNode(tbl->getDB(), indexPtr, fltnode,iter, pos); + }else + { + fltnode->mutex_.releaseShareLock(tbl->sysDB_->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + } + + printError(ErrSysFatal, "Unable to append undo lock for TreeInsert\n"); + return rc; - printDebug(DM_TreeIndex, "\nExit TreeNode::Insert - 1"); + } + } return rc; } -void TreeNode::displayAll(int fldOffset) + +long long TreeNode::getTotalElements() { - TreeNode *iter = this; - int loc=0; - while(iter->prev_) - { - printf("PRABA::ITERATING\n"); - iter = iter->prev_; - } - printf("\nDISPLAY NODES:START\n"); + DbRetVal rv=OK; + TreeNode *iter = (TreeNode *) this ; + TreeNode *tnode=NULL; + long long totalElement=0; while(iter != NULL) { - char **rec = (char**)((char*) iter + sizeof(TreeNode)); - printf("\n>>>"); - for(loc=0;locnoElements_;loc++) + for(int i=0;i< iter->noElements_;i++) { - printf("%d,",*((int*)((char*) *(rec + loc )+fldOffset))); + tnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode))+ ((i)*sizeof(void *)))); + totalElement += tnode->noElements_; } - iter = iter->next_; + iter=iter->next_; } - printf("-----\n"); - printf("DISPLAY NODES:END\n"); + return totalElement; } -void TreeNode::displayAll(IndexInfo *indInfo, void *indexPtr) +void TreeNode::displayAll(int fldOffset) { - HashIndexInfo *info = (HashIndexInfo*) indInfo; - CINDEX *iptr = (CINDEX*)indexPtr; - TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; - int offset = info->fldOffset; - DataType type = info->type; - int noOfBuckets = info->noOfBuckets; - TreeNode *iter =start; - int loc=0; - while(iter->prev_) + DbRetVal rv=OK; + TreeNode *iter = (TreeNode *) this ; + TreeNode *tnode=NULL; + TreeNode *prev = iter; + bool result = false; + printf("\n"); + while(iter != NULL) { - iter = iter->prev_; + tnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode))+ ((iter->noElements_-1)*sizeof(void *)))); + char *record = ((char*)tnode->max_)+ fldOffset; + TreeNode *needremovetnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode)))); + printf(" %d / %d \n",*(int*)record,*(int*)((char*)needremovetnode->min_)+ fldOffset); + for(int i=0;i< iter->noElements_;i++) + { + tnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode))+ ((i)*sizeof(void *)))); + printf(" %d Min:%d Max:%d\n ",i, *(int*)tnode->min_, *(int*)tnode->max_); + char **rec= (char**)((char*)tnode + sizeof(TreeNode)); + for(int j=0; j < tnode->noElements_; j++){ + printf("%d,",*((int*)((char*) *(rec + j )+fldOffset))); + } + printf("\n"); + + } + iter=iter->next_; } - printf("\nDISPLAY NODES:START\n"); + printf("\n"); +} +void TreeNode::displayAll() +{ + DbRetVal rv=OK; + TreeNode *iter = (TreeNode *) this ; + TreeNode *tnode=NULL; + long long totalElement=0; + int count=1; + printf("\n"); while(iter != NULL) { - char **rec = (char**)((char*) iter + sizeof(TreeNode)); - printf("\n>>>"); - for(loc=0;locnoElements_;loc++) + printf(" %d %d %x %d \n", count, iter->noElements_, &iter->mutex_, iter->mutex_.getLockVal()); + for(int i=0;i< iter->noElements_;i++) { - printf("%d,",*((int*)((char*) *(rec + loc )+info->fldOffset))); + tnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode))+ ((i)*sizeof(void *)))); + printf(" %d %x %d \n",i, tnode->noElements_, &tnode->mutex_, tnode->mutex_.getLockVal()); + totalElement += tnode->noElements_; } - iter = iter->next_; + iter=iter->next_; + count++; } - printf("-----\n"); - printf("DISPLAY NODES:END\n"); + printf(" %lld \n",totalElement); + printf("\n"); } -DbRetVal TreeNode::insert(Database *db, IndexInfo *indInfo, void *indexPtr, void *tuple) + +DbRetVal TreeNode::insertNodeIntoFirstLevel(Database * db, IndexInfo * indInfo, void* indexPtr, TreeNode * newNode,int nodepos) { + DbRetVal rv=OK; + TreeNode *start = (TreeNode *) this; HashIndexInfo *info = (HashIndexInfo*) indInfo; CINDEX *iptr = (CINDEX*)indexPtr; - TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; int offset = info->fldOffset; DataType type = info->type; int noOfBuckets = info->noOfBuckets; - TreeNode *iter =start; void *record = NULL; - TreeNode *prev = start; - char *keyVal = (char*) tuple + info->fldOffset; - DbRetVal rc = OK; - bool recordInserted = false; - printDebug(DM_TreeIndex, "\nInside TreeNode::Insert - 2"); - int count =0; - int direction = 0; //0:current,1:right,2:rightLeft,-1:left,-2:leftRight - DbRetVal rv = OK; - while(iter != NULL) + char **node = NULL; + char *tmp = NULL; + char *tmpnode=NULL; + TreeNode *tempNode = start; + if(start->noElements_< noOfBuckets) { - record = ((char*)iter->max_)+ info->fldOffset; - printDebug(DM_TreeIndex, "\n%d---%d", *((int*)keyVal), *((int*)record)); - bool result = AllDataType::compareVal(keyVal, record, OpGreaterThan, - info->type, info->compLength); - if (result) + printDebug(DM_TreeIndex,"insertNodeIntoFirstLevel after node insert manage first level node"); + if(start->noElements_<= nodepos) { - if(direction == -1) - { - direction = -2; - break; - } - direction = 1; - prev = iter; - iter = iter->next_; - printDebug(DM_TreeIndex, "\n2Insert- > "); + node = (char **)((char*)start + sizeof(TreeNode) + (nodepos * sizeof(void *))); + start->noElements_++; + *node = (char*)newNode; }else { - record = ((char*)iter->min_)+ info->fldOffset; - result = AllDataType::compareVal(keyVal, record, OpLessThan, - info->type, info->compLength); - if (result) { - if(direction == 1) - { - direction = 2; - break; - } - direction = -1; - prev = iter; - iter = iter->prev_; - printDebug(DM_TreeIndex, "\n2Insert- < "); - } - else - { - printDebug(DM_TreeIndex, "\n2Insert- = "); - direction=0; - break; - } + node = (char**)((char*)start + sizeof(TreeNode)); + tmp = (char *)malloc(sizeof(void *) * (start->noElements_ - nodepos)); + memcpy(tmp, (char*)node + (nodepos * sizeof(void *)), sizeof(void *) * (start->noElements_ - nodepos)); + memcpy((char*)node + ((nodepos+1) * sizeof(void *)), tmp, sizeof(void *) * (start->noElements_ - nodepos)); + free(tmp); + node = (char **)((char*)node + (nodepos * sizeof(void *))); + *node = (char*)newNode; + start->noElements_++; } } - - if(direction == 2) + else { - //Check the size of the prev node.... - //if not full then move the iter to prev and call insertLast() - //else call insertFirst(); - - if((iter->prev_ != NULL) && (iter->prev_->noElements_ < noOfBuckets) ) + node = (char**)((char*)start + sizeof(TreeNode)); + if(start->noElements_ > nodepos) { - printDebug(DM_TreeIndex, "\n2Insert- d=2 if "); - iter = iter->prev_; - rv = insert(1, db, indInfo, iptr, tuple, iter); - } - else - { - printDebug(DM_TreeIndex, "\n2Insert- d=2 else "); - rv = insert(-1, db, indInfo, iptr, tuple, iter); - } - } - else if(direction == 1) - { - iter = prev; - if((iter->noElements_ >= noOfBuckets) && (iter->next_ != NULL) - && (iter->next_->noElements_ < noOfBuckets) ) + tmpnode = *(char **)((char*)node+ ((start->noElements_-1) * sizeof(void *)));//store last one + tmp = (char *)malloc(sizeof(void *) * (start->noElements_ - nodepos)); + memcpy(tmp, (char*)node + (nodepos * sizeof(void *)), sizeof(void *) * (start->noElements_ - nodepos-1)); + memcpy((char*)node + ((nodepos+1) * sizeof(void *)), tmp, sizeof(void *) * (start->noElements_ - nodepos-1)); + free(tmp); + node = (char **)((char*)node + (nodepos * sizeof(void *))); + *node = (char*)newNode; + }else { - printDebug(DM_TreeIndex, "\n2Insert- d=1 if "); - iter = iter->next_; - rv = insert(-1, db, indInfo, iptr, tuple, iter); + tmpnode =(char*)newNode; } - else + nodepos=0; + if( start->next_ != NULL && start->next_->noElements_< noOfBuckets) { - printDebug(DM_TreeIndex, "\n2Insert- d=1 else "); - rv = insert(1, db, indInfo, iptr, tuple, iter); - } - } - else if(direction == -2) - { - if(iter->next_ != NULL && iter->next_->noElements_ < noOfBuckets ) - { - printDebug(DM_TreeIndex, "\n2Insert- d=-2 if "); - iter = iter->next_; - rv = insert(-1, db, indInfo, iptr, tuple, iter); - } - else - { - printDebug(DM_TreeIndex, "\n2Insert- d=-2 else "); - rv = insert(1, db, indInfo, iptr, tuple, iter); - } - } - else if(direction == -1) - { - iter = prev; - if((iter->noElements_ >= noOfBuckets) && (iter->prev_ != NULL) - && (iter->prev_->noElements_ < noOfBuckets) ) + start = start->next_; + + node = (char**)((char*)start + sizeof(TreeNode)); + tmp = (char *)malloc(sizeof(void *) * (start->noElements_ - nodepos)); + memcpy(tmp, (char*)node + (nodepos * sizeof(void *)), sizeof(void *) * (start->noElements_ - nodepos)); + memcpy((char*)node + ((nodepos+1) * sizeof(void *)), tmp, sizeof(void *) * (start->noElements_ - nodepos)); + free(tmp); + node = (char **)((char*)node + (nodepos * sizeof(void *))); + *node = (char*)tmpnode; + start->noElements_++; + start->mutex_.releaseShareLock(db->procSlot); + }else { - printDebug(DM_TreeIndex, "\n2Insert- d=-1 if "); - iter = iter->prev_; - rv = insert(1, db, indInfo, iptr, tuple, iter); + printDebug(DM_TreeIndex, "Check if full and start->next_ ==NULL then create new one"); + Chunk *ftchunk = (Chunk*) iptr->chunkPtr_; + TreeNode *ftnode = (TreeNode*) ftchunk->allocate(db, &rv); + if (ftnode == NULL) + { + printError(rv, "Exit TreeNode firstlevel allocate fail"); + tempNode->mutex_.releaseShareLock(db->procSlot); + return rv; + } + ftnode->mutex_.init(); + strcpy(ftnode->mutex_.name, "I-Tree"); + ftnode->min_= NULL; + ftnode->max_ = NULL; + ftnode->noElements_ =1; + ftnode->balance_ = 0; + char **tn=(char**)((char*) ftnode+sizeof(TreeNode)); + *tn = (char*)tmpnode; + ftnode->next_ = start->next_; + ftnode->prev_ = start; + start->next_ = ftnode; } - else - { - printDebug(DM_TreeIndex, "\n2Insert- d=-1 else "); - rv = insert(-1, db, indInfo, iptr, tuple, iter); - } } - else - { - printDebug(DM_TreeIndex, "\n2Insert- d=0 "); - rv = insert(0, db, indInfo, iptr, tuple, iter); - } - printDebug(DM_TreeIndex, "\n %d While ..Exit TreeNode::Insert - 2",count); - return rv; + tempNode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",tempNode); + return OK; } -DbRetVal TreeNode::insert(int position, Database * db, IndexInfo * indInfo, - CINDEX * iptr, void * tuple, TreeNode * iter) -{ - //position--- -1:First,0:Middle,1:Last + + +DbRetVal TreeNode::insertRecordIntoNodeAndArrangeFirstLevel(Database * db, IndexInfo * indInfo, void* indexPtr, void * tuple, TreeNode * fstLevel, int nodePos) +{ + TreeNode *iter = (TreeNode *) this; HashIndexInfo *info = (HashIndexInfo*) indInfo; - TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; + CINDEX *iptr = (CINDEX*)indexPtr; int offset = info->fldOffset; DataType type = info->type; int noOfBuckets = info->noOfBuckets; void *record = NULL; - TreeNode *prev = start; - TreeNode *next = start; char *keyVal = (char*) tuple + info->fldOffset; DbRetVal rc = OK; bool recordInserted = false; - iter->mutex_.getLock(db->procSlot); - if(position == -1) + TreeNode *tmpNode=NULL; + int ret = iter->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + if(iter->noElements_>= noOfBuckets) { - if(iter->noElements_ >= noOfBuckets) + //Ist level full + //Decide new record should go in left or right of second level + //if it is inside then create new memcpy all address from location to next node + //if left check prev_ node has free space or not if yes insert at end else create new + //if right check next_ node has free space or not if yes insert at Ist loc nad do memcpy else create new + //create node and link to prevous node and link to the Fistlevel + record = ((char*)iter->max_)+ info->fldOffset; + bool result = AllDataType::compareVal(keyVal, record, OpGreaterThan, info->type, info->compLength); + if(result) { - Chunk *chunk = (Chunk*) iptr->chunkPtr_; - TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); - if (tnode == NULL) + printDebug(DM_TreeIndex,"locateed Node full new node create at iright"); + //check right for free space if not create node right + tmpNode = iter->next_; + if(tmpNode!=NULL && tmpNode->noElements_ < noOfBuckets) { - printDebug(DM_TreeIndex, "\nExit TreeNode::Insert Position tnode=NULL"); - iter->mutex_.releaseLock(db->procSlot); - return rc; + //insert at beginning + ret = tmpNode->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + char *tmp = NULL; + char **rec = (char**)((char*)tmpNode + sizeof(TreeNode)); + tmp = (char *)malloc(sizeof(void *) * (tmpNode->noElements_)); + memcpy(tmp, (char*)rec , sizeof(void *) * (iter->noElements_)); + memcpy((char*)rec + (1*sizeof(void *)), tmp, sizeof(void *) * (iter->noElements_)); + *rec = (char*)tuple; + tmpNode->min_=tuple; + tmpNode->noElements_++; + free(tmp); + iter->mutex_.releaseShareLock(db->procSlot); + tmpNode->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fstLevel); } - tnode->mutex_.init(); - tnode->min_ = tuple; - tnode->max_ = tuple; - tnode->noElements_ =1; - tnode->next_ = iter; - tnode->prev_ = iter->prev_; - iter->prev_ = tnode; - tnode->balance_ = 0; - char **rec = (char**)((char*)tnode + sizeof(TreeNode)); - *rec = (char*) tuple; - } - else - { - printDebug(DM_TreeIndex, "\n3Insert- p=-1 else "); - char **rec = (char**)((char*)iter + sizeof(TreeNode)); - char *tmp = (char *)malloc(sizeof(void **) * iter->noElements_); - memcpy(tmp, (char*)rec, sizeof(void **)* iter->noElements_); - memcpy((char*)rec + sizeof(void **), tmp, sizeof(void **) * (iter->noElements_)); - free(tmp); - iter->min_ = tuple; - iter->noElements_++; - *rec = (char*) tuple; - } - } - else if(position == 1) - { - if(iter->noElements_ >= noOfBuckets) - { - printDebug(DM_TreeIndex, "\n3Insert- p=1 if "); - Chunk *chunk = (Chunk*) iptr->chunkPtr_; - TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); - if (tnode == NULL) + else { - printDebug(DM_TreeIndex, "\nExit TreeNode::Insert Position tnode=NULL"); - iter->mutex_.releaseLock(db->procSlot); - return rc; + //allocate new node here + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); + if (tnode == NULL) + { + printError(rc, "Exit TreeNode create fail after node full"); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fstLevel); + return rc; + } + if( fstLevel->next_!=NULL && fstLevel->noElements_>= noOfBuckets && fstLevel->next_->noElements_< noOfBuckets) + { + ret = fstLevel->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + } + tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); + tnode->min_ = tuple; + tnode->max_ = tuple; + tnode->noElements_ =1; + tnode->next_ = NULL; + tnode->prev_ = NULL; + tnode->balance_ = 0; + char **rec = (char**)((char*) tnode + sizeof(TreeNode)); + *rec = (char*) tuple; + if(iter->next_!=NULL){ + if( 0 !=Mutex::CASL((long*)&iter->next_->prev_, (long)iter->next_->prev_, (long)tnode)) + { + printError(ErrLockTimeOut, "Lock timeout..retry Tree"); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + return ErrLockTimeOut; + } + } + tnode->next_= iter->next_; + tnode->prev_= iter; + iter->next_= tnode; + nodePos++; + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->insertNodeIntoFirstLevel(db, indInfo, indexPtr, tnode, nodePos); } - tnode->mutex_.init(); - tnode->min_ = tuple; - tnode->max_ = tuple; - tnode->noElements_ =1; - tnode->next_ = iter->next_; - tnode->prev_ = iter; - iter->next_ = tnode; - if(tnode->next_) + }else + { + record = ((char*)iter->min_)+ info->fldOffset; + bool result = AllDataType::compareVal(keyVal, record, OpLessThan, info->type, info->compLength); + if(result) { - tnode->next_->prev_ = tnode; + printDebug(DM_TreeIndex,"\nlocateed Node full new node create at left"); + //check left for free space if not create node left + tmpNode = iter->prev_; + if(tmpNode!=NULL && tmpNode->noElements_ < noOfBuckets) + { + //insert at End + ret = tmpNode->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + char **rec = (char**)((char*)tmpNode + sizeof(TreeNode)); + rec = (char **)((char *)rec + (tmpNode->noElements_ * sizeof(void *))); + *rec = (char*)tuple; + tmpNode->max_ = tuple; + tmpNode->noElements_++; + iter->mutex_.releaseShareLock(db->procSlot); + tmpNode->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fstLevel); + }else + { + //allocate here + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); + if (tnode == NULL) + { + printError(rc, "Exit TreeNode create fail after node full"); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fstLevel); + return rc; + } + if( fstLevel->next_!=NULL && fstLevel->noElements_>= noOfBuckets && fstLevel->next_->noElements_< noOfBuckets) + { + ret = fstLevel->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + } + tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); + tnode->min_ = tuple; + tnode->max_ = tuple; + tnode->noElements_ =1; + tnode->next_ = NULL; + tnode->prev_ = NULL; + tnode->balance_ = 0; + char **rec = (char**)((char*) tnode + sizeof(TreeNode)); + printDebug(DM_TreeIndex, "Storing first record at %x\n", rec); + *rec = (char*) tuple; + if(iter->prev_!=NULL) { + if( 0 !=Mutex::CASL((long*)&iter->prev_->next_, (long)iter->prev_->next_, (long)tnode)) + { + printError(ErrLockTimeOut, "Lock timeout..retry Tree"); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + return ErrLockTimeOut; + } + } + tnode->prev_= iter->prev_; + tnode->next_= iter; + iter->prev_= tnode; + //manage First level + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->insertNodeIntoFirstLevel(db, indInfo, indexPtr, tnode, nodePos); + } + }else + { + //create right + //locate position shift node + void *tmprec=NULL; + char **rec = (char**)((char*) iter + sizeof(TreeNode)); + tmprec = iter->max_; + int start = 0; + int end = iter->noElements_ - 1; + int middle; + int loc = 0; + char *tmp = NULL; + loc=0; + for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) + { + loc = middle; + record = ((char*)*(rec+middle)) + info->fldOffset; + printDebug(DM_TreeIndex, "%d-%d\n\n", *((int*)keyVal), *((int*)record)); + bool res = AllDataType::compareVal(keyVal, record, + OpLessThan, info->type, info->compLength); + if(res) + { + end = middle - 1; + } + else + { + res = AllDataType::compareVal(keyVal, record, + OpGreaterThan, info->type, info->compLength); + if (res) { + start = middle + 1; + loc = start; + }else { + loc = middle; + if (info->isUnique) { + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printError(ErrUnique, "Unique constraint violation"); + return ErrUnique; + } + break; + } + } + } + + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); + if (tnode == NULL) + { + printError(rc, "Exit TreeNode create fail after node full"); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fstLevel); + return rc; + } + if( fstLevel->next_!=NULL && fstLevel->noElements_>= noOfBuckets && fstLevel->next_->noElements_< noOfBuckets) + { + ret = fstLevel->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); //release here 1st level + return ErrLockTimeOut; + } + } + tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); + tnode->min_ = tuple; + tnode->max_ = tuple; + tnode->noElements_ =1; + tnode->next_ = NULL; + tnode->prev_ = NULL; + tnode->balance_ = 0; + + //shift all element from the location to next node + char **fstRec = (char**)((char*)iter + sizeof(TreeNode)); + tmp = (char *)malloc(sizeof(void *) * (iter->noElements_ - loc)); + memcpy(tmp, (char*)fstRec+ (loc * sizeof(void *)), sizeof(void *) * (iter->noElements_ - loc)); + rec = (char **)((char*)fstRec + (loc * sizeof(void *))); + *rec = (char*)tuple; + //copy to next node + fstRec = (char**)((char*) tnode + sizeof(TreeNode)); + memcpy((char*)fstRec, tmp, sizeof(void *) * (iter->noElements_- loc)); + free(tmp); + tnode->noElements_= iter->noElements_- loc; + tnode->max_= tmprec; + tnode->min_= *fstRec; + iter->noElements_= loc + 1; + iter->max_= tuple; + if(loc==0) + { + iter->min_ = tuple; + } + if(iter->next_!=NULL){ + if( 0 !=Mutex::CASL((long*)&iter->next_->prev_, (long)iter->next_->prev_, (long)tnode)) + { + printError(ErrLockTimeOut, "Lock timeout..retry Tree"); + chunk->free(db, tnode); + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + return ErrLockTimeOut; + } + } + tnode->next_= iter->next_; + tnode->prev_=iter; + iter->next_=tnode; //TODO::need here CASL + nodePos++; + //shift right done after this block + printDebug(DM_TreeIndex,"located Node full new node create at right position %d shift node",loc); + //manage First level + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->insertNodeIntoFirstLevel(db, indInfo, indexPtr, tnode, nodePos); } - tnode->balance_ = 0; - char **rec = (char**)((char*)tnode + sizeof(TreeNode)); - *rec = (char*) tuple; - } - else + } + return OK; + } + if(iter->noElements_< noOfBuckets) + { + fstLevel->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex,"located Node not full insert in same node"); + + record = ((char*)iter->max_)+ info->fldOffset; + printDebug(DM_TreeIndex, "\n%d---%d", *((int*)keyVal), *((int*)record)); + bool result = AllDataType::compareVal(keyVal, record, OpGreaterThan, info->type, info->compLength); + if(result) { - printDebug(DM_TreeIndex, "\n3Insert- p=1 else "); char **rec = (char**)((char*)iter + sizeof(TreeNode)); rec = (char **)((char *)rec + (iter->noElements_ * sizeof(void **))); iter->max_ = tuple; iter->noElements_++; *rec = (char*) tuple; - rec = (char**)((char*)iter + sizeof(TreeNode)); - rec = (char**)((char *)rec + ((iter->noElements_-1) * sizeof(void **))); } - } - else - { - printDebug(DM_TreeIndex, "\n3Insert- p=0 "); - - int start = 0; - int end = iter->noElements_ - 1; - int middle; - int loc = 0; - char **rec = (char**)((char*)iter + sizeof(TreeNode)); - char *tmp = NULL; - loc=0; - for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) + else { - loc = middle; - record = ((char*)*(rec+middle)) + info->fldOffset; - printDebug(DM_TreeIndex, "\n3Insert- p=0 get record \n"); - printDebug(DM_TreeIndex, "%d-%d\n\n", *((int*)keyVal), *((int*)record)); - bool res = AllDataType::compareVal(keyVal, record, OpEquals, info->type, info->compLength); - if(res) + int start = 0; + int end = iter->noElements_ - 1; + int middle; + int loc = 0; + char **rec = (char**)((char*)iter + sizeof(TreeNode)); + char *tmp = NULL; + loc=0; + for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) { loc = middle; - if (info->isUnique) { - iter->mutex_.releaseLock(db->procSlot); - printError(ErrUnique, "Unique constraint violation\n"); - return ErrUnique; + record = ((char*)*(rec+middle)) + info->fldOffset; + printDebug(DM_TreeIndex, "%d-%d\n\n", *((int*)keyVal), *((int*)record)); + bool res = AllDataType::compareVal(keyVal, record, OpLessThan, info->type, info->compLength); + if(res) + { + end = middle - 1; + } + else + { + res = AllDataType::compareVal(keyVal, record, OpGreaterThan, info->type, info->compLength); + if (res) { + start = middle + 1; + loc = start; + }else { + loc = middle; + if (info->isUnique) + { + iter->mutex_.releaseShareLock(db->procSlot); + fstLevel->mutex_.releaseShareLock(db->procSlot); + printError(ErrUnique, "Unique constraint violation"); + return ErrUnique; + } + break; + } } - break; - } - res = AllDataType::compareVal(keyVal, record, OpLessThan, info->type, info->compLength); - if(res ) - { - end = middle - 1; - } - else - { - start = middle + 1; - loc = start; - } - } - if(iter->noElements_ >= noOfBuckets) - { - printDebug(DM_TreeIndex, "\n3Insert- p=0 if "); - Chunk *chunk = (Chunk*) iptr->chunkPtr_; - TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rc); - if (tnode == NULL) - { - printDebug(DM_TreeIndex, "\nExit TreeNode::Insert Position tnode=NULL"); - iter->mutex_.releaseLock(db->procSlot); - return rc; - } - tnode->mutex_.init(); - tnode->next_ = iter->next_; - tnode->prev_ = iter; - iter->next_ = tnode; - if(tnode->next_) - { - tnode->next_->prev_ = tnode; } - tnode->balance_ = 0; - char **rec = (char**)((char*)iter + sizeof(TreeNode)); - char *tmp = (char *)malloc(sizeof(void *) * (iter->noElements_ - loc)); - memcpy(tmp, (char*)rec + (loc * sizeof(void *)), sizeof(void *) * (iter->noElements_ - loc));///////// Check the type cast char * - rec = (char**)((char *)rec + (loc * sizeof(void *))); - *rec = (char*)tuple; - tnode->noElements_ = iter->noElements_ - loc; - iter->noElements_ = loc + 1; + printDebug(DM_TreeIndex, "\nInsert pos-%d",loc); rec = (char**)((char*)iter + sizeof(TreeNode)); - iter->min_ = *rec; - iter->max_ = tuple; - rec = (char**)((char*)tnode + sizeof(TreeNode)); - memcpy((char*)rec, tmp, (tnode->noElements_) * sizeof(void *)); - tnode->min_ = *rec; - rec = (char**)((char *)rec + ((tnode->noElements_ - 1) * sizeof(void *))); - tnode->max_ = *rec ; - free(tmp); - } - else - { - printDebug(DM_TreeIndex, "\n3Insert- p=0 else pos-%d",loc); - char **rec = (char**)((char*)iter + sizeof(TreeNode)); - char *tmp = (char *)malloc(sizeof(void *) * (iter->noElements_ - loc)); + tmp = (char *)malloc(sizeof(void *) * (iter->noElements_ - loc)); memcpy(tmp, (char*)rec + (loc * sizeof(void *)), sizeof(void *) * (iter->noElements_ - loc));///////// Check the type cast char * memcpy((char*)rec + ((loc+1) * sizeof(void *)), tmp, sizeof(void *) * (iter->noElements_ - loc)); free(tmp); if(loc==0) { - iter->min_ = tuple; + iter->min_ = tuple; } iter->noElements_++; rec = (char **)((char*)rec + (loc * sizeof(void *))); *rec = (char*)tuple; } + //first level mutex release + iter->mutex_.releaseShareLock(db->procSlot); } - iter->mutex_.releaseLock(db->procSlot); - return rc; + return OK; } DbRetVal TreeIndex::remove(TableImpl *tbl, Transaction *tr, void *indexPtr, IndexInfo *indInfo, void *tuple, bool undoFlag) { - //printf("Tree index remove called\n"); + DbRetVal rc = OK; HashIndexInfo *info = (HashIndexInfo*) indInfo; CINDEX *iptr = (CINDEX*)indexPtr; TreeNode *start = (TreeNode*) iptr->hashNodeChunk_; - TreeNode *iter = locateNode(start, tuple, indInfo); - if (NULL == iter) return OK; //element not found - return removeElement(tbl->getDB(), iter, tuple, info); + int pos=0; + TreeNode *fltnode = start->locateNode(tbl->getDB(),start, tuple, indInfo,rc); + if (NULL == fltnode) return rc; //First Level Node Not found + TreeNode *iter = start->locateNodeFromFirstLevel(fltnode, indInfo, tuple, &pos); + if (NULL == iter) { + fltnode->mutex_.releaseShareLock((tbl->getDB())->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + return OK; + } //element not found + rc = removeElement(tbl->getDB(), iter, tuple, info); + if( rc != OK ){ + fltnode->mutex_.releaseShareLock((tbl->getDB())->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + printError(rc, "Romove from TreeNode Failed "); + return rc; + } + if(0 == iter->noElements_) + { + removeNode(tbl->getDB(), indexPtr, fltnode, iter, pos); + }else + { + fltnode->mutex_.releaseShareLock((tbl->getDB())->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + } + TreeUndoLogInfo hInfo; + hInfo.metaData_ = tbl->db_->getMetaDataPtr(); + hInfo.tuple_ = tuple; + hInfo.cIndex_= indexPtr; + if (!undoFlag) { + rc =tr->appendLogicalTreeUndoLog(tbl->sysDB_, DeleteTreeIndexOperation, &hInfo, sizeof(TreeUndoLogInfo)); + if( rc != OK){ + //Reverse back + //Currently nodes are not freed + rc = start->insert(tbl->db_, info, iptr, tuple); + if (rc != OK){ printError(ErrSysFatal, "double failure on undo log remove followed by tree insert\n");} + printError(ErrSysFatal, "Unable to append undo lock for TreeRemove\n"); + return rc; + } + } + return rc; } -TreeNode* TreeIndex::locateNode(TreeNode *iter, void *tuple, IndexInfo *indInfo) +void TreeIndex::removeNode(Database *db,void *indexPtr,TreeNode *fltnode, TreeNode *node,int pos) { + CINDEX *iptr = (CINDEX*)indexPtr; + char **nod = (char**)((char*)fltnode + sizeof(TreeNode)); + char *tmp = (char *)malloc(sizeof(void *) * (fltnode->noElements_ - pos)); + memcpy(tmp, (char*)nod + ((pos+1) * sizeof(void *)), sizeof(void *) * (fltnode->noElements_ - pos)); + memcpy((char*)nod + ((pos) * sizeof(void *)), tmp, sizeof(void *) * (fltnode->noElements_ - pos)); + free(tmp); + fltnode->noElements_--; + if(node->prev_!=NULL) node->prev_->next_= node->next_; + if(node->next_!=NULL) node->next_->prev_= node->prev_; + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + chunk->free(db, node); + printDebug(DM_TreeIndex,"TreeNode at postion %d Freed",pos); + if(fltnode->noElements_== 0) + { + if(fltnode->prev_!=NULL) { + fltnode->prev_->next_= fltnode->next_; + } + else { + iptr->hashNodeChunk_ = fltnode->next_ ; + } + if(fltnode->next_!=NULL) { + fltnode->next_->prev_= fltnode->prev_; + } + //need discussion in the above situation to solve concureny + printDebug(DM_TreeIndex,"TreeNode from first level Freed"); + fltnode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + chunk->free(db, fltnode); + }else{ + fltnode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",fltnode); + } +} + +DbRetVal TreeNode::insert(Database *db,IndexInfo *indInfo,void *indexPtr,void *tuple) +{ + DbRetVal rv=OK; + TreeNode *iter = (TreeNode *) this ; HashIndexInfo *info = (HashIndexInfo*) indInfo; + CINDEX *iptr = (CINDEX*)indexPtr; void *searchKey =(void*)((char*)tuple + info->fldOffset); - while(iter != NULL) + TreeNode *tnode=NULL; + TreeNode *prev = iter; + bool result = false; + int ret = iter->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + return ErrLockTimeOut; + } + printDebug(DM_TreeIndex," Mutex Taken on %x\n",iter); + + while(iter != NULL )//&& iter->noElements_>= info->noOfBuckets ) + { + tnode = (TreeNode *)*((char**)((char*)((char*)iter + sizeof(TreeNode))+ ((iter->noElements_-1)*sizeof(void *)))); + char *record = ((char*)tnode->max_)+ info->fldOffset; + result = AllDataType::compareVal(searchKey, record,OpLessThanEquals,info->type, info->compLength); + if (result) + { + break; + }else + { + if(tnode->noElements_ >= info->noOfBuckets) + { + if(iter->next_!=NULL) + { + ret = iter->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + iter->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",iter); + return ErrLockTimeOut; + } + printDebug(DM_TreeIndex," Mutex Taken on %x\n",iter->next_); + prev = iter; + iter = iter->next_; + prev->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",prev); + }else{ + prev = iter; + iter = iter->next_; + } + }else + { + if(iter->next_!=NULL) + { + tnode = (TreeNode *)*((char**)((char*)((char*)iter->next_ + sizeof(TreeNode)))); + char *record = ((char*)tnode->min_)+ info->fldOffset; + result = AllDataType::compareVal(searchKey, record,OpLessThan,info->type, info->compLength); + if (result) + { + break; + } else + { + if(iter->next_!=NULL) + { + ret = iter->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + iter->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",iter); + return ErrLockTimeOut; + } + printDebug(DM_TreeIndex," Mutex Taken on %x\n",iter); + prev = iter; + iter = iter->next_; + prev->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",prev); + }else + { + prev = iter; + iter = iter->next_; + } + } + }else{ + break; + } + } + } + } + if( iter == NULL && prev->noElements_< info->noOfBuckets) + { + iter = prev ; + } + if(iter == NULL) + { + //create Ist level node then leaf node ,insert record and return + printDebug(DM_TreeIndex, "iter =NULL create Ist level node then leaf node ,insert record and return"); + Chunk *chunk = (Chunk*) iptr->chunkPtr_; + TreeNode *tnode = (TreeNode*) chunk->allocate(db, &rv); + if (tnode == NULL) + { + printError(rv, "Exit TreeNode allocate fail"); + return rv; + } + tnode->mutex_.init(); + strcpy(tnode->mutex_.name, "Tree"); + tnode->min_ = tuple; + tnode->max_ = tuple; + tnode->noElements_ =1; + tnode->next_ = NULL; + tnode->prev_ = NULL; + tnode->balance_ = 0; + char **rec = (char**)((char*) tnode + sizeof(TreeNode)); + printDebug(DM_TreeIndex, "Storing first record at %x\n", rec); + *rec = (char*) tuple; + TreeNode *prevNode = (TreeNode*)*(char**)((char*) prev +sizeof(TreeNode)+((prev->noElements_-1)* sizeof(void*))); + prevNode->next_= tnode; + tnode->prev_= prevNode; + //fist levelnode + Chunk *ftchunk = (Chunk*) iptr->chunkPtr_; + TreeNode *ftnode = (TreeNode*) ftchunk->allocate(db, &rv); + if (ftnode == NULL) + { + printDebug(DM_TreeIndex, "Exit TreeNode firstlevel allocate fail"); + return rv; + } + ftnode->mutex_.init(); + strcpy(ftnode->mutex_.name, "I-Tree"); + ftnode->min_= NULL; + ftnode->max_ = NULL; + ftnode->noElements_ =1; + ftnode->next_ = NULL; + ftnode->balance_ = 0; + char **tn=(char**)((char*) ftnode+sizeof(TreeNode)); + *tn = (char*)tnode; + ftnode->prev_= prev; + prev->next_=ftnode; + prev->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",prev); + return OK; + } + //Get leaf Node + int nodepos=0; + tnode = locateNodeFromFirstLevel(iter, indInfo, tuple, &nodepos); + rv = tnode->insertRecordIntoNodeAndArrangeFirstLevel(db, indInfo, indexPtr, tuple, iter, nodepos); + return rv; +} + +TreeNode* TreeNode::locateNode(Database *db, TreeNode *iter, void *tuple, IndexInfo *indInfo,DbRetVal &rv) +{ + if(iter == NULL) return NULL; + HashIndexInfo *info = (HashIndexInfo*) indInfo; + void *searchKey =(void*)((char*)tuple + info->fldOffset); + TreeNode *tnode=NULL; + int ret = iter->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + rv = ErrLockTimeOut; + return NULL; + } + printDebug(DM_TreeIndex," Mutex Taken on %x\n",iter); + TreeNode *tmpNode=NULL; + while(iter->noElements_>= info->noOfBuckets && iter != NULL) { - char *record = ((char*)iter->max_)+ info->fldOffset; - bool result = AllDataType::compareVal(searchKey, record, - OpGreaterThan, - info->type, info->compLength); + tnode = (TreeNode *)*((char**)((char*)iter + sizeof(TreeNode)+ ((iter->noElements_-1)*sizeof(void *)))); + char *record = ((char*)tnode->max_)+ info->fldOffset; + bool result = AllDataType::compareVal(searchKey, record,OpLessThanEquals,info->type, info->compLength); if (result) { - iter = iter->next_; + break; }else { - record = ((char*)iter->min_)+ info->fldOffset; - result = AllDataType::compareVal(searchKey, record, - OpGreaterThanEquals, - info->type, info->compLength); - if (result) { - //current node contains the key - return iter; - } - else + if(iter->next_!=NULL) { - //need to move left - iter = iter->prev_; + ret = iter->next_->mutex_.getExclusiveLock(db->procSlot); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + iter->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",iter); + rv = ErrLockTimeOut; + return NULL; + } + printDebug(DM_TreeIndex," Mutex Taken on %x\n",iter->next_); + tmpNode = iter; + iter = iter->next_; + tmpNode->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",tmpNode); + }else{ + iter->mutex_.releaseShareLock(db->procSlot); + printDebug(DM_TreeIndex," Mutex Release on %x\n",iter); + iter = iter->next_; } } } - return NULL; + //Get leaf Node + return iter; + } +TreeNode *TreeNode::locateNodeFromFirstLevel(TreeNode *ftnode, IndexInfo *indInfo,void *tuple, int *pos) +{ + HashIndexInfo *info = (HashIndexInfo*) indInfo; + int fldOffset = info->fldOffset; + DataType type = info->type; + int length = info->compLength; + void *searchKey =(void*)((char*)tuple + info->fldOffset); + int loc=0, middle = 0, start = 0, end = ftnode->noElements_-1; + char **node = (char**)((char*)ftnode + sizeof(TreeNode)); + TreeNode *tNode; + for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) + { + loc = middle; + char *record =(char *)(((TreeNode *) *(char**)((char*)node + (loc * sizeof(void *))))->max_)+fldOffset; + + bool res = AllDataType::compareVal(searchKey, record, OpLessThan,type, length); + if(res) + { + end = middle - 1; + } + else + { + res = AllDataType::compareVal(searchKey, record, OpGreaterThan, type, length); + if (res) { + start = middle + 1; + if(start <= (ftnode->noElements_-1)) loc = start; + }else { + loc=middle; + break; + } + } + } + printDebug(DM_TreeIndex, "inside locateNodeFromFirstLevel loc=%d",loc); + *pos=loc; + tNode = ((TreeNode *)*(char**)((char*)node + (loc * sizeof(void *)))); + return tNode; +} + DbRetVal TreeIndex::removeElement(Database *db, TreeNode *iter, void *tuple, HashIndexInfo *info) { void *searchKey =(void*)((char*)tuple + info->fldOffset); int loc=0, middle=0, start=0, end=iter->noElements_-1; char **rec = (char**)((char*)iter + sizeof(TreeNode)); - iter->mutex_.getLock(db->procSlot); + int ret = iter->mutex_.getExclusiveLock(db->procSlot,true,true); + if (0 != ret) { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + return ErrLockTimeOut; + } for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) { loc = middle; char *record = ((char*)*(rec+middle)) + info->fldOffset; - bool res = AllDataType::compareVal(searchKey, record, OpEquals, + bool res = AllDataType::compareVal(searchKey, record, OpLessThan, info->type, info->compLength); if(res) { - loc = middle; - break; - } - res = AllDataType::compareVal(searchKey, record, OpLessThan, - info->type, info->compLength); - if(res) - { end = middle - 1; } else { - start = middle + 1; - loc = start; + res = AllDataType::compareVal(searchKey, record, OpGreaterThan, + info->type, info->compLength); + if (res) { + start = middle + 1; + loc = start; + } else { + loc = middle; + break; + } } } char *tmp = (char *)malloc(sizeof(void *) * (iter->noElements_ - loc)); @@ -516,8 +1175,7 @@ DbRetVal TreeIndex::removeElement(Database *db, TreeNode *iter, void *tuple, Has { iter->min_ = tuple; } - iter->mutex_.releaseLock(db->procSlot); - //TODO::if noElement is zero then deallocate the tree node + iter->mutex_.releaseShareLock(db->procSlot); iter->noElements_--; return OK; } diff --git a/src/storage/TreeIter.cxx b/src/storage/TreeIter.cxx index 9ccfbfef..01833cc3 100644 --- a/src/storage/TreeIter.cxx +++ b/src/storage/TreeIter.cxx @@ -31,6 +31,7 @@ void* TreeIter::getFirstElement() char **tuple = (char**)((char*)rec + (loc * sizeof(void *))); return *tuple; } + void* TreeIter::getLastElement() { if (NULL == iter) return NULL; @@ -46,6 +47,7 @@ void* TreeIter::getLastElement() char **tuple = (char**)((char*)rec + (loc * sizeof(void *))); return *tuple; } + void* TreeIter::prev() { if (0 != nodeOffset ) @@ -65,137 +67,266 @@ void* TreeIter::prev() void TreeIter::nextNode() { if (recordsOver) return ; - if (NULL== iter) return ; - iter=iter->next_; + if (NULL == iter) return ; + TreeNode *tmpIter = iter; + iter = iter->next_; + if(iter){ + int ret = iter->mutex_.getShareLock(procSlot, true); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + tmpIter->mutex_.releaseShareLock(procSlot); + return ; + } + } + tmpIter->mutex_.releaseShareLock(procSlot); nodeOffset=0; } + +void TreeIter::reset() +{ + if(iter && !firstCall) iter->mutex_.releaseShareLock(procSlot); + firstCall = true; + recordsOver=false; + iter = head; +} + void* TreeIter::next() { int direction=0; - if (recordsOver) return NULL; + if (recordsOver){ + if(iter) iter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; + } if (NULL== iter) return NULL; if (firstCall) { if (OpLessThan ==op || OpLessThanEquals == op) { - while(iter->prev_) - { - iter = iter->prev_; - } - firstCall = false; nodeOffset = 1; + firstCall = false; char **rec = (char**)((char*) iter + sizeof(TreeNode)); + int ret = iter->mutex_.getShareLock(procSlot,true); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + return NULL; + } //iter->displayAll(fldOffset); return *rec; } - else if (OpGreaterThan == op || OpGreaterThanEquals == op || - OpEquals == op) + else if (OpGreaterThan == op) + { + char *rec = (char*)locateNode(); + firstCall = false; + if(rec){ + bool result = AllDataType::compareVal(searchKey, rec+fldOffset, + OpEquals, type, length); + //equals comparision does not apply to float and double + if (result || type==typeFloat || type == typeDouble) return next(); + } + return rec; + }else if (OpGreaterThanEquals == op) { void *rec = locateNode(); firstCall = false; - //iter->displayAll(fldOffset); + return rec; + }else if (OpEquals == op) + { + void *rec = locateNode(); + firstCall = false; + if(isUnique) recordsOver = true; return rec; } - firstCall = false; + //firstCall = false; }else { if (nodeOffset == iter->noElements_) { - if (NULL == iter->next_) {recordsOver = true; return NULL;} + if (NULL == iter->next_) { + recordsOver = true; + iter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; + } char* record = ((char*)iter->next_->min_)+ fldOffset; bool result = AllDataType::compareVal(searchKey, record, OpGreaterThanEquals, type, length); if (!result && (OpLessThan ==op || OpLessThanEquals == op)) { - recordsOver= true; return NULL; + //Case: search key 10 , next node first record is 20 + //condition is < or <= + recordsOver= true; + iter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; }else if (result && (OpGreaterThan == op || OpGreaterThanEquals == op)) { - recordsOver= true; return NULL; + //Case: search key 20 , next node first record is 10 + //condition is > or >= + recordsOver= true; + iter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; } - iter=iter->next_; - if (NULL == iter) return NULL; + TreeNode *tmpIter = iter; + iter = iter->next_; + int ret = iter->mutex_.getShareLock(procSlot,true); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + tmpIter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; + } + tmpIter->mutex_.releaseShareLock(procSlot); + printDebug(DM_TreeIndex,"\n Moving Node next"); nodeOffset=0; } - //TODO::take node mutex here char **rec = (char**)((char*)iter + sizeof(TreeNode)); rec = (char**)((char *)rec + ((nodeOffset) * sizeof(void **))); nodeOffset++; - //TODO::release node mutex here + //TEMP::UNCOMMENT THIS if any issue + /*if(NULL==(*rec)) + iter->mutex_.releaseShareLock(procSlot); + */ return *rec; } return NULL; } void* TreeIter::locateNode() { - while(iter != NULL) + TreeNode *tnode=NULL; + TreeNode *fiter= (TreeNode *)fstLTnode; + int ret=0; + ret = fiter->mutex_.getShareLock(procSlot,true); + if (0 != ret) { - char *record = ((char*)iter->max_)+ fldOffset; - bool result = AllDataType::compareVal(searchKey, record, - OpGreaterThan, - type, length); + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + return NULL; + } + while( fiter!= NULL) + { + printDebug(DM_TreeIndex,"\n Search in first level start"); + tnode = (TreeNode *)*((char**)((char*)((char*)fiter + sizeof(TreeNode))+ ((fiter->noElements_-1)*sizeof(void *)))); + char *record = ((char*)tnode->max_)+ fldOffset; + bool result = AllDataType::compareVal(searchKey, record,OpLessThanEquals,type, length); if (result) { - //need to move right - iter = iter->next_; + break; }else { - record = ((char*)iter->min_)+ fldOffset; - result = AllDataType::compareVal(searchKey, record, - OpGreaterThanEquals, - type, length); - if (result) { - //current node contains the key - void *rec = locateElement(); - return rec; - } - else - { - //need to move left - if(NULL==iter->prev_) - { - void *rec = locateElement(); - return rec; + printDebug(DM_TreeIndex,"\n Search in first level next"); + TreeNode* tmpIter = fiter; + if(fiter->next_!= NULL){ + fiter = fiter->next_; + ret = fiter->mutex_.getShareLock(procSlot,true); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + tmpIter->mutex_.releaseShareLock(procSlot); + iter = NULL; + return NULL; } - iter = iter->prev_; + tmpIter->mutex_.releaseShareLock(procSlot); + }else{ + tmpIter->mutex_.releaseShareLock(procSlot); + fiter = NULL; } } } - return NULL; + if(fiter == NULL) + { + iter = NULL; + return NULL; + } + //Get leaf Node + + int loc=0, middle=0, start=0, end=fiter->noElements_-1; + char **rec = (char**)((char*)fiter + sizeof(TreeNode)); + TreeNode *tNode; + if(fiter->noElements_==1) + { + tNode = ((TreeNode *)*(char**)((char*)rec + (loc * sizeof(void *)))); + iter = tNode; + fiter->mutex_.releaseShareLock(procSlot); + void *rec1 = locateElement(); + return rec1; + } + for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) + { + loc = middle; + tNode = (TreeNode *)*((char**)((char*)((char*)fiter + sizeof(TreeNode))+ (loc*sizeof(void *)))); + char *record = ((char*)tNode->max_)+ fldOffset; + + bool res = AllDataType::compareVal(searchKey, record, OpLessThan, + type, length); + if(res) + { + end = middle - 1; + } + else + { + res = AllDataType::compareVal(searchKey, record, OpGreaterThan, + type, length); + if (res) { + start = middle + 1; + loc = start; + }else { + loc = middle; + break; + } + } + } + printDebug(DM_TreeIndex,"\n Search in fisrt level end loc =%d\n",loc); + tNode = ((TreeNode *)*(char**)((char*)rec + (loc * sizeof(void *)))); + iter = tNode; + fiter->mutex_.releaseShareLock(procSlot); + void *rec1 = locateElement(); + return rec1; } + + void* TreeIter::locateElement() { //do binary search and locate the element int loc=0, middle=0, start=0, end=iter->noElements_-1; char **rec = (char**)((char*)iter + sizeof(TreeNode)); - //TODO::take node mutex + int ret = iter->mutex_.getShareLock(procSlot,true); + if (0 != ret) + { + printError(ErrLockTimeOut,"Unable to lock the tree node. Retry..."); + return NULL; + } for(middle = (start + end) / 2; start <= end ; middle = (start +end )/2) { loc = middle; char *record = ((char*)*(rec+middle)) + fldOffset; - bool res = AllDataType::compareVal(searchKey, record, OpEquals, + bool res = AllDataType::compareVal(searchKey, record, OpLessThan, type, length); if(res) { - loc = middle; - break; - } - res = AllDataType::compareVal(searchKey, record, OpLessThan, - type, length); - if(res) - { end = middle - 1; } else { - start = middle + 1; - loc = start; + res = AllDataType::compareVal(searchKey, record, OpGreaterThan, + type, length); + if (res) { + start = middle + 1; + loc = start; + }else { + loc = middle; + break; + } } } nodeOffset=loc; char **tuple = (char**)((char*)rec + (loc * sizeof(void *))); nodeOffset++; - //TODO::release node mutex here + //iter->mutex_.releaseShareLock(procSlot); return *tuple; } diff --git a/src/storage/TupleIterator.cxx b/src/storage/TupleIterator.cxx index bd139ee8..5292707c 100644 --- a/src/storage/TupleIterator.cxx +++ b/src/storage/TupleIterator.cxx @@ -20,73 +20,84 @@ #include #include #include +DbRetVal TupleIterator::setPlan() +{ + PredicateImpl *predImpl = (PredicateImpl*) pred_; + if (treeIndexScan == scanType_) + { + HashIndexInfo *hIdxInfo = (HashIndexInfo*)info; + FieldIterator iter = hIdxInfo->idxFldList.getIterator(); + if(iter.hasElement()) + { + FieldDef *def = iter.nextElement(); + keyPtr = (char*)predImpl->valPtrForIndexField(def->fldName_, hIdxInfo->isUnique); + op = predImpl->opForIndexField(def->fldName_); + } + CINDEX *iptr = (CINDEX*) hIdxInfo->indexPtr; + TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_; + if(fstNode!=NULL){ + TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode))); + tIter->set(start,(TreeNode*)iptr->hashNodeChunk_,procSlot); + }else{ + tIter->set(NULL,(TreeNode*)iptr->hashNodeChunk_,procSlot); + } + tIter->setSearchKey(keyPtr, op); + if (hIdxInfo->isUnique) tIter->setUnique(); + tIter->setFldOffset(hIdxInfo->fldOffset); + tIter->setTypeLength(hIdxInfo->type, hIdxInfo->compLength); + } + if(predImpl) predImpl->setIfNoLeftRight(); + return OK; +} DbRetVal TupleIterator::open() { PredicateImpl *predImpl = (PredicateImpl*) pred_; if (fullTableScan == scanType_) { - cIter = new ChunkIterator(); *cIter = ((Chunk*)chunkPtr_)->getIterator(); }else if (hashIndexScan == scanType_) { HashIndexInfo *hIdxInfo = (HashIndexInfo*)info; bool isPtr = false; FieldIterator iter = hIdxInfo->idxFldList.getIterator(); - char *keyBuffer; int offset = hIdxInfo->fldOffset; - keyBuffer = (char*) malloc(hIdxInfo->compLength); - void *keyStartBuffer = (void*) keyBuffer, *keyPtr; + if(!keyBuffer) keyBuffer = (char*) malloc(hIdxInfo->compLength); + void *keyPtr = NULL; + char *keyBufferIter = keyBuffer; while(iter.hasElement()) { FieldDef *def = iter.nextElement(); - keyPtr = (void*)predImpl->valPtrForIndexField(def->fldName_); - AllDataType::copyVal(keyBuffer, keyPtr, def->type_, def->length_); - keyBuffer = keyBuffer + def->length_; + //keyPtr = (void*)predImpl->valPtrForIndexField(def->fldName_,hIdxInfo->isUnique); + //TODO::PRABA::the below opt should be done for hash also + keyPtr = (void*)predImpl->valPtrForIndexField(def->fldName_,false); + AllDataType::copyVal(keyBufferIter, keyPtr, def->type_, def->length_); + keyBufferIter = keyBufferIter + def->length_; } - int bucketNo = 0; - if (hIdxInfo->type == typeComposite) - bucketNo = HashIndex::computeHashBucket(hIdxInfo->type, - (char *)keyStartBuffer, hIdxInfo->noOfBuckets, hIdxInfo->compLength); - else bucketNo = HashIndex::computeHashBucket(hIdxInfo->type, - keyStartBuffer, hIdxInfo->noOfBuckets, hIdxInfo->compLength); - free(keyStartBuffer); + int bucketNo = HashIndex::computeHashBucket(hIdxInfo->type, + keyBuffer, hIdxInfo->noOfBuckets, hIdxInfo->compLength); Bucket *bucket = &(hIdxInfo->buckets[bucketNo]); - int ret = bucket->mutex_.getLock(procSlot); - if (ret != 0) - { - printError(ErrLockTimeOut,"Unable to acquire bucket Mutex for bucket %d",bucketNo); - return ErrLockTimeOut; - } HashIndexNode *head = (HashIndexNode*) bucket->bucketList_; if (!head) { - bucket->mutex_.releaseLock(procSlot); - bIter = NULL ; + bIter->setHead(head); return OK; } printDebug(DM_HashIndex, "open:head for bucket %x is :%x", bucket, head); - bIter = new BucketIter(head); - bucket->mutex_.releaseLock(procSlot); + bIter->setHead(head); }else if (treeIndexScan == scanType_) { HashIndexInfo *hIdxInfo = (HashIndexInfo*)info; - bool isPtr = false; - FieldIterator iter = hIdxInfo->idxFldList.getIterator(); - void *keyPtr; ComparisionOp op; - if(iter.hasElement()) - { - FieldDef *def = iter.nextElement(); - keyPtr = (void*)predImpl->valPtrForIndexField(def->fldName_); - op = predImpl->opForIndexField(def->fldName_); - //TODO::remove this predicate term as it is pushed to tree iter - } CINDEX *iptr = (CINDEX*) hIdxInfo->indexPtr; - tIter = new TreeIter((TreeNode*)iptr->hashNodeChunk_); - tIter->setSearchKey(keyPtr, op); - tIter->setFldOffset(hIdxInfo->fldOffset); - tIter->setTypeLength(hIdxInfo->type, hIdxInfo->compLength); + TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_; + if(fstNode!=NULL){ + TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode))); + tIter->set(start,(TreeNode*)iptr->hashNodeChunk_,procSlot); + }else{ + tIter->set(NULL,(TreeNode*)iptr->hashNodeChunk_,procSlot); + } + if (hIdxInfo->isUnique) tIter->setUnique(); } - if(predImpl) predImpl->setIfNoLeftRight(); + isClosed = false; return OK; } @@ -116,7 +127,6 @@ void* TupleIterator::next() DbRetVal rv = OK; if (fullTableScan == scanType_) { - if (NULL == pred_) { //no predicates @@ -125,26 +135,38 @@ void* TupleIterator::next() else { int offset=0; + bool isLargeSizeAllocator = cIter->isLargeSize(); void *val = predImpl->getValIfPointLookupOnInt(offset); char *tup = NULL; if (val != NULL) { - while (true) - { - tup = (char*)cIter->nextElement(); - if(NULL == tup) return NULL; - if (*(int*)val == *((int*)(tup+offset))) break; - } - return tup; + int value = *(int*)val; + if (isLargeSizeAllocator) { + while (true) + { + tup = (char*)cIter->nextElement(); + if(NULL == tup) return NULL; + if (value == *((int*)(tup+offset))) break; + } + return tup; + }else { + tup = (char*)cIter->nextElementIntMatch(value, offset); + return tup; + } } val = predImpl->getVal1IfBetweenOnInt(offset); if (val != NULL) { void *val2 = predImpl->getVal2IfBetweenOnInt(offset); + int value1 = *(int*)val; + int value2 = *(int*)val2; while (true) { - tup = (char*)cIter->nextElement(); + if(isLargeSizeAllocator) + tup = (char*)cIter->nextElement(); + else + tup = (char*)cIter->nextElementInt(); if(NULL == tup) return NULL; - if (*((int*)(tup+offset)) >= *(int*)val && - *((int*)(tup+offset)) <= *(int*)val2) break; + if (*((int*)(tup+offset)) >= value1 && + *((int*)(tup+offset)) <= value2) break; } return tup; } @@ -153,7 +175,10 @@ void* TupleIterator::next() bool result = false; while (!result) { - tuple = cIter->nextElement(); + if(isLargeSizeAllocator) + tuple = cIter->nextElement(); + else + tuple = cIter->nextElementInt(); if(NULL == tuple) return NULL; //predImpl->setTuple(tuple); printDebug(DM_Table, "Evaluating the predicate from fullTableScan"); @@ -162,11 +187,6 @@ void* TupleIterator::next() } }else if (hashIndexScan == scanType_) { - if (NULL == bIter) - { - //if there are no nodes in bucket bIter will be null - return NULL; - } //evaluate till it succeeds bool result = false; while (!result) @@ -203,7 +223,7 @@ void* TupleIterator::next() } //predImpl->setTuple(tuple); predImpl->evaluateForTable(result, (char*)tuple); - if(!result && (isBetInvolved() || isPointLookInvolved())) tIter->nextNode(); + if(!result && (isBetween || isPointLook)) tIter->nextNode(); } } return tuple; @@ -211,28 +231,20 @@ void* TupleIterator::next() DbRetVal TupleIterator::close() { - if (scanType_ == fullTableScan) - { - delete cIter; - cIter = NULL; - } else if (scanType_ == hashIndexScan) - { - delete bIter; - bIter = NULL; - } else if (scanType_ == treeIndexScan) - { - delete tIter; - tIter = NULL; - } - - scanType_ = unknownScan; + if (isClosed) return OK; + reset(); + isClosed = true; return OK; } void TupleIterator::reset() { DbRetVal rv = OK; - if (scanType_ == fullTableScan) *cIter = ((Chunk*)chunkPtr_)->getIterator(); - else if (scanType_ == hashIndexScan) if(bIter) bIter->reset(); - else if (scanType_ == treeIndexScan) if(tIter) tIter->reset(); + if (scanType_ == fullTableScan) { + if (cIter) *cIter = ((Chunk*)chunkPtr_)->getIterator(); + } + else if (scanType_ == hashIndexScan) { + if(bIter) bIter->reset(); + } + else if (scanType_ == treeIndexScan) { if(tIter) tIter->reset(); } } diff --git a/src/storage/UserManagerImpl.cxx b/src/storage/UserManagerImpl.cxx index 1163d6aa..469ce208 100644 --- a/src/storage/UserManagerImpl.cxx +++ b/src/storage/UserManagerImpl.cxx @@ -27,13 +27,14 @@ int UserManagerImpl::createUser(const char *name, const char *password) int ret = 0; //add entry to USER table CatalogTableUSER cUser(systemDatabase_); - cUser.insert(name, password); + ret = cUser.insert(name, password); if (0 != ret) { printError(ErrSysInternal, "Catalog table insert failed for the user %s",name); return ErrSysInternal; } + logFine(Conf::logger, "User Created %s" , name); return OK; } @@ -54,17 +55,18 @@ int UserManagerImpl::deleteUser(const char *name) "User %s not exists",name); return ErrNotExists; } + logFine(Conf::logger, "User Deleted %s" , name); return OK; } int UserManagerImpl::changePassword(const char *usrName, const char* newPasswd) { - if (!isDba) +/* if (!isDba) { printError(ErrNoPrivilege, "Only DBA privileged schema can change password for other users"); return ErrNoPrivilege; - } + }*/ int ret = 0; CatalogTableUSER cUser(systemDatabase_); ret = cUser.changePass(usrName, newPasswd ); @@ -74,6 +76,7 @@ int UserManagerImpl::changePassword(const char *usrName, const char* newPasswd) "Catalog table updation failed for user %s",usrName); return ErrSysInternal; } + logFine(Conf::logger, "Password changed for %s" ,usrName); return OK; } @@ -89,5 +92,18 @@ int UserManagerImpl::changePassword(const char* newPasswd) "Catalog table updation failed"); return ErrSysInternal; } + logFine(Conf::logger, "Password changed for %s" ,userName); return OK; } + +List UserManagerImpl::getAllUserNames(int *retval) +{ + DbRetVal ret = OK; + //to store the tuple pointer of the table + void *tptr =NULL; + CatalogTableUSER cUser(systemDatabase_); + List userList = cUser.getUserList(); + return userList; +} + + diff --git a/src/storage/Util.cxx b/src/storage/Util.cxx index cbf61164..d3541d98 100644 --- a/src/storage/Util.cxx +++ b/src/storage/Util.cxx @@ -1,6 +1,27 @@ #include #include +unsigned int Util::hashBinary(char *strVal, int length) +{ + unsigned int hval, g; + hval = 0; + char *str =strVal; + int iter = 0; + while (iter != length) + { + hval <<= 4; + hval += (unsigned int) *str++; + g = hval & ((unsigned int) 0xf << (32 - 4)); + if (g != 0) + { + hval ^= g >> (32 - 8); + hval ^= g; + } + iter++; + } + return hval; +} + DbRetVal GlobalUniqueID::create() { int key = Conf::config.getShmIDKey(); @@ -19,6 +40,7 @@ DbRetVal GlobalUniqueID::create() DbRetVal GlobalUniqueID::open() { + if (ptr != NULL) return OK; int key = Conf::config.getShmIDKey(); int id = os::shm_open(key, MAX_UNIQUE_ID *sizeof(int), 0666); if (-1 == id) { @@ -46,7 +68,8 @@ int GlobalUniqueID::getID(UniqueIDType type) { int *id = (int*)(((char*)ptr) + sizeof(int) * type); int oldVal = *id; - int ret = Mutex::CAS(id, oldVal, oldVal+1); + int newVal = oldVal + 1; + int ret = Mutex::CAS(id, oldVal, newVal); if (ret) return -1; return *id; } diff --git a/src/storage/VarHeapAllocator.cxx b/src/storage/VarHeapAllocator.cxx new file mode 100644 index 00000000..04624277 --- /dev/null +++ b/src/storage/VarHeapAllocator.cxx @@ -0,0 +1,202 @@ +#include +#include +#include + +void VarHeapAllocator::print() +{ + printf("\nTotal number of new allocation happened : %d",newAllocateCounter); + printf("\nTotal number of re allocation happened : %d",reAllocateCounter); + printf("\nTotal number of deallocation happened : %d",deallocateCounter); + printf("\nTotal number of page created : %d\n",pageCounter); +} +void VarHeapAllocator::initializeInfo(void *ptr) +{ + *(void **)ptr = top; + top = ptr; + usedBytes = 0; + offset = (char *)top+PAGEINFOSIZE; + *(short int *)((char *)offset+1) = pageSize- PAGEINFOSIZE-BLOCKINFOSIZE; +} +void VarHeapAllocator::init(int size,int pMode) +{ + mode = pMode; + initSize(size); +} +void VarHeapAllocator::initSize(int size) +{ + void *ptr; + ptr = calloc(size,1); + if(ptr == NULL) + { + printError(ErrOS, "unable to allocate memory of %d bytes", size); + return; + } + pageSize = size; + initializeInfo(ptr); + isInitialized = 1; + pageCounter++; +} + +void * VarHeapAllocator::allocate(int size) +{ + void *allocateptr, *ptr, *freeSpaceDetector, *pageDetector; + short int pageSizeCounter = 0, add; + short int isFound = 0; + + if(isInitialized != 1) + { + printError(ErrBadCall, "Error:not initialized"); + return NULL; + } + if(size > ( pageSize - PAGEINFOSIZE-(2*BLOCKINFOSIZE) )) + { + printError(ErrBadCall, "The requested size is greater than the page Size"); + return NULL; + } + if(mode ==0 ) + { + //printf("\ninside allocate offset = %u\tpagesize= %d\tusedmemory=%d\tmemoryrequested = %d",offset,pageSize,usedBytes, size); + if( ( usedBytes + size ) > ( pageSize - PAGEINFOSIZE ) ) + { + ptr = calloc(pageSize,1); + if(ptr == NULL) + { + printError(ErrOS, "unable to allocate memory of %d bytes",pageSize); + return NULL; + } + pageCounter++; + initializeInfo(ptr); + } + allocateptr = offset; + offset = (char *)offset+size; + usedBytes += size; + //printf("\nafter allocate offset = %u\tusedmemory=%d\tmemoryrequested = %d\treturn ptr = %u",offset,usedBytes, size,allocateptr); + return (allocateptr); + } + else if(mode == 1) + { + //printf("\nCursor is inside mode = 1"); + pageDetector = top; + int isAllocated, noOfBytes; + while(pageDetector) + { + isFound = 0; + pageSizeCounter = 0; + freeSpaceDetector = (char *)pageDetector+PAGEINFOSIZE; + pageSizeCounter += PAGEINFOSIZE; + isAllocated = *(char *)freeSpaceDetector; + noOfBytes = *(short int *)((char *)freeSpaceDetector+1); + //printf("\nStarting from the page:"); + //printf(":\nfreespacedetector is looking into the pointer: %d\n",freeSpaceDetector); + //printf("\nfinding allocation = %d and bytes = %d\n",isAllocated,noOfBytes); + while(pageSizeCounter+noOfBytes+BLOCKINFOSIZE < pageSize) + { + if(isAllocated == 0 && noOfBytes >= size+BLOCKINFOSIZE) + { + isFound = 1; + reAllocateCounter++; + break; + } + pageSizeCounter = pageSizeCounter+noOfBytes+BLOCKINFOSIZE; + freeSpaceDetector = (char *)freeSpaceDetector+noOfBytes+BLOCKINFOSIZE; + //printf("\nfreespacedetector is looking into the pointer = %u ",freeSpaceDetector); + isAllocated = *(char *)freeSpaceDetector; + noOfBytes = *(short int *)((char *)freeSpaceDetector+1); + //printf("\nfinding allocated = %d and bytes = %d\n",isAllocated,noOfBytes); + } + //printf("After searching the page (expect last block), pointer is at: %u",freeSpaceDetector); + if(isFound == 1) + break; + //printf(" searching the last block of the page, at: %u",freeSpaceDetector); + if(isFound == 0 && pageSizeCounter+noOfBytes+BLOCKINFOSIZE == pageSize) + { + if(isAllocated == 0 && noOfBytes >= size+BLOCKINFOSIZE) + { + isFound = 1; + newAllocateCounter++; + break; + } + } + pageDetector = *(void **)pageDetector; + //printf("next page at : %u",pageDetector); + } + if(pageDetector == NULL) + { + ptr = calloc(pageSize,1); + if(ptr == NULL) + { + printError(ErrOS, "unable to allocate memory of %d bytes",pageSize); + return NULL; + } + initializeInfo(ptr); + newAllocateCounter++; + pageCounter++; + freeSpaceDetector = (char *)top+PAGEINFOSIZE; + } + *(char *)freeSpaceDetector = 1; + int availMemory = *(short int *)((char *)freeSpaceDetector+1); + *(short int *)((char *)freeSpaceDetector+1) = size; + *(short int *)((char *)freeSpaceDetector+size+BLOCKINFOSIZE+1) = availMemory-size-BLOCKINFOSIZE; + //printf("\nHere we can get a free spase in side the current page: %d\n",freeSpaceDetector); + //printf("\nis allocated == %d and bytes = %d\n",*(char *)freeSpaceDetector,*(short int *)((char *)freeSpaceDetector+1)); + //printf("\n next block = %u\t allocated == %d and bytes = %d\n",(char *)freeSpaceDetector+size+BLOCKINFOSIZE,*((char *)freeSpaceDetector+size+BLOCKINFOSIZE),*(short int *)((char *)freeSpaceDetector+size+BLOCKINFOSIZE+1) ); + + } +} +void VarHeapAllocator::deallocate(void *ptr) +{ + //printf("\nBefore deAllocating the value at pointer is : %d",* (char *)ptr); + *(char *)ptr = 0; + //printf("\nAfter deAllocating the value at pointer is : %d",* (char *)ptr); + deallocateCounter++; +} + +void VarHeapAllocator::destroy() +{ + void *ptr, *temp; + ptr = top; + unsigned int add; + while(ptr) + { + temp = ptr; + ptr = *(void **)ptr; + //printf("deallocating %u",temp); + free(temp); + } +} + +/* +int main() +{ + int bsize; + VarHeapAllocator mAllocator; + mAllocator.init(50,1); + int i = 0, choice; + unsigned int ptr; + while(true) + { + cout << "enter the choice that u want"; + cin>> choice; + if(choice == 1) + { + cout << "please enter the memory in bytes that u want to allocate"; + cin >> bsize; + mAllocator.allocate(bsize); + } + else if(choice == 2) + { + cout << "please enter the memory address to deallocate"; + cin >> ptr; + } + else + { + // exit(1); + break; + } + } + + mAllocator.destroy(); + +} +*/ + diff --git a/src/storage/os.cxx b/src/storage/os.cxx index 15c4a975..65f35564 100644 --- a/src/storage/os.cxx +++ b/src/storage/os.cxx @@ -100,11 +100,21 @@ int os::closeFile(int fd) } int os::lockFile(int fd) { +#ifdef SOLARIS + //TODO + return 0; +#else return flock(fd, LOCK_EX); +#endif } int os::unlockFile(int fd) { +#ifdef SOLARIS + //TODO + return 0; +#else return ::flock(fd, LOCK_UN); +#endif } off_t os::lseek(int fildes, off_t offset, int whence) -- 2.11.4.GIT