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
);
67 DbRetVal
Transaction::removeFromHasList(Database
*sysdb
, void *tuple
)
69 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
70 TransHasNode
*iter
= hasLockList_
, *prev
= hasLockList_
;
73 printError(ErrNotFound
, "Fatal:HasList is empty");
78 if (tuple
== iter
->node_
->ptrToTuple_
)
80 prev
->next_
= iter
->next_
;
81 chunk
->free(sysdb
, iter
);
82 if (iter
== hasLockList_
) hasLockList_
= NULL
;
89 printError(ErrNotFound
, "Fatal:There is no tuple lock in has list for tuple:%x", tuple
);
95 printError(ErrWarning
, "Element in hasList: %d %x: %x:%d\n", cnt
, iter
->node_
, iter
->node_
->ptrToTuple_
, *(int*)iter
->node_
->ptrToTuple_
);
103 DbRetVal
Transaction::releaseAllLocks(LockManager
*lockManager_
)
105 Database
*sysdb
=lockManager_
->systemDatabase_
;
106 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
107 TransHasNode
*iter
= hasLockList_
, *prev
;
113 printDebug(DM_Transaction
, "Releasing lock %x",prev
->node_
->ptrToTuple_
);
114 rv
= lockManager_
->releaseLock(prev
->node_
->ptrToTuple_
);
115 chunk
->free(sysdb
, prev
);
120 bool Transaction::findInHasList(Database
*sysdb
, LockHashNode
*node
)
122 TransHasNode
*iter
= hasLockList_
;
125 if (iter
->node_
== node
) return true;
131 DbRetVal
Transaction::appendUndoLog(Database
*sysdb
, OperationType type
,
132 void *data
, size_t size
)
135 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, data
, size
, &rv
);
136 if (logInfo
== NULL
) return rv
;
137 if (size
) os::memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, size
);
139 printDebug(DM_Transaction
, "creating undo log and append %x optype:%d",
146 DbRetVal
Transaction::appendLogicalUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
, void* indexPtr
)
149 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, data
, size
, &rv
);
150 if (logInfo
== NULL
) return rv
;
151 char **indPtr
= (char**)((char*)logInfo
+ sizeof(UndoLogInfo
));
152 *indPtr
= (char*) indexPtr
;
154 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
158 DbRetVal
Transaction::appendLogicalHashUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
)
161 HashUndoLogInfo
*hInfo
= (HashUndoLogInfo
*) data
;
162 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, hInfo
->tuple_
, size
, &rv
);
163 if (logInfo
== NULL
) return rv
;
164 memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, sizeof(HashUndoLogInfo
));
166 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
169 DbRetVal
Transaction::appendLogicalTreeUndoLog(Database
*sysdb
, OperationType type
, void *data
, size_t size
)
172 TreeUndoLogInfo
*hInfo
= (TreeUndoLogInfo
*) data
;
173 UndoLogInfo
*logInfo
= createUndoLog(sysdb
, type
, hInfo
->tuple_
, size
, &rv
);
174 if (logInfo
== NULL
) return rv
;
175 memcpy((char*)logInfo
+ sizeof(UndoLogInfo
), data
, sizeof(TreeUndoLogInfo
));
177 printDebug(DM_Transaction
, "creating logical undo log and append %x optype:%d", logInfo
, type
);
181 UndoLogInfo
* Transaction::createUndoLog(Database
*sysdb
, OperationType type
, void *data
,
182 size_t size
, DbRetVal
*rv
)
184 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
185 int reqSize
= size
+ sizeof(UndoLogInfo
);
186 UndoLogInfo
*logInfo
= NULL
;
188 int totalTries
= Conf::config
.getMutexRetries();
189 while (tries
< totalTries
)
192 logInfo
= (UndoLogInfo
*)chunk
->allocate(sysdb
, reqSize
, rv
);
193 if (logInfo
!=NULL
) break;
194 if (*rv
!= ErrLockTimeOut
)
196 printError(*rv
, "Unable to allocate undo log");
199 //printError (ErrWarning, Undo Log Alloc: LockTimeOut Retry:%d", tries);
203 if (logInfo
== NULL
) {
204 printError(*rv
, "Unable to allocate undo log record after %d retries", tries
);
207 logInfo
->opType_
= type
;
208 logInfo
->ptrToTuple_
= data
;
209 logInfo
->size_
= size
;
210 logInfo
->next_
= NULL
;
214 void Transaction::addAtBegin(UndoLogInfo
* logInfo
)
216 //add it to the begin of the log list
217 logInfo
->next_
= firstUndoLog_
;
218 firstUndoLog_
= logInfo
;
222 UndoLogInfo
* Transaction::popUndoLog()
224 UndoLogInfo
*iter
= firstUndoLog_
, *prev
= firstUndoLog_
;
230 firstUndoLog_
= iter
;
235 int Transaction::noOfUndoLogs()
237 UndoLogInfo
*iter
= firstUndoLog_
;
246 void Transaction::printDebugInfo(Database
*sysdb
)
248 printf("<TransactionInfo>\n");
249 if (waitLock_
!= NULL
)
251 printf("<WaitLock>");
253 printf("</WaitLock>");
256 printf("<UndoLogs>\n");
257 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
258 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
259 UndoLogInfo
*iter
= firstUndoLog_
;
267 printf("</TotalNodes> %d </TotalNodes>\n", count
);
268 printf("</UndoLogs>\n");
270 printf("<TransHasList>\n");
271 chunk
= sysdb
->getSystemDatabaseChunk(TransHasTableId
);
272 printf(" <TotalPages> %d </TotalPages>\n", chunk
->totalPages());
273 TransHasNode
*hasIter
= hasLockList_
;
275 while (NULL
!= hasIter
)
278 hasIter
= hasIter
->next_
;
281 printf("</TotalNodes> %d </TotalNodes>\n", count
);
282 printf("</TransHasList>\n");
284 printf("</TransactionInfo>\n");
287 DbRetVal
Transaction::removeUndoLogs(Database
*sysdb
)
289 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
290 UndoLogInfo
*logInfo
= NULL
;
291 while(NULL
!= (logInfo
= popUndoLog()))
293 chunk
->free(sysdb
, logInfo
);
299 DbRetVal
Transaction::applyUndoLogs(Database
*sysdb
)
301 Chunk
*chunk
= sysdb
->getSystemDatabaseChunk(UndoLogTableID
);
302 UndoLogInfo
*logInfo
= NULL
;
303 while(NULL
!= (logInfo
= popUndoLog()))
305 switch(logInfo
->opType_
)
307 case InsertOperation
:
309 int *isUsed
= ((int*)(logInfo
->ptrToTuple_
) - 1);
311 printError(ErrSysFatal
, "Fatal: Row is already not in use");
314 //May memcpy is not needed as no one will update this
315 //as lock is taken on this tuple
316 os::memcpy(logInfo
->ptrToTuple_
, (char*) logInfo
+
317 sizeof(UndoLogInfo
), logInfo
->size_
);
320 case DeleteOperation
:
322 int *isUsed
= ((int*)(logInfo
->ptrToTuple_
) - 1);
324 printError(ErrSysFatal
, "Fatal: Row is already in use");
327 /*os::memcpy(logInfo->ptrToTuple_, (char*) logInfo +
328 sizeof(UndoLogInfo), logInfo->size_);*/
331 case UpdateOperation
:
333 int *isUsed
= ((int*)(logInfo
->ptrToTuple_
) - 1);
335 printError(ErrSysFatal
, "Fatal: Row is not in use during update rollback");
337 os::memcpy(logInfo
->ptrToTuple_
, (char*) logInfo
+
338 sizeof(UndoLogInfo
), logInfo
->size_
);
341 case InsertHashIndexOperation
:
342 HashIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
343 + sizeof(UndoLogInfo
));
345 //case UpdateHashIndexOperation:
346 //HashIndex::updateLogicalUndoLog((char *)logInfo
347 // + sizeof(UndoLogInfo));
349 case DeleteHashIndexOperation
:
350 HashIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
351 + sizeof(UndoLogInfo
));
353 case InsertTreeIndexOperation
:
354 TreeIndex::deleteLogicalUndoLog(sysdb
, (char *)logInfo
355 + sizeof(UndoLogInfo
));
357 case DeleteTreeIndexOperation
:
358 TreeIndex::insertLogicalUndoLog(sysdb
, (char *)logInfo
359 + sizeof(UndoLogInfo
));
362 chunk
->free(sysdb
, logInfo
);