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 Bucket
* LockManager::getLockBucket(void *tuple
)
26 int noOfBuckets
= LOCK_BUCKET_SIZE
;
27 Bucket
* buckets
= systemDatabase_
->getLockHashBuckets();
28 unsigned long key
=(unsigned long)tuple
;
29 int bucketNo
= HashIndex::computeHashBucket(typeULong
, &key
, noOfBuckets
);
31 Bucket
*bucket
= &(buckets
[bucketNo
]);
32 printDebug(DM_Lock
, "getLockBucket bucketno:%d bucket:%x",bucketNo
, bucket
);
38 DbRetVal
LockManager::getSharedLock(void *tuple
, Transaction
**trans
)
41 //take the bucket mutex for read
42 //go the the next level bucket list
43 //get the bucket iterator
44 //go the node where the lock info resides
45 //check which mode the lock is taken
47 // upgrade the bucket mutex to write
48 // take it and increment the readers count
49 // release bucket mutex and exit
52 // upgrade the bucket mutex to write
53 // increment waitReaders count
54 // release the bucket mutex
55 // wait for timeout period or (takes shared lock and release it ) till it becomes free.
57 // take bucket mutex for write
58 // decrement waitReaders count
59 // releaese bucket mutex
63 // take bucket mutex for write
65 // releaese bucket mutex
69 linfo
.noOfReaders_
= 1;
70 //keeping it ready for the allocation, because when
71 //lock node is not present in the list, then it means we are the first
72 //to acquire lock so for sure we will get it.
73 printDebug(DM_Lock
, "LockManager::getSharedLock Begin");
74 Bucket
*bucket
= getLockBucket(tuple
);
75 int lockRet
= bucket
->mutex_
.tryLock();
78 printDebug(DM_Lock
, "LockManager::getSharedLock:End-Unable to get mutex");
79 printError(ErrLockTimeOut
,"Unable to acquire bucket mutex");
80 return ErrLockTimeOut
;
82 LockHashNode
*lockNode
= (LockHashNode
*) bucket
->bucketList_
;
85 LockHashNode
*node
= allocLockNode(linfo
, tuple
);
88 printError(ErrNoMemory
, "No memory to allocate Lock node");
91 printDebug(DM_Lock
, "Bucket list is null: Allocating new LockHashNode %x", node
);
92 bucket
->bucketList_
= (void*)node
; //make it as head
93 bucket
->mutex_
.releaseLock();
94 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
95 printDebug(DM_Lock
, "LockManager::getSharedLock End");
99 LockHashNode
*cachedLockNode
= NULL
;
101 LockHashNode
*iter
= lockNode
;
102 //Iterate though the list and find the element's lock info
105 if(iter
->ptrToTuple_
== tuple
)
107 if (iter
->lInfo_
.noOfReaders_
== -1)
110 iter
->lInfo_
.waitReaders_
++;
111 cachedLockNode
= iter
;
112 bucket
->mutex_
.releaseLock();
113 (*trans
)->updateWaitLock(iter
);
114 printDebug(DM_Lock
, "lock node:%x exclusive locked",iter
);
117 else if (iter
->lInfo_
.noOfReaders_
== 0)
119 if(iter
->lInfo_
.waitWriters_
>0)
121 iter
->lInfo_
.waitReaders_
++;
122 cachedLockNode
= iter
;
123 bucket
->mutex_
.releaseLock();
124 (*trans
)->updateWaitLock(iter
);
125 printDebug(DM_Lock
, "lock node:%x Writers waiting.",iter
);
130 iter
->lInfo_
.noOfReaders_
++;
131 bucket
->mutex_
.releaseLock();
132 (*trans
)->insertIntoHasList(systemDatabase_
, iter
);
133 printDebug(DM_Lock
, "lock node:%x First to take shared lock",
135 printDebug(DM_Lock
, "LockManager::getSharedLock End");
140 iter
->lInfo_
.noOfReaders_
++;
141 bucket
->mutex_
.releaseLock();
142 (*trans
)->insertIntoHasList(systemDatabase_
, iter
);
143 printDebug(DM_Lock
, "lock node:%x incr readers",iter
);
144 printDebug(DM_Lock
, "LockManager::getSharedLock End");
148 printDebug(DM_Lock
, "Finding the lock node. iter:%x",iter
);
151 if (NULL
== cachedLockNode
)
153 LockHashNode
*node
= allocLockNode(linfo
, tuple
);
156 bucket
->mutex_
.releaseLock();
157 printError(ErrNoMemory
, "No memory to allocate Lock node");
160 printDebug(DM_Lock
,"Not Found.Created new lock node:%x",node
);
161 LockHashNode
*it
= lockNode
;
162 while (NULL
!= it
->next_
) it
= it
->next_
;
164 bucket
->mutex_
.releaseLock();
165 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
166 printDebug(DM_Lock
, "LockManager::getSharedLock End");
169 bucket
->mutex_
.releaseLock();
172 struct timeval timeout
;
173 timeout
.tv_sec
= config
.getMutexSecs();
174 timeout
.tv_usec
= config
.getMutexUSecs();
176 //printDebug(DM_Lock, "Trying to get mutex: for bucket %x\n", bucket);
179 lockRet
= bucket
->mutex_
.tryLock();
182 printDebug(DM_Lock
, "Mutex is waiting for long time:May be deadlock");
183 printDebug(DM_Lock
, "LockManager::getSharedLock End");
184 printError(ErrLockTimeOut
, "Unable to get bucket mutex");
185 return ErrLockTimeOut
;
187 if (cachedLockNode
->lInfo_
.noOfReaders_
== 0)
189 //if there are waiters allow then to take the lock
190 if (cachedLockNode
->lInfo_
.waitWriters_
<0)
192 cachedLockNode
->lInfo_
.noOfReaders_
++;
193 cachedLockNode
->lInfo_
.waitReaders_
--;
194 bucket
->mutex_
.releaseLock();
195 (*trans
)->insertIntoHasList(systemDatabase_
, cachedLockNode
);
196 (*trans
)->removeWaitLock();
197 printDebug(DM_Lock
, "LockManager::getSharedLock End");
200 } else if (cachedLockNode
->lInfo_
.noOfReaders_
== -1)
202 if ((*trans
)->findInHasList(systemDatabase_
, cachedLockNode
))
204 bucket
->mutex_
.releaseLock();
205 printDebug(DM_Lock
, "LockManager::getSharedLock End");
210 cachedLockNode
->lInfo_
.noOfReaders_
++;
211 cachedLockNode
->lInfo_
.waitReaders_
--;
212 bucket
->mutex_
.releaseLock();
213 (*trans
)->insertIntoHasList(systemDatabase_
, cachedLockNode
);
214 printDebug(DM_Lock
, "LockManager::getSharedLock End");
218 bucket
->mutex_
.releaseLock();
219 os::select(0, 0, 0, 0, &timeout
);
221 printDebug(DM_Lock
, "Trying to lock the lock node:%x iteration:%d",cachedLockNode
, tries
);
223 printDebug(DM_Lock
, "Mutex is waiting for long time:May be deadlock");
224 printDebug(DM_Lock
, "LockManager::getSharedLock End");
225 printError(ErrLockTimeOut
, "Unable to acquire lock for long time.Timed out");
226 return ErrLockTimeOut
;
230 DbRetVal
LockManager::getExclusiveLock(void *tuple
, Transaction
**trans
)
233 linfo
.noOfReaders_
= -1;
234 printDebug(DM_Lock
, "LockManager::getExclusiveLock Begin");
235 //keeping it ready for the allocation, because when
236 //lock node is not present in the list, then it means we are the first
237 //to acquire lock so for sure we will get it.
239 Bucket
*bucket
= getLockBucket(tuple
);
240 int lockRet
= bucket
->mutex_
.tryLock();
243 printDebug(DM_Lock
, "Unable to acquire bucket mutex:May be deadlock");
244 printError(ErrLockTimeOut
, "Unable to acquire bucket mutex");
245 return ErrLockTimeOut
;
247 LockHashNode
*lockNode
= (LockHashNode
*) bucket
->bucketList_
;
248 if (NULL
== lockNode
)
250 LockHashNode
*node
= allocLockNode(linfo
, tuple
);
253 printError(ErrNoMemory
, "No memory to allocate Lock node");
256 printDebug(DM_Lock
, "No head. So new lock node allocated:%x",node
);
257 bucket
->bucketList_
= (void*)node
; //make it as head
258 bucket
->mutex_
.releaseLock();
259 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
260 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
264 LockHashNode
*cachedLockNode
= NULL
;
266 LockHashNode
*iter
= lockNode
;
267 //Iterate though the list and find the element's lock info
270 if(iter
->ptrToTuple_
== tuple
)
272 if (iter
->lInfo_
.noOfReaders_
!= 0)
274 iter
->lInfo_
.waitWriters_
++;
275 bucket
->mutex_
.releaseLock();
276 (*trans
)->updateWaitLock(iter
);
277 cachedLockNode
= iter
;
278 printDebug(DM_Lock
, "Either some one has exclusive or shared lock:%x",iter
);
283 iter
->lInfo_
.noOfReaders_
= -1;
284 bucket
->mutex_
.releaseLock();
285 (*trans
)->insertIntoHasList(systemDatabase_
, iter
);
286 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
290 printDebug(DM_Lock
, "Finding the lock node. iter:%x",iter
);
293 if (NULL
== cachedLockNode
)
295 LockHashNode
*node
= allocLockNode(linfo
, tuple
);
298 bucket
->mutex_
.releaseLock();
299 printError(ErrNoMemory
, "No memory to allocate Lock node");
302 printDebug(DM_Lock
, "Not Found:Creating new lock node:%x",node
);
303 LockHashNode
*it
= lockNode
;
304 while (NULL
!= it
->next_
) it
= it
->next_
;
306 bucket
->mutex_
.releaseLock();
307 (*trans
)->insertIntoHasList(systemDatabase_
, node
);
308 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
311 bucket
->mutex_
.releaseLock();
314 struct timeval timeout
;
315 timeout
.tv_sec
= config
.getMutexSecs();
316 timeout
.tv_usec
= config
.getMutexUSecs();
320 lockRet
= bucket
->mutex_
.tryLock();
323 printError(ErrLockTimeOut
, "Unable to get bucket mutex");
324 return ErrLockTimeOut
;
326 if (cachedLockNode
->lInfo_
.noOfReaders_
== 0)
328 cachedLockNode
->lInfo_
.noOfReaders_
= -1;
329 cachedLockNode
->lInfo_
.waitWriters_
--;
330 bucket
->mutex_
.releaseLock();
331 (*trans
)->insertIntoHasList(systemDatabase_
, cachedLockNode
);
332 (*trans
)->removeWaitLock();
333 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
335 }else if ( cachedLockNode
->lInfo_
.noOfReaders_
== 1)
337 if ((*trans
)->findInHasList(systemDatabase_
, cachedLockNode
))
339 printDebug(DM_Lock
, "upgrading shared to exclusive lock:%x",
341 //upgrade it to exclusive lock
342 cachedLockNode
->lInfo_
.noOfReaders_
= -1;
343 cachedLockNode
->lInfo_
.waitWriters_
--;
344 bucket
->mutex_
.releaseLock();
345 (*trans
)->removeWaitLock();
346 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
349 }else if ( cachedLockNode
->lInfo_
.noOfReaders_
== -1)
351 if ((*trans
)->findInHasList(systemDatabase_
, cachedLockNode
))
353 printDebug(DM_Lock
, "You already have exclusive lock:%x",
355 cachedLockNode
->lInfo_
.waitWriters_
--;
356 bucket
->mutex_
.releaseLock();
357 (*trans
)->removeWaitLock();
358 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
362 bucket
->mutex_
.releaseLock();
363 os::select(0, 0, 0, 0, &timeout
);
365 printDebug(DM_Lock
, "Trying to lock the lock node:%x iteration:%d",cachedLockNode
, tries
);
367 printDebug(DM_Lock
, "LockManager::getExclusiveLock End");
368 printError(ErrLockTimeOut
, "Unable to acquire lock for long time.Timed out");
369 return ErrLockTimeOut
;
376 DbRetVal
LockManager::releaseLock(void *tuple
)
379 linfo
.noOfReaders_
= 0;
380 //keeping it ready for the allocation, because when
381 //lock node is not present in the list, then it means we are the first
382 //to acquire lock so for sure we will get it.
383 printDebug(DM_Lock
, "LockManager:releaseLock Start");
384 Bucket
*bucket
= getLockBucket(tuple
);
385 printDebug(DM_Lock
,"Bucket is %x", bucket
);
386 int lockRet
= bucket
->mutex_
.tryLock();
389 printDebug(DM_Lock
, "Mutex is waiting for long time:May be deadlock");
390 printDebug(DM_Lock
, "LockManager:releaseLock End");
391 printError(ErrLockTimeOut
, "Unable to get bucket mutex");
392 return ErrLockTimeOut
;
394 LockHashNode
*lockNode
= (LockHashNode
*) bucket
->bucketList_
;
395 if (NULL
== lockNode
)
397 bucket
->mutex_
.releaseLock();
398 printDebug(DM_Lock
, "LockManager:releaseLock End");
399 printError(ErrSysFatal
, "Lock Element Not found: Probable Data Corruption");
403 LockHashNode
*iter
= lockNode
;
404 //Iterate though the list and find the element's lock info
407 if(iter
->ptrToTuple_
== tuple
)
410 if (iter
->lInfo_
.noOfReaders_
== -1)
412 iter
->lInfo_
.noOfReaders_
= 0;
413 if (iter
->lInfo_
.waitWriters_
== 0 || iter
->lInfo_
.waitReaders_
==0)
415 deallocLockNode(iter
, bucket
);
416 bucket
->mutex_
.releaseLock();
417 printDebug(DM_Lock
, "Releasing exclusive lock and dealloc node:%x",
419 printDebug(DM_Lock
, "LockManager:releaseLock End");
424 bucket
->mutex_
.releaseLock();
425 printDebug(DM_Lock
, "Releasing exclusive lock");
426 printDebug(DM_Lock
, "LockManager:releaseLock End");
430 else if (iter
->lInfo_
.noOfReaders_
== 1)
432 iter
->lInfo_
.noOfReaders_
= 0;
433 if (iter
->lInfo_
.waitWriters_
== 0 || iter
->lInfo_
.waitReaders_
==0)
435 deallocLockNode(iter
, bucket
);
436 bucket
->mutex_
.releaseLock();
437 printDebug(DM_Lock
, "Releasing read lock and dealloc node:%x",iter
);
438 printDebug(DM_Lock
, "LockManager:releaseLock End");
444 iter
->lInfo_
.noOfReaders_
--;
445 bucket
->mutex_
.releaseLock();
446 printDebug(DM_Lock
, "Decrementing read lock:%x",iter
);
447 printDebug(DM_Lock
, "LockManager:releaseLock End");
452 printDebug(DM_Lock
, "Finding the lock node. iter:%x",iter
);
455 bucket
->mutex_
.releaseLock();
456 printError(ErrSysFatal
, "Lock Element Not found: Probable Data Corruption");
460 DbRetVal
LockManager::isExclusiveLocked(void *tuple
, bool &status
)
462 Bucket
*bucket
= getLockBucket(tuple
);
463 printDebug(DM_Lock
,"Bucket is %x", bucket
);
464 int lockRet
= bucket
->mutex_
.tryLock();
467 printDebug(DM_Lock
, "Mutex is waiting for long time:May be deadlock");
468 printDebug(DM_Lock
, "LockManager:releaseLock End");
469 printError(ErrLockTimeOut
, "Unable to get bucket mutex");
470 return ErrLockTimeOut
;
472 LockHashNode
*lockNode
= (LockHashNode
*) bucket
->bucketList_
;
473 if (NULL
== lockNode
)
475 bucket
->mutex_
.releaseLock();
476 printDebug(DM_Lock
, "bucketList is empty. so data element not locked");
481 LockHashNode
*iter
= lockNode
;
482 //Iterate though the list and find the element's lock info
483 //Only exclusive locks are checked. shared locks are not considered for this
486 if(iter
->ptrToTuple_
== tuple
)
488 if (iter
->lInfo_
.noOfReaders_
== 1) {
489 bucket
->mutex_
.releaseLock();
494 printDebug(DM_Lock
, "Finding the lock node. iter:%x",iter
);
497 bucket
->mutex_
.releaseLock();
502 LockHashNode
* LockManager::allocLockNode(LockInfo
&info
, void *tuple
)
505 Chunk
*chunk
= systemDatabase_
->getSystemDatabaseChunk(LockTableId
);
506 LockHashNode
*node
= (LockHashNode
*)chunk
->allocate(systemDatabase_
);
509 printError(ErrNoMemory
,
510 "No memory to allocate Lock node");
513 node
->ptrToTuple_
= tuple
;
519 void LockManager::deallocLockNode(LockHashNode
*node
, Bucket
*bucket
)
521 Chunk
*chunk
= systemDatabase_
->getSystemDatabaseChunk(LockTableId
);
522 LockHashNode
*nodeList
= (LockHashNode
*) bucket
->bucketList_
;
523 LockHashNode
*iter
= nodeList
, *prev
= nodeList
;
524 if (nodeList
== node
)
526 bucket
->bucketList_
= NULL
;
535 chunk
->free(systemDatabase_
, node
);