1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 ***************************************************************************/
16 #include<Transaction.h>
20 #include<CatalogTables.h>
23 //Code assumes that only one thread can work on a transaction
24 DbRetVal
Transaction::insertIntoHasList(Database
*sysdb
, LockHashNode
*node
)
27 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
29 TransHasNode
*hasNode
= NULL
; //(TransHasNode*)chunk->allocate(sysdb, &rv);
31 int totalTries
= Conf::config
.getMutexRetries();
32 while (tries
< totalTries
)
35 hasNode
= (TransHasNode
*)chunk
->allocate(sysdb
, &rv
);
36 if (hasNode
!=NULL
) break;
37 if (rv
!= ErrLockTimeOut
)
39 printError(rv
, "Unable to allocate trans has node");
46 printError(rv
, "Could not allocate Trans has node after %d retry", tries
);
49 printDebug(DM_Transaction
, "insertIntoHasList new TransHasNode created:%x",
51 hasNode
->node_
= node
;
52 hasNode
->next_
= NULL
;
53 if (NULL
== hasLockList_
)
55 printDebug(DM_Transaction
, "hasLockList is null:It is now %x",hasNode
);
56 hasLockList_
= hasNode
;
60 TransHasNode
*it
= hasLockList_
;
61 while (NULL
!= it
->next_
) { it
= it
->next_
; }
63 printDebug(DM_Transaction
, "Added to hasLockList at end:%x",it
);
64 logFinest(Conf::logger
, "Added locknode:%x to hasLockList", hasNode
->node_
);
68 DbRetVal
Transaction::removeFromHasList(Database
*sysdb
, void *tuple
)
70 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
71 TransHasNode
*iter
= hasLockList_
, *prev
= hasLockList_
;
74 printError(ErrNotFound
, "Fatal:HasList is empty");
79 if (tuple
== iter
->node_
->ptrToTuple_
)
81 prev
->next_
= iter
->next_
;
82 chunk
->free(sysdb
, iter
);
83 if (iter
== hasLockList_
) hasLockList_
= NULL
;
84 logFinest(Conf::logger
, "Removed locknode:%x from hasLockList",
92 printError(ErrNotFound
, "Fatal:There is no tuple lock in has list for tuple:%x", tuple
);
93 //TEMP::for debugging.do not remove
98 printError(ErrWarning, "Element in hasList: %d %x: %x:%d\n", cnt, iter->node_, iter->node_->ptrToTuple_ , *(int*)iter->node_->ptrToTuple_);
106 DbRetVal
Transaction::releaseAllLocks(LockManager
*lockManager_
)
108 Database
*sysdb
=lockManager_
->systemDatabase_
;
109 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
110 TransHasNode
*iter
= hasLockList_
, *prev
;
116 printDebug(DM_Transaction
, "Releasing lock %x",prev
->node_
->ptrToTuple_
);
117 logFinest(Conf::logger
, "Releasing lock for tuple:%x",prev
->node_
->ptrToTuple_
);
118 rv
= lockManager_
->releaseLock(prev
->node_
->ptrToTuple_
);
119 chunk
->free(sysdb
, prev
);
124 bool Transaction::findInHasList(Database
*sysdb
, LockHashNode
*node
)
126 TransHasNode
*iter
= hasLockList_
;
129 if (iter
->node_
== node
) return true;
135 DbRetVal
Transaction::appendUndoLog(Database
*sysdb
, OperationType type
,
136 void *data
, size_t size
)
139 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, data
, size
, &rv
);
140 if (logInfo
== NULL
) return rv
;
141 if (size
) os::memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, size
);
143 printDebug(DM_Transaction
, "creating undo log and append %x optype:%d",
150 DbRetVal
Transaction::appendLogicalUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
, void* indexPtr
)
153 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, data
, size
, &rv
);
154 if (logInfo
== NULL
) return rv
;
155 char **indPtr
= (char**)((char*)logInfo
+ sizeof(UndoLogInfo
));
156 *indPtr
= (char*) indexPtr
;
158 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
162 DbRetVal
Transaction::appendLogicalHashUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
)
165 HashUndoLogInfo
*hInfo
= (HashUndoLogInfo
*) data
;
166 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, hInfo
->tuple_
, size
, &rv
);
167 if (logInfo
== NULL
) return rv
;
168 memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, sizeof(HashUndoLogInfo
));
170 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
173 DbRetVal
Transaction::appendLogicalTreeUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
)
176 TreeUndoLogInfo
*hInfo
= (TreeUndoLogInfo
*) data
;
177 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, hInfo
->tuple_
, size
, &rv
);
178 if (logInfo
== NULL
) return rv
;
179 memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, sizeof(TreeUndoLogInfo
));
181 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
185 UndoLogInfo
* Transaction::createUndoLog(Database
*sysdb
, OperationType type
, void *data
,
186 size_t size
, DbRetVal
*rv
)
188 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
189 int reqSize
= size
+ sizeof(UndoLogInfo
);
190 UndoLogInfo
*logInfo
= NULL
;
192 int totalTries
= Conf::config
.getMutexRetries();
193 while (tries
< totalTries
)
196 logInfo
= (UndoLogInfo
*)chunk
->allocate(sysdb
, reqSize
, rv
);
197 if (logInfo
!=NULL
) break;
198 if (*rv
!= ErrLockTimeOut
)
200 printError(*rv
, "Unable to allocate undo log");
206 if (logInfo
== NULL
) {
207 printError(*rv
, "Unable to allocate undo log record after %d retries", tries
);
210 logInfo
->data_
= (char *)logInfo
+ sizeof(UndoLogInfo
);
211 logInfo
->opType_
= type
;
212 logInfo
->size_
= size
;
213 logInfo
->next_
= NULL
;
217 void Transaction::addAtBegin(UndoLogInfo
* logInfo
)
219 //add it to the begin of the log list
220 logInfo
->next_
= firstUndoLog_
;
221 firstUndoLog_
= logInfo
;
225 UndoLogInfo
* Transaction::popUndoLog()
227 UndoLogInfo
*iter
= firstUndoLog_
, *prev
= firstUndoLog_
;
233 firstUndoLog_
= iter
;
238 int Transaction::noOfUndoLogs()
240 UndoLogInfo
*iter
= firstUndoLog_
;
249 void Transaction::printDebugInfo(Database
*sysdb
)
251 printf("<TransactionInfo>\n");
252 if (waitLock_
!= NULL
)
254 printf("<WaitLock>");
256 printf("</WaitLock>");
259 printf("<UndoLogs>\n");
260 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
261 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
262 UndoLogInfo
*iter
= firstUndoLog_
;
270 printf("</TotalNodes> %d </TotalNodes>\n", count
);
271 printf("</UndoLogs>\n");
273 printf("<TransHasList>\n");
274 chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
275 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
276 TransHasNode
*hasIter
= hasLockList_
;
278 while (NULL
!= hasIter
)
281 hasIter
= hasIter
->next_
;
284 printf("</TotalNodes> %d </TotalNodes>\n", count
);
285 printf("</TransHasList>\n");
287 printf("</TransactionInfo>\n");
290 DbRetVal
Transaction::removeUndoLogs(Database
*sysdb
)
292 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
293 UndoLogInfo
*logInfo
= NULL
;
294 while(NULL
!= (logInfo
= popUndoLog()))
296 chunk
->free(sysdb
, logInfo
);
302 DbRetVal
Transaction::applyUndoLogs(Database
*sysdb
)
304 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
305 UndoLogInfo
*logInfo
= NULL
;
306 while(NULL
!= (logInfo
= popUndoLog()))
308 logFinest(Conf::logger
, "Apply undo log type:%d", logInfo
->opType_
);
309 switch(logInfo
->opType_
)
311 case InsertOperation
:
313 char *ptr
= (char *)logInfo
->data_
;
314 void *ptrToTuple
= (void *)*(long *)ptr
;
315 ptr
+= sizeof(void *);
316 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
318 printError(ErrSysFatal
, "Fatal: Row is already not in use");
321 handleVarcharUndoInsert(sysdb
, ptr
);
324 case DeleteOperation
:
326 char *ptr
= (char *)logInfo
->data_
;
327 void *ptrToTuple
= (void *)*(long *)ptr
;
328 ptr
+= sizeof(void *);
329 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
331 printError(ErrSysFatal
, "Fatal: Row is already in use");
334 //data record will be intact as we have lock on that record
335 handleVarcharUndoDelete(sysdb
, ptr
);
338 case UpdateOperation
:
340 char *ptr
= (char *)logInfo
->data_
;
341 void *ptrToTuple
= (void *)*(long *)ptr
;
342 ptr
+= sizeof(void *);
343 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
345 printError(ErrSysFatal
, "Fatal: Row is not in use during update rollback");
347 handleVarcharUndoUpdate(sysdb
, ptr
, ptrToTuple
);
350 case InsertHashIndexOperation
:
352 HashIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
353 + sizeof(UndoLogInfo
));
356 case DeleteHashIndexOperation
:
358 HashIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
359 + sizeof(UndoLogInfo
));
362 case InsertTreeIndexOperation
:
364 TreeIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
365 + sizeof(UndoLogInfo
));
368 case DeleteTreeIndexOperation
:
370 TreeIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
371 + sizeof(UndoLogInfo
));
376 printError(ErrSysFatal
, "Illegal undo log type");
380 chunk
->free(sysdb
, logInfo
);
384 DbRetVal
Transaction::handleVarcharUndoInsert(Database
*sysdb
, char *ptr
)
386 // ptr will have following info encapsulated.
387 // metadataPtr + nVarchars + varchar chunk ptr +
391 void *metaData
= (void *)*(long *)ptr
;
392 ptr
+= sizeof(void *);
393 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
394 db
.setProcSlot(sysdb
->procSlot
);
396 int noOfVarchar
= *(int *)ptr
;
398 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
399 ptr
+= sizeof(void *);
400 void **ptrToVarchars
= (void **) ptr
;
401 for (int i
= 0; i
< noOfVarchar
; i
++) {
402 if (*(long *) ptrToVarchars
[i
] != 0L) {
403 vcchunk
->free(&db
, (void *)*(long *)ptrToVarchars
[i
]);
404 *(long *) ptrToVarchars
[i
] = 0L;
410 DbRetVal
Transaction::handleVarcharUndoDelete(Database
*sysdb
, char *ptr
)
412 // ptr will have following info encapsulated.
413 // metadataPtr + nVarchars + varchar chunk ptr + ptrs to varchars +
414 // size and value pairs for varchars
415 void *metaData
= (void *)*(long *)ptr
;
416 ptr
+= sizeof(void *);
418 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
419 db
.setProcSlot(sysdb
->procSlot
);
421 int noOfVarchar
= *(int *) ptr
;
423 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
424 ptr
+= sizeof(void *);
425 void **ptrToVarchars
= (void **) ptr
;
426 ptr
+= noOfVarchar
* sizeof (void *);
427 char *lenValPtr
= (char *) ptr
;
428 for (int i
= 0; i
< noOfVarchar
; i
++) {
429 int len
= *(int *) lenValPtr
;
430 lenValPtr
+= sizeof(int);
432 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
433 strcpy((char *)ptr
, lenValPtr
);
435 *(long *) ptrToVarchars
[i
] = (long)ptr
;
437 *(long *) ptrToVarchars
[i
] = 0L;
442 DbRetVal
Transaction::handleVarcharUndoUpdate(Database
*sysdb
, char *ptr
, void *ptrToTuple
)
444 // logInfo->data_ will have following info encapsulated.
445 // tupleptr + tuple length + actual tuple + metadataPtr +
446 // nVarchars + varchar chunk ptr + ptrs to varchars +
447 // size and value pairs for varchars
449 int tupleLen
= *(int *) ptr
;
453 void *metaData
= (void *)*(long *)ptr
;
454 ptr
+= sizeof(void *);
456 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
457 db
.setProcSlot(sysdb
->procSlot
);
459 int noOfVarchar
= *(int *) ptr
;
461 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
462 ptr
+= sizeof(void *);
463 void **ptrToVarchars
= (void **) ptr
;
464 ptr
+= noOfVarchar
* sizeof (void *);
465 char *lenValPtr
= (char *) ptr
;
466 for (int i
= 0; i
< noOfVarchar
; i
++) {
467 if (*(long *) ptrToVarchars
[i
] != 0L) {
468 vcchunk
->free(&db
, (void *)*(long *) ptrToVarchars
[i
]);
469 *(long *) ptrToVarchars
[i
] = 0L;
472 os::memcpy(ptrToTuple
, tuple
, tupleLen
);
473 for (int i
= 0; i
< noOfVarchar
; i
++) {
474 int len
= *(int *) lenValPtr
; lenValPtr
+= sizeof(int);
476 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
477 strcpy((char *)ptr
, lenValPtr
);
479 *(long *) ptrToVarchars
[i
] = (long) ptr
;
481 *(long *) ptrToVarchars
[i
] = 0L;