code reorg
[csql.git] / src / storage / LockManager.cxx
blob4ebd6e42e817e15fe570ca6cf29030d9ebd6f2bf
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;
198 DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans)
200 if (trans == NULL) {
201 printf("Transaction is NULL\n");
202 printStackTrace();
203 os:sleep(5000);
205 DbRetVal rv = OK;
206 LockInfo linfo;
207 linfo.noOfReaders_ = -1;
208 //printf("DEBUG:getExclusiveLock Called\n");
209 printDebug(DM_Lock, "LockManager::getExclusiveLock Begin");
210 //keeping it ready for the allocation, because when
211 //lock node is not present in the list, then it means we are the first
212 //to acquire lock so for sure we will get it.
214 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
215 if (NULL == node)
217 if (ErrLockTimeOut == rv) return rv;
218 if (ErrNotFound == rv)
219 rv = lockTable.addNewLockNode(tuple, trans, linfo);
220 lockTable.releaseBucketMutex();
221 return rv;
223 if (node->lInfo_.noOfReaders_ != 0)
225 node->lInfo_.waitWriters_++;
226 (*trans)->updateWaitLock(node);
227 printDebug(DM_Lock, "Either some one has exclusive or shared lock:%x",node);
229 else
231 DbRetVal rv =OK;
232 (*trans)->insertIntoHasList(systemDatabase_, node);
233 node->lInfo_.noOfReaders_ = -1;
234 lockTable.releaseBucketMutex();
235 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
236 return rv;
238 lockTable.releaseBucketMutex();
239 return retryExclusiveLock(trans, node);
241 bool LockManager::takeXLockOneReader(Transaction **trans, LockHashNode *node)
243 bool satisfy = false;
244 if ((*trans)->findInHasList(systemDatabase_, node))
246 satisfy = true;
247 printDebug(DM_Lock, "upgrading shared to exclusive lock:%x", node);
248 //upgrade it to exclusive lock
249 node->lInfo_.noOfReaders_ = -1;
250 node->lInfo_.waitWriters_--;
251 (*trans)->removeWaitLock();
253 return satisfy;
255 bool LockManager::takeXLockOneWriter(Transaction **trans, LockHashNode *node)
257 bool satisfy = false;
258 if ((*trans)->findInHasList(systemDatabase_, node))
260 satisfy = true;
261 printDebug(DM_Lock, "You already have exclusive lock:%x", node);
262 node->lInfo_.waitWriters_--;
263 (*trans)->removeWaitLock();
265 return satisfy;
267 DbRetVal LockManager::takeXLockNotInUse(Transaction **trans, LockHashNode *node)
269 (*trans)->insertIntoHasList(systemDatabase_, node);
270 node->lInfo_.noOfReaders_ = -1;
271 node->lInfo_.waitWriters_--;
272 (*trans)->removeWaitLock();
273 return OK;
275 DbRetVal LockManager::retryExclusiveLock(Transaction **trans, LockHashNode *node )
277 int tries = 0;
278 int ret = 0;
279 int lockRet =0;
280 struct timeval timeout;
281 timeout.tv_sec = Conf::config.getLockSecs();
282 timeout.tv_usec = Conf::config.getLockUSecs();
284 while (tries < Conf::config.getLockRetries())
286 lockRet = lockTable.getBucketMutex();
287 if (lockRet != 0)
289 os::select(0,0,0,0, &timeout);
290 tries++;
291 continue;
293 if (node->lInfo_.noOfReaders_ == 0)
295 takeXLockNotInUse(trans, node);
296 lockTable.releaseBucketMutex();
297 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
298 return OK;
299 }else if ( node->lInfo_.noOfReaders_ == 1)
301 bool satisfy = takeXLockOneReader(trans, node);
302 if (satisfy) {
303 lockTable.releaseBucketMutex();
304 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
305 return OK;
307 }else if ( node->lInfo_.noOfReaders_ == -1)
309 bool satisfy = takeXLockOneWriter(trans, node);
310 if (satisfy) {
311 lockTable.releaseBucketMutex();
312 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
313 return OK;
316 lockTable.releaseBucketMutex();
317 os::select(0, 0, 0, 0, &timeout);
318 tries++;
319 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",node, tries);
321 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
322 (*trans)->removeWaitLock();
323 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
324 return ErrLockTimeOut;
326 DbRetVal LockManager::releaseLock(void *tuple)
328 printDebug(DM_Lock, "LockManager:releaseLock Start");
329 DbRetVal rv = OK;
330 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
331 if (NULL == node)
333 if (ErrLockTimeOut == rv) return rv;
334 lockTable.releaseBucketMutex();
335 printError(ErrSysFatal, "Fatal:Lock Element Not found for tuple:%x %d", tuple, *(int*)tuple);
336 printStackTrace();
337 return ErrSysFatal;
339 if (node->lInfo_.noOfReaders_ == -1)
341 //exclusive lock release
342 lockTable.releaseLock(node);
344 else if (node->lInfo_.noOfReaders_ == 1)
346 //single shared lock release
347 lockTable.releaseLock(node);
349 else if (node->lInfo_.noOfReaders_ == 0)
351 lockTable.releaseBucketMutex();
352 printError(ErrSysFatal, "Fatal:Lock Element found for tuple:%x with noOfReaders:%d ", tuple, node->lInfo_.noOfReaders_);
353 return ErrSysFatal;
355 else
357 //+ve value means taken in shared mode
358 node->lInfo_.noOfReaders_--;
359 printDebug(DM_Lock, "Decrementing read lock:%x",node);
361 lockTable.releaseBucketMutex();
362 printDebug(DM_Lock, "LockManager:releaseLock End");
363 return OK;
366 DbRetVal LockManager::isExclusiveLocked(void *tuple, Transaction **trans, bool &status)
368 if (trans == NULL) {
369 printf("Transaction is NULL\n");
370 printStackTrace();
371 os:sleep(5000);
373 DbRetVal rv = OK;
374 LockHashNode *lockNode = lockTable.getLockNode(tuple, rv, true);
375 if (NULL == lockNode)
377 if (ErrLockTimeOut == rv) return rv;
378 lockTable.releaseBucketMutex();
379 printDebug(DM_Lock, "LockNode not found in bucket");
380 status = false;
381 return OK;
383 if (lockNode->lInfo_.noOfReaders_ == -1)
385 if((*trans)->findInHasList(systemDatabase_, lockNode))
387 printDebug(DM_Lock, "You already have exclusive Lock: %x", lockNode);
388 status = false;
390 else
391 status = true;
392 lockTable.releaseBucketMutex();
393 return OK;
395 lockTable.releaseBucketMutex();
396 status = false;
397 return OK;