code reorg
[csql.git] / src / storage / LockManager.cxx
blob84a8443c65e06403cd7e8555eb9d877fa021f16c
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 LockManager::LockManager(Database *sysDb_)
26 systemDatabase_ = sysDb_;
27 lockTable.setDb(sysDb_);
30 void LockManager::printUsageStatistics()
32 lockTable.printUsageStatistics();
35 void LockManager::printDebugInfo()
37 lockTable.printDebugInfo();
39 void LockManager::printMutexInfo()
41 lockTable.printMutexInfo();
44 DbRetVal LockManager::getSharedLock(void *tuple, Transaction **trans)
46 //get the bucket list
47 //take the bucket mutex for read
48 //go the the next level bucket list
49 //get the bucket iterator
50 //go the node where the lock info resides
51 //check which mode the lock is taken
52 // if shared then
53 // upgrade the bucket mutex to write
54 // take it and increment the readers count
55 // release bucket mutex and exit
56 // if exclusive then
57 // go into the loop
58 // upgrade the bucket mutex to write
59 // increment waitReaders count
60 // release the bucket mutex
61 // wait for timeout period or (takes shared lock and release it ) till it becomes free.
62 // if times out
63 // take bucket mutex for write
64 // decrement waitReaders count
65 // releaese bucket mutex
67 // return
68 // if it becomes free
69 // take bucket mutex for write
70 // increment readers
71 // releaese bucket mutex
73 // return
74 LockInfo linfo;
75 linfo.noOfReaders_ = 1;
76 //keeping it ready for the allocation, because when
77 //lock node is not present in the list, then it means we are the first
78 //to acquire lock so for sure we will get it.
79 printDebug(DM_Lock, "LockManager::getSharedLock Begin");
80 DbRetVal rv = OK;
81 if (NULL == trans) {
82 printError(ErrSysFatal, "Fatal:Trans is null");
83 printStackTrace();
84 os::sleep(1000);
86 LockHashNode *iter = lockTable.getLockNode(tuple, rv, true);
87 if (NULL == iter)
89 if (ErrLockTimeOut == rv) return rv;
90 if (ErrNotFound == rv)
91 rv = lockTable.addNewLockNode(tuple, trans, linfo);
92 lockTable.releaseBucketMutex();
93 return rv;
95 LockHashNode *node = NULL;
96 if (iter->lInfo_.noOfReaders_ == -1)
98 iter->lInfo_.waitReaders_++;
99 node = iter;
100 (*trans)->updateWaitLock(iter);
101 printDebug(DM_Lock, "lock node:%x exclusive locked",iter);
103 else if (iter->lInfo_.noOfReaders_ == 0)
105 if(iter->lInfo_.waitWriters_ >0)
107 iter->lInfo_.waitReaders_++;
108 node = iter;
109 (*trans)->updateWaitLock(iter);
110 printDebug(DM_Lock, "lock node:%x Writers waiting.",iter);
112 else
114 DbRetVal rv = OK;
115 (*trans)->insertIntoHasList(systemDatabase_, iter);
116 iter->lInfo_.noOfReaders_++;
117 lockTable.releaseBucketMutex();
118 printDebug(DM_Lock, "lock node:%x First to take shared lock", iter);
119 printDebug(DM_Lock, "LockManager::getSharedLock End");
120 return rv;
122 }else {
123 (*trans)->insertIntoHasList(systemDatabase_, iter);
124 iter->lInfo_.noOfReaders_++;
125 lockTable.releaseBucketMutex();
126 printDebug(DM_Lock, "lock node:%x incr readers",iter);
127 printDebug(DM_Lock, "LockManager::getSharedLock End");
128 return OK;
130 lockTable.releaseBucketMutex();
131 return retrySharedLock(trans, node);
134 DbRetVal LockManager::retrySharedLock(Transaction **trans, LockHashNode *node )
136 int tries = 0;
137 int ret = 0;
138 struct timeval timeout;
139 timeout.tv_sec = Conf::config.getLockSecs();
140 timeout.tv_usec = Conf::config.getLockUSecs();
142 //printDebug(DM_Lock, "Trying to get mutex: for bucket %x\n", bucket);
143 while (tries < Conf::config.getLockRetries())
145 int lockRet = lockTable.getBucketMutex();
146 if (lockRet != 0)
148 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
149 printDebug(DM_Lock, "LockManager::getSharedLock End");
150 printError(ErrLockTimeOut, "Unable to get bucket mutex");
151 (*trans)->removeWaitLock();
152 return ErrLockTimeOut;
154 if (node->lInfo_.noOfReaders_ == 0)
156 //if there are waiters allow then to take the lock
157 if (node->lInfo_.waitWriters_ <0)
159 (*trans)->insertIntoHasList(systemDatabase_, node);
160 node->lInfo_.noOfReaders_++;
161 node->lInfo_.waitReaders_--;
162 lockTable.releaseBucketMutex();
163 (*trans)->removeWaitLock();
164 printDebug(DM_Lock, "LockManager::getSharedLock End");
165 return OK;
167 } else if (node->lInfo_.noOfReaders_ == -1)
169 if ((*trans)->findInHasList(systemDatabase_, node))
171 lockTable.releaseBucketMutex();
172 (*trans)->removeWaitLock();
173 printDebug(DM_Lock, "LockManager::getSharedLock End");
174 return OK;
176 } else
178 DbRetVal rv =OK;
179 (*trans)->insertIntoHasList(systemDatabase_, node);
180 node->lInfo_.noOfReaders_++;
181 node->lInfo_.waitReaders_--;
182 lockTable.releaseBucketMutex();
183 (*trans)->removeWaitLock();
184 printDebug(DM_Lock, "LockManager::getSharedLock End");
185 return OK;
187 lockTable.releaseBucketMutex();
188 os::select(0, 0, 0, 0, &timeout);
189 tries++;
190 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",node, tries);
192 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
193 printDebug(DM_Lock, "LockManager::getSharedLock End");
194 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
195 (*trans)->removeWaitLock();
196 return ErrLockTimeOut;
199 DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans)
201 if (trans == NULL) {
202 printf("Transaction is NULL\n");
203 printStackTrace();
204 os:sleep(5000);
206 DbRetVal rv = OK;
207 LockInfo linfo;
208 linfo.noOfReaders_ = -1;
209 //printf("DEBUG:getExclusiveLock Called\n");
210 printDebug(DM_Lock, "LockManager::getExclusiveLock Begin");
211 //keeping it ready for the allocation, because when
212 //lock node is not present in the list, then it means we are the first
213 //to acquire lock so for sure we will get it.
215 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
216 if (NULL == node)
218 if (ErrLockTimeOut == rv) return rv;
219 if (ErrNotFound == rv)
220 rv = lockTable.addNewLockNode(tuple, trans, linfo);
221 lockTable.releaseBucketMutex();
222 return rv;
224 if (node->lInfo_.noOfReaders_ != 0)
226 node->lInfo_.waitWriters_++;
227 (*trans)->updateWaitLock(node);
228 printDebug(DM_Lock, "Either some one has exclusive or shared lock:%x",node);
230 else
232 DbRetVal rv =OK;
233 (*trans)->insertIntoHasList(systemDatabase_, node);
234 node->lInfo_.noOfReaders_ = -1;
235 lockTable.releaseBucketMutex();
236 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
237 return rv;
239 lockTable.releaseBucketMutex();
240 return retryExclusiveLock(trans, node);
243 bool LockManager::takeXLockOneReader(Transaction **trans, LockHashNode *node)
245 bool satisfy = false;
246 if ((*trans)->findInHasList(systemDatabase_, node))
248 satisfy = true;
249 printDebug(DM_Lock, "upgrading shared to exclusive lock:%x", node);
250 //upgrade it to exclusive lock
251 node->lInfo_.noOfReaders_ = -1;
252 node->lInfo_.waitWriters_--;
253 (*trans)->removeWaitLock();
255 return satisfy;
258 bool LockManager::takeXLockOneWriter(Transaction **trans, LockHashNode *node)
260 bool satisfy = false;
261 if ((*trans)->findInHasList(systemDatabase_, node))
263 satisfy = true;
264 printDebug(DM_Lock, "You already have exclusive lock:%x", node);
265 node->lInfo_.waitWriters_--;
266 (*trans)->removeWaitLock();
268 return satisfy;
271 DbRetVal LockManager::takeXLockNotInUse(Transaction **trans, LockHashNode *node)
273 (*trans)->insertIntoHasList(systemDatabase_, node);
274 node->lInfo_.noOfReaders_ = -1;
275 node->lInfo_.waitWriters_--;
276 (*trans)->removeWaitLock();
277 return OK;
280 DbRetVal LockManager::retryExclusiveLock(Transaction **trans, LockHashNode *node )
282 int tries = 0;
283 int ret = 0;
284 int lockRet =0;
285 struct timeval timeout;
286 timeout.tv_sec = Conf::config.getLockSecs();
287 timeout.tv_usec = Conf::config.getLockUSecs();
289 while (tries < Conf::config.getLockRetries())
291 lockRet = lockTable.getBucketMutex();
292 if (lockRet != 0)
294 os::select(0,0,0,0, &timeout);
295 tries++;
296 continue;
298 if (node->lInfo_.noOfReaders_ == 0)
300 takeXLockNotInUse(trans, node);
301 lockTable.releaseBucketMutex();
302 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
303 return OK;
304 }else if ( node->lInfo_.noOfReaders_ == 1)
306 bool satisfy = takeXLockOneReader(trans, node);
307 if (satisfy) {
308 lockTable.releaseBucketMutex();
309 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
310 return OK;
312 }else if ( node->lInfo_.noOfReaders_ == -1)
314 bool satisfy = takeXLockOneWriter(trans, node);
315 if (satisfy) {
316 lockTable.releaseBucketMutex();
317 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
318 return OK;
321 lockTable.releaseBucketMutex();
322 os::select(0, 0, 0, 0, &timeout);
323 tries++;
324 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",node, tries);
326 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
327 (*trans)->removeWaitLock();
328 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
329 return ErrLockTimeOut;
332 DbRetVal LockManager::releaseLock(void *tuple)
334 printDebug(DM_Lock, "LockManager:releaseLock Start");
335 DbRetVal rv = OK;
336 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
337 if (NULL == node)
339 if (ErrLockTimeOut == rv) return rv;
340 lockTable.releaseBucketMutex();
341 printError(ErrSysFatal, "Fatal:Lock Element Not found for tuple:%x %d", tuple, *(int*)tuple);
342 printStackTrace();
343 return ErrSysFatal;
345 if (node->lInfo_.noOfReaders_ == -1)
347 //exclusive lock release
348 lockTable.releaseLock(node);
350 else if (node->lInfo_.noOfReaders_ == 1)
352 //single shared lock release
353 lockTable.releaseLock(node);
355 else if (node->lInfo_.noOfReaders_ == 0)
357 lockTable.releaseBucketMutex();
358 printError(ErrSysFatal, "Fatal:Lock Element found for tuple:%x with noOfReaders:%d ", tuple, node->lInfo_.noOfReaders_);
359 return ErrSysFatal;
361 else
363 //+ve value means taken in shared mode
364 node->lInfo_.noOfReaders_--;
365 printDebug(DM_Lock, "Decrementing read lock:%x",node);
367 lockTable.releaseBucketMutex();
368 printDebug(DM_Lock, "LockManager:releaseLock End");
369 return OK;
372 DbRetVal LockManager::isExclusiveLocked(void *tuple, Transaction **trans, bool &status)
374 if (trans == NULL) {
375 printf("Transaction is NULL\n");
376 printStackTrace();
377 os:sleep(5000);
379 DbRetVal rv = OK;
380 LockHashNode *lockNode = lockTable.getLockNode(tuple, rv, true);
381 if (NULL == lockNode)
383 if (ErrLockTimeOut == rv) return rv;
384 lockTable.releaseBucketMutex();
385 printDebug(DM_Lock, "LockNode not found in bucket");
386 status = false;
387 return OK;
389 if (lockNode->lInfo_.noOfReaders_ == -1)
391 if((*trans)->findInHasList(systemDatabase_, lockNode))
393 printDebug(DM_Lock, "You already have exclusive Lock: %x", lockNode);
394 status = false;
396 else
397 status = true;
398 lockTable.releaseBucketMutex();
399 return OK;
401 lockTable.releaseBucketMutex();
402 status = false;
403 return OK;