Storage Engine API
lock_manager.h
Go to the documentation of this file.
1 
29 #pragma once
30 
31 #include <cstdint>
32 #include <deque>
33 #include <map>
34 #include <vector>
35 
36 #include "mongo/bson/bsonobj.h"
37 #include "mongo/config.h"
40 #include "mongo/platform/atomic_word.h"
41 #include "mongo/platform/compiler.h"
42 #include "mongo/stdx/condition_variable.h"
43 #include "mongo/stdx/mutex.h"
44 #include "mongo/stdx/unordered_map.h"
45 #include "mongo/util/concurrency/mutex.h"
46 
47 namespace mongo {
48 
53 class LockManager {
55 
56 public:
57  LockManager();
58  ~LockManager();
59 
87  LockResult lock(ResourceId resId, LockRequest* request, LockMode mode);
88  LockResult convert(ResourceId resId, LockRequest* request, LockMode newMode);
89 
101  bool unlock(LockRequest* request);
102 
113  void downgrade(LockRequest* request, LockMode newMode);
114 
120  void cleanupUnusedLocks();
121 
125  void dump() const;
126 
131  void getLockInfoBSON(const std::map<LockerId, BSONObj>& lockToClientMap,
132  BSONObjBuilder* result);
133 
134 private:
135  // The deadlock detector needs to access the buckets and locks directly
136  friend class DeadlockDetector;
137 
138  // The lockheads need access to the partitions
139  friend struct LockHead;
140 
141  // These types describe the locks hash table
142 
143  struct LockBucket {
144  SimpleMutex mutex;
145  typedef stdx::unordered_map<ResourceId, LockHead*> Map;
146  Map data;
148  };
149 
150  // Each locker maps to a partition that is used for resources acquired in intent modes
151  // modes and potentially other modes that don't conflict with themselves. This avoids
152  // contention on the regular LockHead in the lock manager.
153  struct Partition {
154  PartitionedLockHead* find(ResourceId resId);
156  typedef stdx::unordered_map<ResourceId, PartitionedLockHead*> Map;
157  SimpleMutex mutex;
158  Map data;
159  };
160 
165  LockBucket* _getBucket(ResourceId resId) const;
166 
167 
171  Partition* _getPartition(LockRequest* request) const;
172 
176  void _dumpBucket(const LockBucket* bucket) const;
177 
181  void _dumpBucketToBSON(const std::map<LockerId, BSONObj>& lockToClientMap,
182  const LockBucket* bucket,
183  BSONObjBuilder* result);
184 
190  void _buildBucketBSON(const LockRequest* iter,
191  const std::map<LockerId, BSONObj>& lockToClientMap,
192  const LockBucket* bucket,
193  BSONArrayBuilder* locks);
194 
206  void _onLockModeChanged(LockHead* lock, bool checkConflictQueue);
207 
213 
214  static const unsigned _numLockBuckets;
216 
217  static const unsigned _numPartitions;
219 };
220 
221 
232 public:
238  DeadlockDetector(const LockManager& lockMgr, const Locker* initialLocker);
239 
241  while (next()) {
242  }
243 
244  return *this;
245  }
246 
254  bool next();
255 
260  bool hasCycle() const;
261 
265  std::string toString() const;
266 
267 private:
268  // An entry in the owners list below means that some locker L is blocked on some resource
269  // resId, which is currently held by the given set of owners. The reason to store it in
270  // such form is in order to avoid storing pointers to the lockers or to have to look them
271  // up by id, both of which require some form of synchronization other than locking the
272  // bucket for the resource. Instead, given the resId, we can lock the bucket for the lock
273  // and find the respective LockRequests and continue our scan forward.
274  typedef std::vector<LockerId> ConflictingOwnersList;
275 
276  struct Edges {
277  explicit Edges(ResourceId resId) : resId(resId) {}
278 
279  // Resource id indicating the lock node
281 
282  // List of lock owners/pariticipants with which the initial locker conflicts for
283  // obtaining the lock
284  ConflictingOwnersList owners;
285  };
286 
287  typedef std::map<LockerId, Edges> WaitForGraph;
288  typedef WaitForGraph::value_type WaitForGraphPair;
289 
290 
291  // We don't want to hold locks between iteration cycles, so just store the resourceId and
292  // the lockerId so we can directly find them from the lock manager.
294  UnprocessedNode(LockerId lockerId, ResourceId resId) : lockerId(lockerId), resId(resId) {}
295 
298  };
299 
300  typedef std::deque<UnprocessedNode> UnprocessedNodesQueue;
301 
302 
303  void _processNextNode(const UnprocessedNode& node);
304 
305 
306  // Not owned. Lifetime must be longer than that of the graph builder.
309 
310  UnprocessedNodesQueue _queue;
311  WaitForGraph _graph;
312 
314 };
315 
316 } // namespace mongo
Definition: lock_manager.h:153
LockBucket * _lockBuckets
Definition: lock_manager.h:215
Definition: lock_manager.h:293
void downgrade(LockRequest *request, LockMode newMode)
Downgrades the mode in which an already granted request is held, without changing the reference count...
Definition: lock_manager.cpp:639
std::map< LockerId, Edges > WaitForGraph
Definition: lock_manager.h:287
Interface for acquiring locks.
Definition: locker.h:47
Entry point for the lock manager scheduling functionality.
Definition: lock_manager.h:53
void _onLockModeChanged(LockHead *lock, bool checkConflictQueue)
Should be invoked when the state of a lock changes in a way, which could potentially allow other bloc...
Definition: lock_manager.cpp:698
DeadlockDetector & check()
Definition: lock_manager.h:240
void _dumpBucket(const LockBucket *bucket) const
Prints the contents of a bucket to the log.
Definition: lock_manager.cpp:893
SimpleMutex mutex
Definition: lock_manager.h:157
Partition * _partitions
Definition: lock_manager.h:218
Copyright (C) 2014 MongoDB Inc.
Definition: bson_collection_catalog_entry.cpp:38
std::deque< UnprocessedNode > UnprocessedNodesQueue
Definition: lock_manager.h:300
Edges(ResourceId resId)
Definition: lock_manager.h:277
uint64_t LockerId
Definition: lock_manager_defs.h:246
LockResult convert(ResourceId resId, LockRequest *request, LockMode newMode)
Definition: lock_manager.cpp:485
LockResult lock(ResourceId resId, LockRequest *request, LockMode mode)
Acquires lock on the specified resource in the specified mode and returns the outcome of the operatio...
Definition: lock_manager.cpp:434
void getLockInfoBSON(const std::map< LockerId, BSONObj > &lockToClientMap, BSONObjBuilder *result)
Dumps the contents of all locks into a BSON object to be used in lockInfo command in the shell...
Definition: lock_manager.cpp:876
There is one of these objects for each resource that has a lock request.
Definition: lock_manager.cpp:140
WaitForGraph::value_type WaitForGraphPair
Definition: lock_manager.h:288
void _dumpBucketToBSON(const std::map< LockerId, BSONObj > &lockToClientMap, const LockBucket *bucket, BSONObjBuilder *result)
Dump the contents of a bucket to the BSON.
Definition: lock_manager.cpp:829
friend class DeadlockDetector
Definition: lock_manager.h:136
Definition: lock_manager.h:143
ResourceId resId
Definition: lock_manager.h:280
stdx::unordered_map< ResourceId, PartitionedLockHead * > Map
Definition: lock_manager.h:156
static const unsigned _numPartitions
Definition: lock_manager.h:217
Uniquely identifies a lockable resource.
Definition: lock_manager_defs.h:176
stdx::unordered_map< ResourceId, LockHead * > Map
Definition: lock_manager.h:145
MONGO_DISALLOW_COPYING(LockManager)
std::vector< LockerId > ConflictingOwnersList
Definition: lock_manager.h:274
UnprocessedNodesQueue _queue
Definition: lock_manager.h:310
Map data
Definition: lock_manager.h:146
UnprocessedNode(LockerId lockerId, ResourceId resId)
Definition: lock_manager.h:294
Definition: lock_manager.h:276
bool unlock(LockRequest *request)
Decrements the reference count of a previously locked request and if the reference count becomes zero...
Definition: lock_manager.cpp:559
const LockerId _initialLockerId
Definition: lock_manager.h:308
Partition * _getPartition(LockRequest *request) const
Retrieves the Partition that a particular LockRequest should use for intent locking.
Definition: lock_manager.cpp:812
LockResult
Return values for the locking functions of the lock manager.
Definition: lock_manager_defs.h:99
LockMode
Lock modes.
Definition: lock_manager_defs.h:59
void _cleanupUnusedLocksInBucket(LockBucket *bucket)
Helper function to delete all locks that have no request on them on a single bucket.
Definition: lock_manager.cpp:669
const LockManager & _lockMgr
Definition: lock_manager.h:307
DiskLoc bucket
Definition: btree_interface.cpp:336
The PartitionedLockHead allows optimizing the case where requests overwhelmingly use the intent lock ...
Definition: lock_manager.cpp:352
Iteratively builds the wait-for graph, starting from a given blocked Locker and stops either when all...
Definition: lock_manager.h:231
ConflictingOwnersList owners
Definition: lock_manager.h:284
SimpleMutex mutex
Definition: lock_manager.h:144
void dump() const
Dumps the contents of all locks to the log.
Definition: lock_manager.cpp:816
LockBucket * _getBucket(ResourceId resId) const
Retrieves the bucket in which the particular resource must reside.
Definition: lock_manager.cpp:808
void _buildBucketBSON(const LockRequest *iter, const std::map< LockerId, BSONObj > &lockToClientMap, const LockBucket *bucket, BSONArrayBuilder *locks)
Build the BSON object containing the lock info for a particular bucket.
Definition: lock_manager.cpp:858
~LockManager()
Definition: lock_manager.cpp:422
There is one of those entries per each request for a lock.
Definition: lock_manager_defs.h:307
bool _foundCycle
Definition: lock_manager.h:313
WaitForGraph _graph
Definition: lock_manager.h:311
LockManager()
Definition: lock_manager.cpp:417
static const unsigned _numLockBuckets
Definition: lock_manager.h:214
ResourceId resId
Definition: lock_manager.h:297
Map data
Definition: lock_manager.h:158
LockHead * findOrInsert(ResourceId resId)
Definition: lock_manager.cpp:958
LockerId lockerId
Definition: lock_manager.h:296
void cleanupUnusedLocks()
Iterates through all buckets and deletes all locks, which have no requests on them.
Definition: lock_manager.cpp:661