Feature Request ID: 1669025
[csql.git] / src / server / LockManager.c
blob4305cba9655548c03c7a6f6da3bd2cee87b41d08
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>
24 Bucket* LockManager::getLockBucket(void *tuple)
26 int noOfBuckets = LOCK_BUCKET_SIZE;
27 Bucket* buckets = systemDatabase_->getLockHashBuckets();
28 unsigned long key =(unsigned long)tuple ;
29 int bucketNo = HashIndex::computeHashBucket(typeULong, &key, noOfBuckets);
31 Bucket *bucket = &(buckets[bucketNo]);
32 printDebug(DM_Lock, "getLockBucket bucketno:%d bucket:%x",bucketNo, bucket);
33 return bucket;
38 DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans)
40 //get the bucket list
41 //take the bucket mutex for read
42 //go the the next level bucket list
43 //get the bucket iterator
44 //go the node where the lock info resides
45 //check which mode the lock is taken
46 // if shared then
47 // upgrade the bucket mutex to write
48 // take it and increment the readers count
49 // release bucket mutex and exit
50 // if exclusive then
51 // go into the loop
52 // upgrade the bucket mutex to write
53 // increment waitReaders count
54 // release the bucket mutex
55 // wait for timeout period or (takes shared lock and release it ) till it becomes free.
56 // if times out
57 // take bucket mutex for write
58 // decrement waitReaders count
59 // releaese bucket mutex
61 // return
62 // if it becomes free
63 // take bucket mutex for write
64 // increment readers
65 // releaese bucket mutex
67 // return
68 LockInfo linfo;
69 linfo.noOfReaders_ = 1;
70 //keeping it ready for the allocation, because when
71 //lock node is not present in the list, then it means we are the first
72 //to acquire lock so for sure we will get it.
73 printDebug(DM_Lock, "LockManager::getSharedLock Begin");
74 Bucket *bucket = getLockBucket(tuple);
75 int lockRet = bucket->mutex_.tryLock();
76 if (lockRet != 0)
78 printDebug(DM_Lock, "LockManager::getSharedLock:End-Unable to get mutex");
79 printError(ErrLockTimeOut,"Unable to acquire bucket mutex");
80 return ErrLockTimeOut;
82 LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_;
83 if (NULL == lockNode)
85 LockHashNode *node = allocLockNode(linfo, tuple);
86 if (NULL == node)
88 printError(ErrNoMemory, "No memory to allocate Lock node");
89 return ErrNoMemory;
91 printDebug(DM_Lock, "Bucket list is null: Allocating new LockHashNode %x", node);
92 bucket->bucketList_ = (void*)node; //make it as head
93 bucket->mutex_.releaseLock();
94 (*trans)->insertIntoHasList(systemDatabase_, node);
95 printDebug(DM_Lock, "LockManager::getSharedLock End");
96 return OK;
99 LockHashNode *cachedLockNode = NULL;
101 LockHashNode *iter = lockNode;
102 //Iterate though the list and find the element's lock info
103 while(iter != NULL)
105 if(iter->ptrToTuple_ == tuple)
107 if (iter->lInfo_.noOfReaders_ == -1)
110 iter->lInfo_.waitReaders_++;
111 cachedLockNode = iter;
112 bucket->mutex_.releaseLock();
113 (*trans)->updateWaitLock(iter);
114 printDebug(DM_Lock, "lock node:%x exclusive locked",iter);
115 break;
117 else if (iter->lInfo_.noOfReaders_ == 0)
119 if(iter->lInfo_.waitWriters_ >0)
121 iter->lInfo_.waitReaders_++;
122 cachedLockNode = iter;
123 bucket->mutex_.releaseLock();
124 (*trans)->updateWaitLock(iter);
125 printDebug(DM_Lock, "lock node:%x Writers waiting.",iter);
126 break;
128 else
130 iter->lInfo_.noOfReaders_++;
131 bucket->mutex_.releaseLock();
132 (*trans)->insertIntoHasList(systemDatabase_, iter);
133 printDebug(DM_Lock, "lock node:%x First to take shared lock",
134 iter);
135 printDebug(DM_Lock, "LockManager::getSharedLock End");
136 return OK;
138 }else
140 iter->lInfo_.noOfReaders_++;
141 bucket->mutex_.releaseLock();
142 (*trans)->insertIntoHasList(systemDatabase_, iter);
143 printDebug(DM_Lock, "lock node:%x incr readers",iter);
144 printDebug(DM_Lock, "LockManager::getSharedLock End");
145 return OK;
148 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
149 iter = iter->next_;
151 if (NULL == cachedLockNode)
153 LockHashNode *node = allocLockNode(linfo, tuple);
154 if (NULL == node)
156 bucket->mutex_.releaseLock();
157 printError(ErrNoMemory, "No memory to allocate Lock node");
158 return ErrNoMemory;
160 printDebug(DM_Lock,"Not Found.Created new lock node:%x",node);
161 LockHashNode *it = lockNode;
162 while (NULL != it->next_) it = it->next_;
163 it->next_ = node;
164 bucket->mutex_.releaseLock();
165 (*trans)->insertIntoHasList(systemDatabase_, node);
166 printDebug(DM_Lock, "LockManager::getSharedLock End");
167 return OK;
169 bucket->mutex_.releaseLock();
170 int tries = 0;
171 int ret = 0;
172 struct timeval timeout;
173 timeout.tv_sec = config.getMutexSecs();
174 timeout.tv_usec = config.getMutexUSecs();
176 //printDebug(DM_Lock, "Trying to get mutex: for bucket %x\n", bucket);
177 while (tries < 100)
179 lockRet = bucket->mutex_.tryLock();
180 if (lockRet != 0)
182 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
183 printDebug(DM_Lock, "LockManager::getSharedLock End");
184 printError(ErrLockTimeOut, "Unable to get bucket mutex");
185 return ErrLockTimeOut;
187 if (cachedLockNode->lInfo_.noOfReaders_ == 0)
189 //if there are waiters allow then to take the lock
190 if (cachedLockNode->lInfo_.waitWriters_ <0)
192 cachedLockNode->lInfo_.noOfReaders_++;
193 cachedLockNode->lInfo_.waitReaders_--;
194 bucket->mutex_.releaseLock();
195 (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode);
196 (*trans)->removeWaitLock();
197 printDebug(DM_Lock, "LockManager::getSharedLock End");
198 return OK;
200 } else if (cachedLockNode->lInfo_.noOfReaders_ == -1)
202 if ((*trans)->findInHasList(systemDatabase_, cachedLockNode))
204 bucket->mutex_.releaseLock();
205 printDebug(DM_Lock, "LockManager::getSharedLock End");
206 return OK;
208 } else
210 cachedLockNode->lInfo_.noOfReaders_++;
211 cachedLockNode->lInfo_.waitReaders_--;
212 bucket->mutex_.releaseLock();
213 (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode);
214 printDebug(DM_Lock, "LockManager::getSharedLock End");
215 return OK;
218 bucket->mutex_.releaseLock();
219 os::select(0, 0, 0, 0, &timeout);
220 tries++;
221 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",cachedLockNode, tries);
223 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
224 printDebug(DM_Lock, "LockManager::getSharedLock End");
225 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
226 return ErrLockTimeOut;
230 DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans)
232 LockInfo linfo;
233 linfo.noOfReaders_ = -1;
234 printDebug(DM_Lock, "LockManager::getExclusiveLock Begin");
235 //keeping it ready for the allocation, because when
236 //lock node is not present in the list, then it means we are the first
237 //to acquire lock so for sure we will get it.
239 Bucket *bucket = getLockBucket(tuple);
240 int lockRet = bucket->mutex_.tryLock();
241 if (lockRet != 0)
243 printDebug(DM_Lock, "Unable to acquire bucket mutex:May be deadlock");
244 printError(ErrLockTimeOut, "Unable to acquire bucket mutex");
245 return ErrLockTimeOut;
247 LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_;
248 if (NULL == lockNode)
250 LockHashNode *node = allocLockNode(linfo, tuple);
251 if (NULL == node)
253 printError(ErrNoMemory, "No memory to allocate Lock node");
254 return ErrNoMemory;
256 printDebug(DM_Lock, "No head. So new lock node allocated:%x",node);
257 bucket->bucketList_ = (void*)node; //make it as head
258 bucket->mutex_.releaseLock();
259 (*trans)->insertIntoHasList(systemDatabase_, node);
260 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
261 return OK;
264 LockHashNode *cachedLockNode = NULL;
266 LockHashNode *iter = lockNode;
267 //Iterate though the list and find the element's lock info
268 while(iter != NULL)
270 if(iter->ptrToTuple_ == tuple)
272 if (iter->lInfo_.noOfReaders_ != 0)
274 iter->lInfo_.waitWriters_++;
275 bucket->mutex_.releaseLock();
276 (*trans)->updateWaitLock(iter);
277 cachedLockNode = iter;
278 printDebug(DM_Lock, "Either some one has exclusive or shared lock:%x",iter);
279 break;
281 else
283 iter->lInfo_.noOfReaders_ = -1;
284 bucket->mutex_.releaseLock();
285 (*trans)->insertIntoHasList(systemDatabase_, iter);
286 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
287 return OK;
290 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
291 iter = iter->next_;
293 if (NULL == cachedLockNode)
295 LockHashNode *node = allocLockNode(linfo, tuple);
296 if (NULL == node)
298 bucket->mutex_.releaseLock();
299 printError(ErrNoMemory, "No memory to allocate Lock node");
300 return ErrNoMemory;
302 printDebug(DM_Lock, "Not Found:Creating new lock node:%x",node);
303 LockHashNode *it = lockNode;
304 while (NULL != it->next_) it = it->next_;
305 it->next_ = node;
306 bucket->mutex_.releaseLock();
307 (*trans)->insertIntoHasList(systemDatabase_, node);
308 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
309 return OK;
311 bucket->mutex_.releaseLock();
312 int tries = 0;
313 int ret = 0;
314 struct timeval timeout;
315 timeout.tv_sec = config.getMutexSecs();
316 timeout.tv_usec = config.getMutexUSecs();
318 while (tries < 100)
320 lockRet = bucket->mutex_.tryLock();
321 if (lockRet != 0)
323 printError(ErrLockTimeOut, "Unable to get bucket mutex");
324 return ErrLockTimeOut;
326 if (cachedLockNode->lInfo_.noOfReaders_ == 0)
328 cachedLockNode->lInfo_.noOfReaders_ = -1;
329 cachedLockNode->lInfo_.waitWriters_--;
330 bucket->mutex_.releaseLock();
331 (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode);
332 (*trans)->removeWaitLock();
333 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
334 return OK;
335 }else if ( cachedLockNode->lInfo_.noOfReaders_ == 1)
337 if ((*trans)->findInHasList(systemDatabase_, cachedLockNode))
339 printDebug(DM_Lock, "upgrading shared to exclusive lock:%x",
340 cachedLockNode);
341 //upgrade it to exclusive lock
342 cachedLockNode->lInfo_.noOfReaders_ = -1;
343 cachedLockNode->lInfo_.waitWriters_--;
344 bucket->mutex_.releaseLock();
345 (*trans)->removeWaitLock();
346 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
347 return OK;
349 }else if ( cachedLockNode->lInfo_.noOfReaders_ == -1)
351 if ((*trans)->findInHasList(systemDatabase_, cachedLockNode))
353 printDebug(DM_Lock, "You already have exclusive lock:%x",
354 cachedLockNode);
355 cachedLockNode->lInfo_.waitWriters_--;
356 bucket->mutex_.releaseLock();
357 (*trans)->removeWaitLock();
358 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
359 return OK;
362 bucket->mutex_.releaseLock();
363 os::select(0, 0, 0, 0, &timeout);
364 tries++;
365 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",cachedLockNode, tries);
367 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
368 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
369 return ErrLockTimeOut;
376 DbRetVal LockManager::releaseLock(void *tuple)
378 LockInfo linfo;
379 linfo.noOfReaders_ = 0;
380 //keeping it ready for the allocation, because when
381 //lock node is not present in the list, then it means we are the first
382 //to acquire lock so for sure we will get it.
383 printDebug(DM_Lock, "LockManager:releaseLock Start");
384 Bucket *bucket = getLockBucket(tuple);
385 printDebug(DM_Lock,"Bucket is %x", bucket);
386 int lockRet = bucket->mutex_.tryLock();
387 if (lockRet != 0)
389 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
390 printDebug(DM_Lock, "LockManager:releaseLock End");
391 printError(ErrLockTimeOut, "Unable to get bucket mutex");
392 return ErrLockTimeOut;
394 LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_;
395 if (NULL == lockNode)
397 bucket->mutex_.releaseLock();
398 printDebug(DM_Lock, "LockManager:releaseLock End");
399 printError(ErrSysFatal, "Lock Element Not found: Probable Data Corruption");
400 return ErrSysFatal;
403 LockHashNode *iter = lockNode;
404 //Iterate though the list and find the element's lock info
405 while(iter != NULL)
407 if(iter->ptrToTuple_ == tuple)
410 if (iter->lInfo_.noOfReaders_ == -1)
412 iter->lInfo_.noOfReaders_ = 0;
413 if (iter->lInfo_.waitWriters_ == 0 || iter->lInfo_.waitReaders_ ==0)
415 deallocLockNode(iter, bucket);
416 bucket->mutex_.releaseLock();
417 printDebug(DM_Lock, "Releasing exclusive lock and dealloc node:%x",
418 iter);
419 printDebug(DM_Lock, "LockManager:releaseLock End");
420 return OK;
422 else
424 bucket->mutex_.releaseLock();
425 printDebug(DM_Lock, "Releasing exclusive lock");
426 printDebug(DM_Lock, "LockManager:releaseLock End");
427 return OK;
430 else if (iter->lInfo_.noOfReaders_ == 1)
432 iter->lInfo_.noOfReaders_ = 0;
433 if (iter->lInfo_.waitWriters_ == 0 || iter->lInfo_.waitReaders_ ==0)
435 deallocLockNode(iter, bucket);
436 bucket->mutex_.releaseLock();
437 printDebug(DM_Lock, "Releasing read lock and dealloc node:%x",iter);
438 printDebug(DM_Lock, "LockManager:releaseLock End");
439 return OK;
442 else
444 iter->lInfo_.noOfReaders_--;
445 bucket->mutex_.releaseLock();
446 printDebug(DM_Lock, "Decrementing read lock:%x",iter);
447 printDebug(DM_Lock, "LockManager:releaseLock End");
448 return OK;
452 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
453 iter = iter->next_;
455 bucket->mutex_.releaseLock();
456 printError(ErrSysFatal, "Lock Element Not found: Probable Data Corruption");
457 return ErrSysFatal;
460 DbRetVal LockManager::isExclusiveLocked(void *tuple, bool &status)
462 Bucket *bucket = getLockBucket(tuple);
463 printDebug(DM_Lock,"Bucket is %x", bucket);
464 int lockRet = bucket->mutex_.tryLock();
465 if (lockRet != 0)
467 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
468 printDebug(DM_Lock, "LockManager:releaseLock End");
469 printError(ErrLockTimeOut, "Unable to get bucket mutex");
470 return ErrLockTimeOut;
472 LockHashNode *lockNode = (LockHashNode*) bucket->bucketList_;
473 if (NULL == lockNode)
475 bucket->mutex_.releaseLock();
476 printDebug(DM_Lock, "bucketList is empty. so data element not locked");
477 status = false;
478 return OK;
481 LockHashNode *iter = lockNode;
482 //Iterate though the list and find the element's lock info
483 //Only exclusive locks are checked. shared locks are not considered for this
484 while(iter != NULL)
486 if(iter->ptrToTuple_ == tuple)
488 if (iter->lInfo_.noOfReaders_ == 1) {
489 bucket->mutex_.releaseLock();
490 status = true;
491 return OK;
494 printDebug(DM_Lock, "Finding the lock node. iter:%x",iter);
495 iter = iter->next_;
497 bucket->mutex_.releaseLock();
498 status = false;
499 return OK;
502 LockHashNode* LockManager::allocLockNode(LockInfo &info, void *tuple)
504 //allocate lock node
505 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
506 LockHashNode *node = (LockHashNode*)chunk->allocate(systemDatabase_);
507 if (NULL == node)
509 printError(ErrNoMemory,
510 "No memory to allocate Lock node");
511 return NULL;
513 node->ptrToTuple_ = tuple;
514 node->lInfo_ = info;
515 node->next_ = NULL;
516 return node;
519 void LockManager::deallocLockNode(LockHashNode *node, Bucket *bucket)
521 Chunk *chunk = systemDatabase_->getSystemDatabaseChunk(LockTableId);
522 LockHashNode *nodeList = (LockHashNode*) bucket->bucketList_;
523 LockHashNode *iter = nodeList, *prev = nodeList;
524 if (nodeList == node)
526 bucket->bucketList_ = NULL;
527 return;
529 while(iter != node)
531 prev = iter;
532 iter = iter->next_;
534 prev = iter->next_;
535 chunk->free(systemDatabase_, node);
536 return ;