1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
19 #include<CatalogTables.h>
20 #include<Transaction.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
)
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
53 // upgrade the bucket mutex to write
54 // take it and increment the readers count
55 // release bucket mutex and exit
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.
63 // take bucket mutex for write
64 // decrement waitReaders count
65 // releaese bucket mutex
69 // take bucket mutex for write
71 // releaese bucket mutex
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");
82 printError(ErrSysFatal
, "Fatal:Trans is null");
86 LockHashNode
*iter
= lockTable
.getLockNode(tuple
, rv
, true);
89 if (ErrLockTimeOut
== rv
) return rv
;
90 if (ErrNotFound
== rv
)
91 rv
= lockTable
.addNewLockNode(tuple
, trans
, linfo
);
92 lockTable
.releaseBucketMutex();
95 LockHashNode
*node
= NULL
;
96 if (iter
->lInfo_
.noOfReaders_
== -1)
98 iter
->lInfo_
.waitReaders_
++;
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_
++;
109 (*trans
)->updateWaitLock(iter
);
110 printDebug(DM_Lock
, "lock node:%x Writers waiting.",iter
);
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");
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");
130 lockTable
.releaseBucketMutex();
131 return retrySharedLock(trans
, node
);
134 DbRetVal
LockManager::retrySharedLock(Transaction
**trans
, LockHashNode
*node
)
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();
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");
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");
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");
187 lockTable
.releaseBucketMutex();
188 os::select(0, 0, 0, 0, &timeout
);
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
)
202 printf("Transaction is NULL\n");
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);
218 if (ErrLockTimeOut
== rv
) return rv
;
219 if (ErrNotFound
== rv
)
220 rv
= lockTable
.addNewLockNode(tuple
, trans
, linfo
);
221 lockTable
.releaseBucketMutex();
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
);
233 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
234 node
->lInfo_
.noOfReaders_
= -1;
235 lockTable
.releaseBucketMutex();
236 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
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
))
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();
258 bool LockManager::takeXLockOneWriter(Transaction
**trans
, LockHashNode
*node
)
260 bool satisfy
= false;
261 if ((*trans
)->findInHasList(systemDatabase_
, node
))
264 printDebug(DM_Lock
, "You already have exclusive lock:%x", node
);
265 node
->lInfo_
.waitWriters_
--;
266 (*trans
)->removeWaitLock();
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();
280 DbRetVal
LockManager::retryExclusiveLock(Transaction
**trans
, LockHashNode
*node
)
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();
294 os::select(0,0,0,0, &timeout
);
298 if (node
->lInfo_
.noOfReaders_
== 0)
300 takeXLockNotInUse(trans
, node
);
301 lockTable
.releaseBucketMutex();
302 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
304 }else if ( node
->lInfo_
.noOfReaders_
== 1)
306 bool satisfy
= takeXLockOneReader(trans
, node
);
308 lockTable
.releaseBucketMutex();
309 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
312 }else if ( node
->lInfo_
.noOfReaders_
== -1)
314 bool satisfy
= takeXLockOneWriter(trans
, node
);
316 lockTable
.releaseBucketMutex();
317 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
321 lockTable
.releaseBucketMutex();
322 os::select(0, 0, 0, 0, &timeout
);
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");
336 LockHashNode
*node
= lockTable
.getLockNode(tuple
, rv
, true);
339 if (ErrLockTimeOut
== rv
) return rv
;
340 lockTable
.releaseBucketMutex();
341 printError(ErrSysFatal
, "Fatal:Lock Element Not found for tuple:%x %d", tuple
, *(int*)tuple
);
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_
);
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");
372 DbRetVal
LockManager::isExclusiveLocked(void *tuple
, Transaction
**trans
, bool &status
)
375 printf("Transaction is NULL\n");
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");
389 if (lockNode
->lInfo_
.noOfReaders_
== -1)
391 if((*trans
)->findInHasList(systemDatabase_
, lockNode
))
393 printDebug(DM_Lock
, "You already have exclusive Lock: %x", lockNode
);
398 lockTable
.releaseBucketMutex();
401 lockTable
.releaseBucketMutex();