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 // logInfo->data_ will have following info encapsulated.
314 // tupleptr + metadataPtr + nVarchars + varchar chunk ptr +
316 char *ptr
= (char *)logInfo
->data_
;
317 void *ptrToTuple
= (void *)*(long *)ptr
; ptr
+= sizeof(void *);
318 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
320 printError(ErrSysFatal
, "Fatal: Row is already not in use");
325 void *metaData
= (void *)*(long *)ptr
; ptr
+= sizeof(void *);
326 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
327 db
.setProcSlot(sysdb
->procSlot
);
329 int noOfVarchar
= *(int *)ptr
; ptr
+= sizeof(int);
330 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
; ptr
+= sizeof(void *);
331 void **ptrToVarchars
= (void **) ptr
;
332 for (int i
= 0; i
< noOfVarchar
; i
++) {
333 if (*(long *) ptrToVarchars
[i
] != 0L) {
334 vcchunk
->free(&db
, (void *)*(long *)ptrToVarchars
[i
]);
335 *(long *) ptrToVarchars
[i
] = 0L;
340 case DeleteOperation
:
342 // logInfo->data_ will have following info encapsulated.
343 // tupleptr + tuple length + actual tuple + metadataPtr +
344 // nVarchars + varchar chunk ptr + ptrs to varchars +
345 // size and value pairs for varchars
346 char *ptr
= (char *)logInfo
->data_
;
347 void *ptrToTuple
= (void *)*(long *)ptr
; ptr
+= sizeof(void *);
348 InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
350 printError(ErrSysFatal
, "Fatal: Row is already in use");
353 //data record will be intact as we have lock on that record
355 void *metaData
= (void *)*(long *)ptr
; ptr
+= sizeof(void *);
357 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
358 db
.setProcSlot(sysdb
->procSlot
);
360 int noOfVarchar
= *(int *) ptr
; ptr
+= sizeof(int);
361 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
; ptr
+= sizeof(void *);
362 void **ptrToVarchars
= (void **) ptr
;
363 ptr
+= noOfVarchar
* sizeof (void *);
364 char *lenValPtr
= (char *) ptr
;
365 for (int i
= 0; i
< noOfVarchar
; i
++) {
366 int len
= *(int *) lenValPtr
; lenValPtr
+= sizeof(int);
368 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
369 strcpy((char *)ptr
, lenValPtr
); lenValPtr
+= len
;
370 *(long *) ptrToVarchars
[i
] = (long)ptr
;
371 } else *(long *) ptrToVarchars
[i
] = 0L;
375 case UpdateOperation
:
377 // logInfo->data_ will have following info encapsulated.
378 // tupleptr + tuple length + actual tuple + metadataPtr +
379 // nVarchars + varchar chunk ptr + ptrs to varchars +
380 // size and value pairs for varchars
381 char *ptr
= (char *)logInfo
->data_
;
382 void *ptrToTuple
= (void *)*(long *)ptr
; ptr
+= sizeof(void *); InUse
*isUsed
= ((InUse
*)(ptrToTuple
) - 1);
384 printError(ErrSysFatal
, "Fatal: Row is not in use during update rollback");
386 int tupleLen
= *(int *) ptr
; ptr
+= sizeof(int);
387 void *tuple
= ptr
; ptr
+= tupleLen
;
388 void *metaData
= (void *)*(long *)ptr
; ptr
+= sizeof(void *);
390 db
.setMetaDataPtr((DatabaseMetaData
*) metaData
);
391 db
.setProcSlot(sysdb
->procSlot
);
393 int noOfVarchar
= *(int *) ptr
; ptr
+= sizeof(int);
394 Chunk
*vcchunk
= (Chunk
*) *(long *)ptr
; ptr
+= sizeof(void *);
395 void **ptrToVarchars
= (void **) ptr
;
396 ptr
+= noOfVarchar
* sizeof (void *);
397 char *lenValPtr
= (char *) ptr
;
398 for (int i
= 0; i
< noOfVarchar
; i
++) {
399 if (*(long *) ptrToVarchars
[i
] != 0L) {
400 vcchunk
->free(&db
, (void *)*(long *) ptrToVarchars
[i
]);
401 *(long *) ptrToVarchars
[i
] = 0L;
404 os::memcpy(ptrToTuple
, tuple
, tupleLen
);
405 for (int i
= 0; i
< noOfVarchar
; i
++) {
406 int len
= *(int *) lenValPtr
; lenValPtr
+= sizeof(int);
408 void *ptr
= vcchunk
->allocate(&db
, len
, &rv
);
409 strcpy((char *)ptr
, lenValPtr
); lenValPtr
+= len
;
410 *(long *) ptrToVarchars
[i
] = (long) ptr
;
411 } else *(long *) ptrToVarchars
[i
] = 0L;
415 case InsertHashIndexOperation
:
417 HashIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
418 + sizeof(UndoLogInfo
));
421 case DeleteHashIndexOperation
:
423 HashIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
424 + sizeof(UndoLogInfo
));
427 case InsertTreeIndexOperation
:
429 TreeIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
430 + sizeof(UndoLogInfo
));
433 case DeleteTreeIndexOperation
:
435 TreeIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
436 + sizeof(UndoLogInfo
));
441 printError(ErrSysFatal
, "Illegal undo log type");
445 chunk
->free(sysdb
, logInfo
);