FreeBSD Porting
[csql.git] / src / storage / Transaction.cxx
blob6d651d22d8cae2ae1273c5f461874b3f25e986bf
1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
4 * *
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. *
9 * *
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. *
14 * *
15 ***************************************************************************/
16 #include<Transaction.h>
17 #include<Lock.h>
18 #include<Database.h>
19 #include<Allocator.h>
20 #include<CatalogTables.h>
21 #include<Debug.h>
23 //Code assumes that only one thread can work on a transaction
24 DbRetVal Transaction::insertIntoHasList(Database *sysdb, LockHashNode *node)
26 //allocate lock node
27 Chunk *chunk = sysdb->getSystemDatabaseChunk(TransHasTableId);
28 DbRetVal rv = OK;
29 TransHasNode *hasNode = NULL; //(TransHasNode*)chunk->allocate(sysdb, &rv);
30 int tries=0;
31 int totalTries = Conf::config.getMutexRetries();
32 while (tries < totalTries)
34 rv = OK;
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");
40 return rv;
42 tries++;
44 if (NULL == hasNode)
46 printError(rv, "Could not allocate Trans has node after %d retry", tries);
47 return rv;
49 printDebug(DM_Transaction, "insertIntoHasList new TransHasNode created:%x",
50 hasNode);
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;
57 return OK;
60 TransHasNode *it = hasLockList_;
61 while (NULL != it->next_) { it = it->next_; }
62 it->next_ = hasNode;
63 printDebug(DM_Transaction, "Added to hasLockList at end:%x",it);
64 return OK;
67 DbRetVal Transaction::removeFromHasList(Database *sysdb, void *tuple)
69 Chunk *chunk = sysdb->getSystemDatabaseChunk(TransHasTableId);
70 TransHasNode *iter = hasLockList_, *prev = hasLockList_;
71 if (NULL == iter)
73 printError(ErrNotFound, "Fatal:HasList is empty");
74 return ErrNotFound;
76 while (iter != NULL)
78 if (tuple == iter->node_->ptrToTuple_)
80 prev->next_ = iter->next_;
81 chunk->free(sysdb, iter);
82 if (iter == hasLockList_) hasLockList_ = NULL;
83 return OK;
85 prev = iter;
86 iter = iter->next_;
88 printStackTrace();
89 printError(ErrNotFound, "Fatal:There is no tuple lock in has list for tuple:%x", tuple);
90 //TEMP::for debugging
91 iter=hasLockList_;
92 int cnt=0;
93 while (iter != NULL)
95 printError(ErrWarning, "Element in hasList: %d %x: %x:%d\n", cnt, iter->node_, iter->node_->ptrToTuple_ , *(int*)iter->node_->ptrToTuple_);
96 cnt++;
97 iter = iter->next_;
99 return ErrNotFound;
103 DbRetVal Transaction::releaseAllLocks(LockManager *lockManager_)
105 Database *sysdb =lockManager_->systemDatabase_;
106 Chunk *chunk = sysdb->getSystemDatabaseChunk(TransHasTableId);
107 TransHasNode *iter = hasLockList_, *prev;
108 DbRetVal rv = OK;
109 while (NULL != iter)
111 prev = iter;
112 iter = iter->next_;
113 printDebug(DM_Transaction, "Releasing lock %x",prev->node_->ptrToTuple_);
114 rv = lockManager_->releaseLock(prev->node_->ptrToTuple_);
115 chunk->free(sysdb, prev);
117 hasLockList_ = NULL;
118 return OK;
120 bool Transaction::findInHasList(Database *sysdb, LockHashNode *node)
122 TransHasNode *iter = hasLockList_;
123 while (NULL != iter)
125 if (iter->node_ == node) return true;
126 iter = iter->next_;
128 return false;
131 DbRetVal Transaction::appendUndoLog(Database *sysdb, OperationType type,
132 void *data, size_t size)
134 DbRetVal rv =OK;
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);
138 addAtBegin(logInfo);
139 printDebug(DM_Transaction, "creating undo log and append %x optype:%d",
140 logInfo, type);
141 return OK;
146 DbRetVal Transaction::appendLogicalUndoLog(Database *sysdb, OperationType type, void *data, size_t size, void* indexPtr)
148 DbRetVal rv = OK;
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;
153 addAtBegin(logInfo);
154 printDebug(DM_Transaction, "creating logical undo log and append %x optype:%d", logInfo, type);
155 return rv;
158 DbRetVal Transaction::appendLogicalHashUndoLog(Database *sysdb, OperationType type, void *data, size_t size)
160 DbRetVal rv = OK;
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));
165 addAtBegin(logInfo);
166 printDebug(DM_Transaction, "creating logical undo log and append %x optype:%d", logInfo, type);
167 return rv;
169 DbRetVal Transaction::appendLogicalTreeUndoLog(Database *sysdb, OperationType type, void *data, size_t size)
171 DbRetVal rv = OK;
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));
176 addAtBegin(logInfo);
177 printDebug(DM_Transaction, "creating logical undo log and append %x optype:%d", logInfo, type);
178 return rv;
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;
187 int tries=0;
188 int totalTries = Conf::config.getMutexRetries();
189 while (tries < totalTries)
191 *rv = OK;
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");
197 return NULL;
199 //printError (ErrWarning, Undo Log Alloc: LockTimeOut Retry:%d", tries);
200 tries++;
203 if (logInfo == NULL) {
204 printError(*rv, "Unable to allocate undo log record after %d retries", tries);
205 return NULL;
207 logInfo->opType_ = type;
208 logInfo->ptrToTuple_ = data;
209 logInfo->size_ = size;
210 logInfo->next_ = NULL;
211 return logInfo;
214 void Transaction::addAtBegin(UndoLogInfo* logInfo)
216 //add it to the begin of the log list
217 logInfo->next_ = firstUndoLog_;
218 firstUndoLog_ = logInfo;
219 return;
222 UndoLogInfo* Transaction::popUndoLog()
224 UndoLogInfo *iter = firstUndoLog_, *prev = firstUndoLog_;
225 if(NULL != iter)
227 prev = iter;
228 iter = iter->next_;
230 firstUndoLog_ = iter;
231 return prev;
235 int Transaction::noOfUndoLogs()
237 UndoLogInfo *iter = firstUndoLog_;
238 int count =0;
239 while(NULL != iter)
241 count++;
242 iter = iter->next_;
244 return count;
246 void Transaction::printDebugInfo(Database *sysdb)
248 printf("<TransactionInfo>\n");
249 if (waitLock_ != NULL)
251 printf("<WaitLock>");
252 waitLock_->print();
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_;
260 int count =0;
261 while(NULL != iter)
263 iter->print();
264 iter = iter->next_;
265 count++;
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_;
274 count =0;
275 while (NULL != hasIter)
277 hasIter->print();
278 hasIter = hasIter->next_;
279 count++;
281 printf("</TotalNodes> %d </TotalNodes>\n", count);
282 printf("</TransHasList>\n");
284 printf("</TransactionInfo>\n");
285 return ;
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);
295 return OK;
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);
310 if (*isUsed == 0) {
311 printError(ErrSysFatal, "Fatal: Row is already not in use");
313 *isUsed = 0;
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_);
318 break;
320 case DeleteOperation:
322 int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1);
323 if (*isUsed == 1) {
324 printError(ErrSysFatal, "Fatal: Row is already in use");
326 *isUsed = 1;
327 /*os::memcpy(logInfo->ptrToTuple_, (char*) logInfo +
328 sizeof(UndoLogInfo), logInfo->size_);*/
329 break;
331 case UpdateOperation:
333 int *isUsed = ((int*)(logInfo->ptrToTuple_) - 1);
334 if (*isUsed == 0) {
335 printError(ErrSysFatal, "Fatal: Row is not in use during update rollback");
337 os::memcpy(logInfo->ptrToTuple_, (char*) logInfo +
338 sizeof(UndoLogInfo), logInfo->size_);
339 break;
341 case InsertHashIndexOperation:
342 HashIndex::deleteLogicalUndoLog(sysdb, (char *)logInfo
343 + sizeof(UndoLogInfo));
344 break;
345 //case UpdateHashIndexOperation:
346 //HashIndex::updateLogicalUndoLog((char *)logInfo
347 // + sizeof(UndoLogInfo));
348 //break;
349 case DeleteHashIndexOperation:
350 HashIndex::insertLogicalUndoLog(sysdb, (char *)logInfo
351 + sizeof(UndoLogInfo));
352 break;
353 case InsertTreeIndexOperation:
354 TreeIndex::deleteLogicalUndoLog(sysdb, (char *)logInfo
355 + sizeof(UndoLogInfo));
356 break;
357 case DeleteTreeIndexOperation:
358 TreeIndex::insertLogicalUndoLog(sysdb, (char *)logInfo
359 + sizeof(UndoLogInfo));
360 break;
362 chunk->free(sysdb, logInfo);
364 return OK;