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
);
184 DbRetVal
Transaction::appendLogicalTrieUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
)
187 TrieUndoLogInfo
*hInfo
= (TrieUndoLogInfo
*) data
;
188 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, hInfo
->tuple_
, size
, &rv
);
189 if (logInfo
== NULL
) return rv
;
190 memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, sizeof(TrieUndoLogInfo
));
192 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
196 UndoLogInfo
* Transaction::createUndoLog(Database
*sysdb
, OperationType type
, void *data
,
197 size_t size
, DbRetVal
*rv
)
199 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
200 int reqSize
= size
+ sizeof(UndoLogInfo
);
201 UndoLogInfo
*logInfo
= NULL
;
203 int totalTries
= Conf::config
.getMutexRetries();
204 while (tries
< totalTries
)
207 logInfo
= (UndoLogInfo
*)chunk
->allocate(sysdb
, reqSize
, rv
);
208 if (logInfo
!=NULL
) break;
209 if (*rv
!= ErrLockTimeOut
)
211 printError(*rv
, "Unable to allocate undo log");
217 if (logInfo
== NULL
) {
218 printError(*rv
, "Unable to allocate undo log record after %d retries", tries
);
221 logInfo
->data_
= (char *)logInfo
+ sizeof(UndoLogInfo
);
222 logInfo
->opType_
= type
;
223 logInfo
->size_
= size
;
224 logInfo
->next_
= NULL
;
228 void Transaction::addAtBegin(UndoLogInfo
* logInfo
)
230 //add it to the begin of the log list
231 logInfo
->next_
= firstUndoLog_
;
232 firstUndoLog_
= logInfo
;
236 UndoLogInfo
* Transaction::popUndoLog()
238 UndoLogInfo
*iter
= firstUndoLog_
, *prev
= firstUndoLog_
;
244 firstUndoLog_
= iter
;
249 int Transaction::noOfUndoLogs()
251 UndoLogInfo
*iter
= firstUndoLog_
;
260 void Transaction::printDebugInfo(Database
*sysdb
)
262 printf("<TransactionInfo>\n");
263 if (waitLock_
!= NULL
)
265 printf("<WaitLock>");
267 printf("</WaitLock>");
270 printf("<UndoLogs>\n");
271 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
272 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
273 UndoLogInfo
*iter
= firstUndoLog_
;
281 printf("</TotalNodes> %d </TotalNodes>\n", count
);
282 printf("</UndoLogs>\n");
284 printf("<TransHasList>\n");
285 chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
286 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
287 TransHasNode
*hasIter
= hasLockList_
;
289 while (NULL
!= hasIter
)
292 hasIter
= hasIter
->next_
;
295 printf("</TotalNodes> %d </TotalNodes>\n", count
);
296 printf("</TransHasList>\n");
298 printf("</TransactionInfo>\n");
301 DbRetVal
Transaction::removeUndoLogs(Database
*sysdb
)
303 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
304 UndoLogInfo
*logInfo
= NULL
;
305 while(NULL
!= (logInfo
= popUndoLog()))
307 chunk
->free(sysdb
, logInfo
);
313 DbRetVal
Transaction::applyUndoLogs(Database
*sysdb
)
315 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
316 UndoLogInfo
*logInfo
= NULL
;
317 while(NULL
!= (logInfo
= popUndoLog()))
319 logFinest(Conf::logger
, "Apply undo log type:%d", logInfo
->opType_
);
320 switch(logInfo
->opType_
)
322 case InsertOperation
:
324 char *ptr
= (char *)logInfo
->data_
;
325 void *ptrToTuple
= (void *)*(long *)ptr
;
326 ptr
+= sizeof(void *);
327 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
329 printError(ErrSysFatal
, "Fatal: Row is already not in use");
332 handleVarcharUndoInsert(sysdb
, ptr
);
335 case DeleteOperation
:
337 char *ptr
= (char *)logInfo
->data_
;
338 void *ptrToTuple
= (void *)*(long *)ptr
;
339 ptr
+= sizeof(void *);
340 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
342 printError(ErrSysFatal
, "Fatal: Row is already in use");
345 //data record will be intact as we have lock on that record
346 handleVarcharUndoDelete(sysdb
, ptr
);
349 case UpdateOperation
:
351 char *ptr
= (char *)logInfo
->data_
;
352 void *ptrToTuple
= (void *)*(long *)ptr
;
353 ptr
+= sizeof(void *);
354 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
356 printError(ErrSysFatal
, "Fatal: Row is not in use during update rollback");
358 handleVarcharUndoUpdate(sysdb
, ptr
, ptrToTuple
);
361 case InsertHashIndexOperation
:
363 HashIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
364 + sizeof(UndoLogInfo
));
367 case DeleteHashIndexOperation
:
369 HashIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
370 + sizeof(UndoLogInfo
));
373 case InsertTreeIndexOperation
:
375 TreeIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
376 + sizeof(UndoLogInfo
));
379 case DeleteTreeIndexOperation
:
381 TreeIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
382 + sizeof(UndoLogInfo
));
385 case InsertTrieIndexOperation
:
387 TrieIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
388 + sizeof(UndoLogInfo
));
391 case DeleteTrieIndexOperation
:
393 TrieIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
394 + sizeof(UndoLogInfo
));
399 printError(ErrSysFatal
, "Illegal undo log type");
403 chunk
->free(sysdb
, logInfo
);
407 DbRetVal
Transaction::handleVarcharUndoInsert(Database
*sysdb
, char *ptr
)
409 // ptr will have following info encapsulated.
410 // metadataPtr + nVarchars + varchar chunk ptr +
414 void *metaData
= (void *)*(long *)ptr
;
415 ptr
+= sizeof(void *);
416 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
417 db
.setProcSlot(sysdb
->procSlot
);
419 int noOfVarchar
= *(int *)ptr
;
421 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
422 ptr
+= sizeof(void *);
423 void **ptrToVarchars
= (void **) ptr
;
424 for (int i
= 0; i
< noOfVarchar
; i
++) {
425 if (*(long *) ptrToVarchars
[i
] != 0L) {
426 vcchunk
->free(&db
, (void *)*(long *)ptrToVarchars
[i
]);
427 *(long *) ptrToVarchars
[i
] = 0L;
433 DbRetVal
Transaction::handleVarcharUndoDelete(Database
*sysdb
, char *ptr
)
435 // ptr will have following info encapsulated.
436 // metadataPtr + nVarchars + varchar chunk ptr + ptrs to varchars +
437 // size and value pairs for varchars
438 void *metaData
= (void *)*(long *)ptr
;
439 ptr
+= sizeof(void *);
441 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
442 db
.setProcSlot(sysdb
->procSlot
);
444 int noOfVarchar
= *(int *) ptr
;
446 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
447 ptr
+= sizeof(void *);
448 void **ptrToVarchars
= (void **) ptr
;
449 ptr
+= noOfVarchar
* sizeof (void *);
450 char *lenValPtr
= (char *) ptr
;
451 for (int i
= 0; i
< noOfVarchar
; i
++) {
452 int len
= *(int *) lenValPtr
;
453 lenValPtr
+= sizeof(int);
455 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
456 strcpy((char *)ptr
, lenValPtr
);
458 *(long *) ptrToVarchars
[i
] = (long)ptr
;
460 *(long *) ptrToVarchars
[i
] = 0L;
465 DbRetVal
Transaction::handleVarcharUndoUpdate(Database
*sysdb
, char *ptr
, void *ptrToTuple
)
467 // logInfo->data_ will have following info encapsulated.
468 // tupleptr + tuple length + actual tuple + metadataPtr +
469 // nVarchars + varchar chunk ptr + ptrs to varchars +
470 // size and value pairs for varchars
472 int tupleLen
= *(int *) ptr
;
476 void *metaData
= (void *)*(long *)ptr
;
477 ptr
+= sizeof(void *);
479 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
480 db
.setProcSlot(sysdb
->procSlot
);
482 int noOfVarchar
= *(int *) ptr
;
484 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
;
485 ptr
+= sizeof(void *);
486 void **ptrToVarchars
= (void **) ptr
;
487 ptr
+= noOfVarchar
* sizeof (void *);
488 char *lenValPtr
= (char *) ptr
;
489 for (int i
= 0; i
< noOfVarchar
; i
++) {
490 if (*(long *) ptrToVarchars
[i
] != 0L) {
491 vcchunk
->free(&db
, (void *)*(long *) ptrToVarchars
[i
]);
492 *(long *) ptrToVarchars
[i
] = 0L;
495 os::memcpy(ptrToTuple
, tuple
, tupleLen
);
496 for (int i
= 0; i
< noOfVarchar
; i
++) {
497 int len
= *(int *) lenValPtr
; lenValPtr
+= sizeof(int);
499 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
500 strcpy((char *)ptr
, lenValPtr
);
502 *(long *) ptrToVarchars
[i
] = (long) ptr
;
504 *(long *) ptrToVarchars
[i
] = 0L;