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
;
198 DbRetVal
LockManager::getExclusiveLock(void *tuple
, Transaction
**trans
)
201 printf("Transaction is NULL\n");
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);
217 if (ErrLockTimeOut
== rv
) return rv
;
218 if (ErrNotFound
== rv
)
219 rv
= lockTable
.addNewLockNode(tuple
, trans
, linfo
);
220 lockTable
.releaseBucketMutex();
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
);
232 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
233 node
->lInfo_
.noOfReaders_
= -1;
234 lockTable
.releaseBucketMutex();
235 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
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
))
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();
255 bool LockManager::takeXLockOneWriter(Transaction
**trans
, LockHashNode
*node
)
257 bool satisfy
= false;
258 if ((*trans
)->findInHasList(systemDatabase_
, node
))
261 printDebug(DM_Lock
, "You already have exclusive lock:%x", node
);
262 node
->lInfo_
.waitWriters_
--;
263 (*trans
)->removeWaitLock();
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();
275 DbRetVal
LockManager::retryExclusiveLock(Transaction
**trans
, LockHashNode
*node
)
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();
289 os::select(0,0,0,0, &timeout
);
293 if (node
->lInfo_
.noOfReaders_
== 0)
295 takeXLockNotInUse(trans
, node
);
296 lockTable
.releaseBucketMutex();
297 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
299 }else if ( node
->lInfo_
.noOfReaders_
== 1)
301 bool satisfy
= takeXLockOneReader(trans
, node
);
303 lockTable
.releaseBucketMutex();
304 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
307 }else if ( node
->lInfo_
.noOfReaders_
== -1)
309 bool satisfy
= takeXLockOneWriter(trans
, node
);
311 lockTable
.releaseBucketMutex();
312 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
316 lockTable
.releaseBucketMutex();
317 os::select(0, 0, 0, 0, &timeout
);
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");
330 LockHashNode
*node
= lockTable
.getLockNode(tuple
, rv
, true);
333 if (ErrLockTimeOut
== rv
) return rv
;
334 lockTable
.releaseBucketMutex();
335 printError(ErrSysFatal
, "Fatal:Lock Element Not found for tuple:%x %d", tuple
, *(int*)tuple
);
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_
);
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");
366 DbRetVal
LockManager::isExclusiveLocked(void *tuple
, Transaction
**trans
, bool &status
)
369 printf("Transaction is NULL\n");
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");
383 if (lockNode
->lInfo_
.noOfReaders_
== -1)
385 if((*trans
)->findInHasList(systemDatabase_
, lockNode
))
387 printDebug(DM_Lock
, "You already have exclusive Lock: %x", lockNode
);
392 lockTable
.releaseBucketMutex();
395 lockTable
.releaseBucketMutex();