exp changes
[csql.git] / src / storage / LockManager.cxx
blob39cb072b5e3766dd7c4ff2c75d684e93cd52da96
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 *cachedLockNode = NULL;
96 if (iter->lInfo_.noOfReaders_ == -1)
98 iter->lInfo_.waitReaders_++;
99 cachedLockNode = 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 cachedLockNode = 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 int tries = 0;
132 int ret = 0;
133 struct timeval timeout;
134 timeout.tv_sec = Conf::config.getLockSecs();
135 timeout.tv_usec = Conf::config.getLockUSecs();
137 //printDebug(DM_Lock, "Trying to get mutex: for bucket %x\n", bucket);
138 while (tries < Conf::config.getLockRetries())
140 int lockRet = lockTable.getBucketMutex();
141 if (lockRet != 0)
143 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
144 printDebug(DM_Lock, "LockManager::getSharedLock End");
145 printError(ErrLockTimeOut, "Unable to get bucket mutex");
146 (*trans)->removeWaitLock();
147 return ErrLockTimeOut;
149 if (cachedLockNode->lInfo_.noOfReaders_ == 0)
151 //if there are waiters allow then to take the lock
152 if (cachedLockNode->lInfo_.waitWriters_ <0)
154 (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode);
155 cachedLockNode->lInfo_.noOfReaders_++;
156 cachedLockNode->lInfo_.waitReaders_--;
157 lockTable.releaseBucketMutex();
158 (*trans)->removeWaitLock();
159 printDebug(DM_Lock, "LockManager::getSharedLock End");
160 return OK;
162 } else if (cachedLockNode->lInfo_.noOfReaders_ == -1)
164 if ((*trans)->findInHasList(systemDatabase_, cachedLockNode))
166 lockTable.releaseBucketMutex();
167 (*trans)->removeWaitLock();
168 printDebug(DM_Lock, "LockManager::getSharedLock End");
169 return OK;
171 } else
173 DbRetVal rv =OK;
174 (*trans)->insertIntoHasList(systemDatabase_, cachedLockNode);
175 cachedLockNode->lInfo_.noOfReaders_++;
176 cachedLockNode->lInfo_.waitReaders_--;
177 lockTable.releaseBucketMutex();
178 (*trans)->removeWaitLock();
179 printDebug(DM_Lock, "LockManager::getSharedLock End");
180 return OK;
183 lockTable.releaseBucketMutex();
184 os::select(0, 0, 0, 0, &timeout);
185 tries++;
186 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",cachedLockNode, tries);
188 printDebug(DM_Lock, "Mutex is waiting for long time:May be deadlock");
189 printDebug(DM_Lock, "LockManager::getSharedLock End");
190 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
191 (*trans)->removeWaitLock();
192 return ErrLockTimeOut;
195 DbRetVal LockManager::getExclusiveLock(void *tuple, Transaction **trans)
197 if (trans == NULL) {
198 printf("Transaction is NULL\n");
199 printStackTrace();
200 os:sleep(5000);
202 DbRetVal rv = OK;
203 LockInfo linfo;
204 linfo.noOfReaders_ = -1;
205 //printf("DEBUG:getExclusiveLock Called\n");
206 printDebug(DM_Lock, "LockManager::getExclusiveLock Begin");
207 //keeping it ready for the allocation, because when
208 //lock node is not present in the list, then it means we are the first
209 //to acquire lock so for sure we will get it.
211 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
212 if (NULL == node)
214 if (ErrLockTimeOut == rv) return rv;
215 if (ErrNotFound == rv)
216 rv = lockTable.addNewLockNode(tuple, trans, linfo);
217 lockTable.releaseBucketMutex();
218 return rv;
220 if (node->lInfo_.noOfReaders_ != 0)
222 node->lInfo_.waitWriters_++;
223 (*trans)->updateWaitLock(node);
224 printDebug(DM_Lock, "Either some one has exclusive or shared lock:%x",node);
226 else
228 DbRetVal rv =OK;
229 (*trans)->insertIntoHasList(systemDatabase_, node);
230 node->lInfo_.noOfReaders_ = -1;
231 lockTable.releaseBucketMutex();
232 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
233 return rv;
235 lockTable.releaseBucketMutex();
236 return retryExclusiveLock(trans, node);
238 bool LockManager::takeXLockOneReader(Transaction **trans, LockHashNode *node)
240 bool satisfy = false;
241 if ((*trans)->findInHasList(systemDatabase_, node))
243 satisfy = true;
244 printDebug(DM_Lock, "upgrading shared to exclusive lock:%x", node);
245 //upgrade it to exclusive lock
246 node->lInfo_.noOfReaders_ = -1;
247 node->lInfo_.waitWriters_--;
248 (*trans)->removeWaitLock();
250 return satisfy;
252 bool LockManager::takeXLockOneWriter(Transaction **trans, LockHashNode *node)
254 bool satisfy = false;
255 if ((*trans)->findInHasList(systemDatabase_, node))
257 satisfy = true;
258 printDebug(DM_Lock, "You already have exclusive lock:%x", node);
259 node->lInfo_.waitWriters_--;
260 (*trans)->removeWaitLock();
262 return satisfy;
264 DbRetVal LockManager::takeXLockNotInUse(Transaction **trans, LockHashNode *node)
266 (*trans)->insertIntoHasList(systemDatabase_, node);
267 node->lInfo_.noOfReaders_ = -1;
268 node->lInfo_.waitWriters_--;
269 (*trans)->removeWaitLock();
270 return OK;
272 DbRetVal LockManager::retryExclusiveLock(Transaction **trans, LockHashNode *node )
274 int tries = 0;
275 int ret = 0;
276 int lockRet =0;
277 struct timeval timeout;
278 timeout.tv_sec = Conf::config.getLockSecs();
279 timeout.tv_usec = Conf::config.getLockUSecs();
281 while (tries < Conf::config.getLockRetries())
283 lockRet = lockTable.getBucketMutex();
284 if (lockRet != 0)
286 os::select(0,0,0,0, &timeout);
287 tries++;
288 continue;
290 if (node->lInfo_.noOfReaders_ == 0)
292 takeXLockNotInUse(trans, node);
293 lockTable.releaseBucketMutex();
294 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
295 return OK;
296 }else if ( node->lInfo_.noOfReaders_ == 1)
298 bool satisfy = takeXLockOneReader(trans, node);
299 if (satisfy) {
300 lockTable.releaseBucketMutex();
301 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
302 return OK;
304 }else if ( node->lInfo_.noOfReaders_ == -1)
306 bool satisfy = takeXLockOneWriter(trans, node);
307 if (satisfy) {
308 lockTable.releaseBucketMutex();
309 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
310 return OK;
313 lockTable.releaseBucketMutex();
314 os::select(0, 0, 0, 0, &timeout);
315 tries++;
316 printDebug(DM_Lock, "Trying to lock the lock node:%x iteration:%d",node, tries);
318 printDebug(DM_Lock, "LockManager::getExclusiveLock End");
319 (*trans)->removeWaitLock();
320 printError(ErrLockTimeOut, "Unable to acquire lock for long time.Timed out");
321 return ErrLockTimeOut;
323 DbRetVal LockManager::releaseLock(void *tuple)
325 printDebug(DM_Lock, "LockManager:releaseLock Start");
326 DbRetVal rv = OK;
327 LockHashNode *node = lockTable.getLockNode(tuple, rv, true);
328 if (NULL == node)
330 if (ErrLockTimeOut == rv) return rv;
331 lockTable.releaseBucketMutex();
332 printError(ErrSysFatal, "Fatal:Lock Element Not found for tuple:%x %d", tuple, *(int*)tuple);
333 printStackTrace();
334 return ErrSysFatal;
336 if (node->lInfo_.noOfReaders_ == -1)
338 //exclusive lock release
339 lockTable.releaseLock(node);
341 else if (node->lInfo_.noOfReaders_ == 1)
343 //single shared lock release
344 lockTable.releaseLock(node);
346 else if (node->lInfo_.noOfReaders_ == 0)
348 lockTable.releaseBucketMutex();
349 printError(ErrSysFatal, "Fatal:Lock Element found for tuple:%x with noOfReaders:%d ", tuple, node->lInfo_.noOfReaders_);
350 return ErrSysFatal;
352 else
354 //+ve value means taken in shared mode
355 node->lInfo_.noOfReaders_--;
356 printDebug(DM_Lock, "Decrementing read lock:%x",node);
358 lockTable.releaseBucketMutex();
359 printDebug(DM_Lock, "LockManager:releaseLock End");
360 return OK;
363 DbRetVal LockManager::isExclusiveLocked(void *tuple, Transaction **trans, bool &status)
365 if (trans == NULL) {
366 printf("Transaction is NULL\n");
367 printStackTrace();
368 os:sleep(5000);
370 DbRetVal rv = OK;
371 LockHashNode *lockNode = lockTable.getLockNode(tuple, rv, true);
372 if (NULL == lockNode)
374 if (ErrLockTimeOut == rv) return rv;
375 lockTable.releaseBucketMutex();
376 printDebug(DM_Lock, "LockNode not found in bucket");
377 status = false;
378 return OK;
380 if (lockNode->lInfo_.noOfReaders_ == -1)
382 if((*trans)->findInHasList(systemDatabase_, lockNode))
384 printDebug(DM_Lock, "You already have exclusive Lock: %x", lockNode);
385 status = false;
387 else
388 status = true;
389 lockTable.releaseBucketMutex();
390 return OK;
392 lockTable.releaseBucketMutex();
393 status = false;
394 return OK;