*** empty log message ***
[csql.git] / src / storage / LockTable.cxx
blob7bdd0ec4ebfa757be1fde92f7d872c17de371cf5
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<Lock.h>
17 #include<Allocator.h>
18 #include<Database.h>
19 #include<CatalogTables.h>
20 #include<Transaction.h>
21 #include<Debug.h>
22 #include<Config.h>
23 #include<Process.h>
24 LockTable::LockTable()
27 LockTable::~LockTable()
31 void LockTable::setDb(Database *sysDb_)
33 systemDatabase_ = sysDb_;
34 lockBuckets = systemDatabase_->getLockHashBuckets();
37 Bucket* LockTable::getLockBucket(void *tuple)
39 unsigned long key =(unsigned long)tuple ;
40 int bucketNo = key % LOCK_BUCKET_SIZE;
41 printDebug(DM_Lock, "getLockBucket bucketno:%d",bucketNo);
42 return &(lockBuckets[bucketNo]);
45 void LockTable::printUsageStatistics()
47 Bucket* buckets = systemDatabase_->getLockHashBuckets();
48 Bucket* bucket;
49 LockHashNode *lockNode;
50 int nodeCount =0, bucketCount =0;
51 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
53 bucket = &(buckets[i]);
54 lockNode = (LockHashNode*) bucket->bucketList_;
55 if (lockNode) bucketCount++; else continue;
56 while (NULL != lockNode) { nodeCount++; lockNode = lockNode->next_; }
58 printf("<LockTable>\n");
59 printf(" <TotalBuckets> %d </TotalBuckets>\n", LOCK_BUCKET_SIZE);
60 printf(" <UsedBuckets> %d </UsedBuckets>\n", bucketCount);
61 printf(" <TotalLockNodes> %d </TotalLockNodes>\n", nodeCount);
62 printf("</LockTable>\n");
65 void LockTable::printMutexInfo()
67 Bucket* buckets = systemDatabase_->getLockHashBuckets();
68 Bucket* bucket;
69 LockHashNode *lockNode;
70 int nodeCount =0, bucketCount =0;
71 printf("<LockTable>\n");
72 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
74 bucket = &(buckets[i]);
75 bucket->mutex_.print();
77 printf("</LockTable>\n");
80 void LockTable::printDebugInfo()
82 Bucket* buckets = systemDatabase_->getLockHashBuckets();
83 Bucket* bucket;
84 LockHashNode *lockNode;
85 int nodeCount =0, bucketCount =0;
86 printf("<LockTable>\n");
87 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
89 nodeCount =0;
90 bucket = &(buckets[i]);
91 //if (bucket) bucketCount++; else continue;
92 lockNode = (LockHashNode*) bucket->bucketList_;
94 while (NULL != lockNode)
96 nodeCount++;
97 lockNode->print();
98 lockNode = lockNode->next_;
100 if (nodeCount) {
101 bucketCount++;
102 printf(" <LockBucket> \n");
103 printf(" <BucketNo> %d </BucketNo> \n", i);
104 printf(" <TotalNodes> %d </TotalNodes>\n", nodeCount);
105 printf(" <LockBucket>\n");
109 printf(" <TotalUsedBuckets> %d </TotalUsedBuckets>\n", bucketCount);
110 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
111 printf(" <TotalPages> %d </TotalPages>\n", chunk->totalPages());
112 printf("</LockTable>\n");
116 LockHashNode* LockTable::getLockNode(void *tuple, DbRetVal &rv, bool takeMutex)
118 curBucket = getLockBucket(tuple);
119 if (takeMutex)
121 int lockRet = getBucketMutex();
122 if (lockRet != 0)
124 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
125 printError(ErrLockTimeOut, "Unable to get bucket mutex");
126 rv = ErrLockTimeOut;
127 return NULL;
130 LockHashNode *iter = (LockHashNode*) curBucket->bucketList_;
131 if (NULL == iter)
133 rv = ErrNotFound;
134 return iter;
136 //Iterate though the list and find the element's lock info
137 while(iter != NULL)
139 if(iter->ptrToTuple_ == tuple) break;
140 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
141 iter = iter->next_;
143 if (NULL == iter)
145 rv = ErrNotFound;
147 return iter;
150 DbRetVal LockTable::addNewLockNode(void *tuple, Transaction **trans,
151 LockInfo &linfo)
153 DbRetVal rv = OK;
154 LockHashNode *newNode = allocLockNode(linfo, tuple, &rv);
155 if (NULL == newNode) return rv;
156 rv =OK;
157 LockHashNode *it = (LockHashNode*) curBucket->bucketList_;
158 if (NULL == it)
160 curBucket->bucketList_ = (void*)newNode; //make it as head
161 (*trans)->insertIntoHasList(systemDatabase_, newNode);
162 return OK;
164 while (NULL != it->next_) it = it->next_;
165 it->next_ = newNode;
166 (*trans)->insertIntoHasList(systemDatabase_, newNode);
167 return OK;
170 DbRetVal LockTable::releaseLock(LockHashNode *node)
172 DbRetVal rv = OK;
173 node->lInfo_.noOfReaders_ = 0;
174 if (node->lInfo_.waitWriters_ == 0 || node->lInfo_.waitReaders_ ==0)
176 int tries = Conf::config.getMutexRetries();
177 do {
178 rv = deallocLockNode(node, curBucket);
179 if (tries == 0) {
180 printError(ErrWarning, "Fatal:Leak: Unable to dealloc lock node %d tries", Conf::config.getMutexRetries());
181 break;
183 tries--;
184 }while (rv == ErrLockTimeOut);
185 printDebug(DM_Lock, "Releasing exclusive lock and dealloc node:%x", node);
187 else
189 printDebug(DM_Lock, "Releasing exclusive lock");
191 return rv;
194 LockHashNode* LockTable::allocLockNode(LockInfo &info, void *tuple, DbRetVal *rv)
196 //allocate lock node
197 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
198 LockHashNode *node = NULL;
199 int tries=0;
200 int totalTries = Conf::config.getMutexRetries();
201 while (tries < totalTries)
203 *rv = OK;
204 node= (LockHashNode*)chunk->allocate(systemDatabase_, rv);
205 if (node !=NULL) break;
206 if (*rv != ErrLockTimeOut)
208 printError(*rv, "Unable to allocate hash index node");
209 return NULL;
211 tries++;
213 if (NULL == node)
215 printError(*rv, "Unable to allocate lock node after %d retry", tries);
216 return NULL;
218 node->ptrToTuple_ = tuple;
219 node->lInfo_ = info;
220 node->next_ = NULL;
221 return node;
224 void LockTable::deallocLockNode(LockHashNode *node)
226 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
227 chunk->free(systemDatabase_, node);
228 return;
231 DbRetVal LockTable::deallocLockNode(LockHashNode *node, Bucket *bucket)
233 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
234 LockHashNode *nodeList = (LockHashNode*) bucket->bucketList_;
235 LockHashNode *iter = nodeList, *prev = nodeList;
236 if (NULL == nodeList)
238 printError(ErrSysFatal, "Fatal:Lock Bucket is NULL");
239 return ErrSysFatal;
241 //If it is the first node, then make the bucket point to the next node
242 //in the list
243 if (nodeList == node)
245 bucket->bucketList_ = node->next_;
246 chunk->free(systemDatabase_, node);
247 return OK;
249 while(iter != NULL)
251 if (iter == node) {
252 prev->next_ = iter->next_;
253 chunk->free(systemDatabase_, node);
254 return OK;
256 prev = iter;
257 iter = iter->next_;
259 printError(ErrSysFatal, "Fatal: Lock node not found in bucket");
260 return ErrSysFatal;
263 DbRetVal LockTable::getBucketMutex()
265 int procSlot = systemDatabase_->procSlot;
266 struct timeval timeout, timeval;
267 timeout.tv_sec = Conf::config.getMutexSecs();
268 timeout.tv_usec = Conf::config.getMutexUSecs();
269 int tries=0;
270 int totalTries = Conf::config.getMutexRetries() *2;
271 int ret =0;
272 while (tries < totalTries)
274 ret = curBucket->mutex_.getLock(procSlot, true);
275 if (ret == 0) break;
276 timeval.tv_sec = timeout.tv_sec;
277 timeval.tv_usec = timeout.tv_usec;
278 os::select(0, 0, 0, 0, &timeval);
279 tries++;
281 if (tries >= totalTries) return ErrLockTimeOut;
282 return OK;
285 void LockTable::releaseBucketMutex()
287 curBucket->mutex_.releaseLock(systemDatabase_->procSlot);