*** empty log message ***
[csql.git] / src / storage / LockTable.cxx
blob9b12e175f4fd3a273bfc6570c83e018051caecd5
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()
30 void LockTable::setDb(Database *sysDb_)
32 systemDatabase_ = sysDb_;
33 lockBuckets = systemDatabase_->getLockHashBuckets();
35 Bucket* LockTable::getLockBucket(void *tuple)
37 unsigned long key =(unsigned long)tuple ;
38 int bucketNo = key % LOCK_BUCKET_SIZE;
39 printDebug(DM_Lock, "getLockBucket bucketno:%d",bucketNo);
40 return &(lockBuckets[bucketNo]);
43 void LockTable::printUsageStatistics()
45 Bucket* buckets = systemDatabase_->getLockHashBuckets();
46 Bucket* bucket;
47 LockHashNode *lockNode;
48 int nodeCount =0, bucketCount =0;
49 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
51 bucket = &(buckets[i]);
52 lockNode = (LockHashNode*) bucket->bucketList_;
53 if (lockNode) bucketCount++; else continue;
54 while (NULL != lockNode) { nodeCount++; lockNode = lockNode->next_; }
56 printf("<LockTable>\n");
57 printf(" <TotalBuckets> %d </TotalBuckets>\n", LOCK_BUCKET_SIZE);
58 printf(" <UsedBuckets> %d </UsedBuckets>\n", bucketCount);
59 printf(" <TotalLockNodes> %d </TotalLockNodes>\n", nodeCount);
60 printf("</LockTable>\n");
63 void LockTable::printMutexInfo()
65 Bucket* buckets = systemDatabase_->getLockHashBuckets();
66 Bucket* bucket;
67 LockHashNode *lockNode;
68 int nodeCount =0, bucketCount =0;
69 printf("<LockTable>\n");
70 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
72 bucket = &(buckets[i]);
73 bucket->mutex_.print();
75 printf("</LockTable>\n");
78 void LockTable::printDebugInfo()
80 Bucket* buckets = systemDatabase_->getLockHashBuckets();
81 Bucket* bucket;
82 LockHashNode *lockNode;
83 int nodeCount =0, bucketCount =0;
84 printf("<LockTable>\n");
85 for (int i =0; i< LOCK_BUCKET_SIZE; i++)
87 nodeCount =0;
88 bucket = &(buckets[i]);
89 //if (bucket) bucketCount++; else continue;
90 lockNode = (LockHashNode*) bucket->bucketList_;
92 while (NULL != lockNode)
94 nodeCount++;
95 lockNode->print();
96 lockNode = lockNode->next_;
98 if (nodeCount) {
99 bucketCount++;
100 printf(" <LockBucket> \n");
101 printf(" <BucketNo> %d </BucketNo> \n", i);
102 printf(" <TotalNodes> %d </TotalNodes>\n", nodeCount);
103 printf(" <LockBucket>\n");
107 printf(" <TotalUsedBuckets> %d </TotalUsedBuckets>\n", bucketCount);
108 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
109 printf(" <TotalPages> %d </TotalPages>\n", chunk->totalPages());
110 printf("</LockTable>\n");
113 LockHashNode* LockTable::getLockNode(void *tuple, DbRetVal &rv, bool takeMutex)
115 curBucket = getLockBucket(tuple);
116 if (takeMutex)
118 int lockRet = getBucketMutex();
119 if (lockRet != 0)
121 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
122 printError(ErrLockTimeOut, "Unable to get bucket mutex");
123 rv = ErrLockTimeOut;
124 return NULL;
127 LockHashNode *iter = (LockHashNode*) curBucket->bucketList_;
128 if (NULL == iter)
130 rv = ErrNotFound;
131 return iter;
133 //Iterate though the list and find the element's lock info
134 while(iter != NULL)
136 if(iter->ptrToTuple_ == tuple) break;
137 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
138 iter = iter->next_;
140 if (NULL == iter)
142 rv = ErrNotFound;
144 return iter;
147 DbRetVal LockTable::addNewLockNode(void *tuple, Transaction **trans,
148 LockInfo &linfo)
150 DbRetVal rv = OK;
151 LockHashNode *newNode = allocLockNode(linfo, tuple, &rv);
152 if (NULL == newNode) return rv;
153 rv =OK;
154 LockHashNode *it = (LockHashNode*) curBucket->bucketList_;
155 if (NULL == it)
157 curBucket->bucketList_ = (void*)newNode; //make it as head
158 (*trans)->insertIntoHasList(systemDatabase_, newNode);
159 return OK;
161 while (NULL != it->next_) it = it->next_;
162 it->next_ = newNode;
163 (*trans)->insertIntoHasList(systemDatabase_, newNode);
164 return OK;
166 DbRetVal LockTable::releaseLock(LockHashNode *node)
168 DbRetVal rv = OK;
169 node->lInfo_.noOfReaders_ = 0;
170 if (node->lInfo_.waitWriters_ == 0 || node->lInfo_.waitReaders_ ==0)
172 int tries = Conf::config.getMutexRetries();
173 do {
174 rv = deallocLockNode(node, curBucket);
175 if (tries == 0) {
176 printError(ErrWarning, "Fatal:Leak: Unable to dealloc lock node %d tries", Conf::config.getMutexRetries());
177 break;
179 tries--;
180 }while (rv == ErrLockTimeOut);
181 printDebug(DM_Lock, "Releasing exclusive lock and dealloc node:%x", node);
183 else
185 printDebug(DM_Lock, "Releasing exclusive lock");
187 return rv;
190 LockHashNode* LockTable::allocLockNode(LockInfo &info, void *tuple, DbRetVal *rv)
192 //allocate lock node
193 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
194 LockHashNode *node = NULL; //(LockHashNode*)chunk->allocate(systemDatabase_, rv);
195 int tries=0;
196 int totalTries = Conf::config.getMutexRetries();
197 while (tries < totalTries)
199 *rv = OK;
200 node= (LockHashNode*)chunk->allocate(systemDatabase_, rv);
201 if (node !=NULL) break;
202 if (*rv != ErrLockTimeOut)
204 printError(*rv, "Unable to allocate hash index node");
205 return NULL;
207 tries++;
209 if (NULL == node)
211 printError(*rv, "Unable to allocate lock node after %d retry", tries);
212 return NULL;
214 node->ptrToTuple_ = tuple;
215 node->lInfo_ = info;
216 node->next_ = NULL;
217 return node;
219 void LockTable::deallocLockNode(LockHashNode *node)
221 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
222 chunk->free(systemDatabase_, node);
223 return;
225 DbRetVal LockTable::deallocLockNode(LockHashNode *node, Bucket *bucket)
227 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
228 LockHashNode *nodeList = (LockHashNode*) bucket->bucketList_;
229 LockHashNode *iter = nodeList, *prev = nodeList;
230 if (NULL == nodeList)
232 printError(ErrSysFatal, "Fatal:Lock Bucket is NULL");
233 return ErrSysFatal;
235 //If it is the first node, then make the bucket point to the next node
236 //in the list
237 if (nodeList == node)
239 bucket->bucketList_ = node->next_;
240 chunk->free(systemDatabase_, node);
241 return OK;
243 while(iter != NULL)
245 if (iter == node) {
246 prev->next_ = iter->next_;
247 chunk->free(systemDatabase_, node);
248 return OK;
250 prev = iter;
251 iter = iter->next_;
253 printError(ErrSysFatal, "Fatal: Lock node not found in bucket");
254 return ErrSysFatal;
256 DbRetVal LockTable::getBucketMutex()
258 int procSlot = systemDatabase_->procSlot;
259 struct timeval timeout, timeval;
260 timeout.tv_sec = Conf::config.getMutexSecs();
261 timeout.tv_usec = Conf::config.getMutexUSecs();
262 int tries=0;
263 int totalTries = Conf::config.getMutexRetries() *2;
264 int ret =0;
265 while (tries < totalTries)
267 ret = curBucket->mutex_.getLock(procSlot, true);
268 if (ret == 0) break;
269 timeval.tv_sec = timeout.tv_sec;
270 timeval.tv_usec = timeout.tv_usec;
271 os::select(0, 0, 0, 0, &timeval);
272 tries++;
274 if (tries >= totalTries) return ErrLockTimeOut;
275 return OK;
277 void LockTable::releaseBucketMutex()
279 curBucket->mutex_.releaseLock(systemDatabase_->procSlot);