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
*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
);
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();
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();
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");
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");
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");
183 lockTable
.releaseBucketMutex();
184 os::select(0, 0, 0, 0, &timeout
);
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
)
198 printf("Transaction is NULL\n");
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);
214 if (ErrLockTimeOut
== rv
) return rv
;
215 if (ErrNotFound
== rv
)
216 rv
= lockTable
.addNewLockNode(tuple
, trans
, linfo
);
217 lockTable
.releaseBucketMutex();
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
);
229 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
230 node
->lInfo_
.noOfReaders_
= -1;
231 lockTable
.releaseBucketMutex();
232 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
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
))
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();
252 bool LockManager::takeXLockOneWriter(Transaction
**trans
, LockHashNode
*node
)
254 bool satisfy
= false;
255 if ((*trans
)->findInHasList(systemDatabase_
, node
))
258 printDebug(DM_Lock
, "You already have exclusive lock:%x", node
);
259 node
->lInfo_
.waitWriters_
--;
260 (*trans
)->removeWaitLock();
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();
272 DbRetVal
LockManager::retryExclusiveLock(Transaction
**trans
, LockHashNode
*node
)
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();
286 os::select(0,0,0,0, &timeout
);
290 if (node
->lInfo_
.noOfReaders_
== 0)
292 takeXLockNotInUse(trans
, node
);
293 lockTable
.releaseBucketMutex();
294 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
296 }else if ( node
->lInfo_
.noOfReaders_
== 1)
298 bool satisfy
= takeXLockOneReader(trans
, node
);
300 lockTable
.releaseBucketMutex();
301 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
304 }else if ( node
->lInfo_
.noOfReaders_
== -1)
306 bool satisfy
= takeXLockOneWriter(trans
, node
);
308 lockTable
.releaseBucketMutex();
309 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
313 lockTable
.releaseBucketMutex();
314 os::select(0, 0, 0, 0, &timeout
);
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");
327 LockHashNode
*node
= lockTable
.getLockNode(tuple
, rv
, true);
330 if (ErrLockTimeOut
== rv
) return rv
;
331 lockTable
.releaseBucketMutex();
332 printError(ErrSysFatal
, "Fatal:Lock Element Not found for tuple:%x %d", tuple
, *(int*)tuple
);
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_
);
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");
363 DbRetVal
LockManager::isExclusiveLocked(void *tuple
, Transaction
**trans
, bool &status
)
366 printf("Transaction is NULL\n");
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");
380 if (lockNode
->lInfo_
.noOfReaders_
== -1)
382 if((*trans
)->findInHasList(systemDatabase_
, lockNode
))
384 printDebug(DM_Lock
, "You already have exclusive Lock: %x", lockNode
);
389 lockTable
.releaseBucketMutex();
392 lockTable
.releaseBucketMutex();