Storage Engine API
lock_manager_defs.h
Go to the documentation of this file.
1 
29 #pragma once
30 
31 #include <cstdint>
32 #include <limits>
33 #include <string>
34 
35 #include "mongo/base/static_assert.h"
36 #include "mongo/base/string_data.h"
37 #include "mongo/config.h"
38 #include "mongo/platform/hash_namespace.h"
39 
40 namespace mongo {
41 
42 class Locker;
43 
44 struct LockHead;
45 struct PartitionedLockHead;
46 
61 enum LockMode {
63  MODE_NONE = 0,
65  MODE_IS = 1,
67  MODE_IX = 2,
69  MODE_S = 3,
71  MODE_X = 4,
72 
78 };
79 
83 const char* modeName(LockMode mode);
84 
88 const char* legacyModeName(LockMode mode);
89 
95 bool isModeCovered(LockMode mode, LockMode coveringMode);
96 
100 inline bool isSharedLockMode(LockMode mode) {
101  return (mode == MODE_IS || mode == MODE_S);
102 }
103 
104 
109 
114 
122 
129 
138 
143 };
144 
145 
162 
165 
168 
173 
176 
179 };
180 
184 const char* resourceTypeName(ResourceType resourceType);
185 
189 class ResourceId {
190  // We only use 3 bits for the resource type in the ResourceId hash
191  enum { resourceTypeBits = 3 };
193 
194 public:
204  };
205 
207  ResourceId(ResourceType type, StringData ns);
208  ResourceId(ResourceType type, const std::string& ns);
209  ResourceId(ResourceType type, uint64_t hashId);
210 
211  bool isValid() const {
212  return getType() != RESOURCE_INVALID;
213  }
214 
215  operator uint64_t() const {
216  return _fullHash;
217  }
218 
219  // This defines the canonical locking order, first by type and then hash id
220  bool operator<(const ResourceId& rhs) const {
221  return _fullHash < rhs._fullHash;
222  }
223 
225  return static_cast<ResourceType>(_fullHash >> (64 - resourceTypeBits));
226  }
227 
228  uint64_t getHashId() const {
229  return _fullHash & (std::numeric_limits<uint64_t>::max() >> resourceTypeBits);
230  }
231 
232  std::string toString() const;
233 
234 private:
240  uint64_t _fullHash;
241 
242  static uint64_t fullHash(ResourceType type, uint64_t hashId);
243 
244 #ifdef MONGO_CONFIG_DEBUG_BUILD
245  // Keep the complete namespace name for debugging purposes (TODO: this will be
246  // removed once we are confident in the robustness of the lock manager).
247  std::string _nsCopy;
248 #endif
249 };
250 
251 #ifndef MONGO_CONFIG_DEBUG_BUILD
252 // Treat the resource ids as 64-bit integers in release mode in order to ensure we do
253 // not spend too much time doing comparisons for hashing.
254 MONGO_STATIC_ASSERT(sizeof(ResourceId) == sizeof(uint64_t));
255 #endif
256 
257 
258 // Type to uniquely identify a given locker object
259 typedef uint64_t LockerId;
260 
261 // Hardcoded resource id for the oplog collection, which is special-cased both for resource
262 // acquisition purposes and for statistics reporting.
263 extern const ResourceId resourceIdLocalDB;
264 extern const ResourceId resourceIdOplog;
265 
266 // Hardcoded resource id for admin db. This is to ensure direct writes to auth collections
267 // are serialized (see SERVER-16092)
268 extern const ResourceId resourceIdAdminDB;
269 
270 // Hardcoded resource id for ParallelBatchWriterMode. We use the same resource type
271 // as resourceIdGlobal. This will also ensure the waits are reported as global, which
272 // is appropriate. The lock will never be contended unless the parallel batch writers
273 // must stop all other accesses globally. This resource must be locked before all other
274 // resources (including resourceIdGlobal). Replication applier threads don't take this
275 // lock.
276 // TODO: Merge this with resourceIdGlobal
278 
290 public:
292 
308  virtual void notify(ResourceId resId, LockResult result) = 0;
309 };
310 
311 
320 struct LockRequest {
321  enum Status {
326 
327  // Counts the rest. Always insert new status types above this entry.
329  };
330 
335 
336  // This is the Locker, which created this LockRequest. Pointer is not owned, just referenced.
337  // Must outlive the LockRequest.
338  //
339  // Written at construction time by Locker
340  // Read by LockManager on any thread
341  // No synchronization
343 
344  // Notification to be invoked when the lock is granted. Pointer is not owned, just referenced.
345  // If a request is in the WAITING or CONVERTING state, must live at least until
346  // LockManager::unlock is cancelled or the notification has been invoked.
347  //
348  // Written at construction time by Locker
349  // Read by LockManager
350  // No synchronization
352 
353  // If the request cannot be granted right away, whether to put it at the front or at the end of
354  // the queue. By default, requests are put at the back. If a request is requested to be put at
355  // the front, this effectively bypasses fairness. Default is FALSE.
356  //
357  // Written at construction time by Locker
358  // Read by LockManager on any thread
359  // No synchronization
361 
362  // When this request is granted and as long as it is on the granted queue, the particular
363  // resource's policy will be changed to "compatibleFirst". This means that even if there are
364  // pending requests on the conflict queue, if a compatible request comes in it will be granted
365  // immediately. This effectively turns off fairness.
366  //
367  // Written at construction time by Locker
368  // Read by LockManager on any thread
369  // No synchronization
371 
372  // When set, an attempt is made to execute this request using partitioned lockheads. This speeds
373  // up the common case where all requested locking modes are compatible with each other, at the
374  // cost of extra overhead for conflicting modes.
375  //
376  // Written at construction time by LockManager
377  // Read by LockManager on any thread
378  // No synchronization
380 
381  // How many times has LockManager::lock been called for this request. Locks are released when
382  // their recursive count drops to zero.
383  //
384  // Written by LockManager on Locker thread
385  // Read by LockManager on Locker thread
386  // Read by Locker on Locker thread
387  // No synchronization
388  unsigned recursiveCount;
389 
390  // Pointer to the lock to which this request belongs, or null if this request has not yet been
391  // assigned to a lock or if it belongs to the PartitionedLockHead for locker (in which case
392  // partitionedLock must be set). The LockHead should be alive as long as there are LockRequests
393  // on it, so it is safe to have this pointer hanging around.
394  //
395  // Written by LockManager on any thread
396  // Read by LockManager on any thread
397  // Protected by LockHead bucket's mutex
399 
400  // Pointer to the partitioned lock to which this request belongs, or null if it is not
401  // partitioned. Only one of 'lock' and 'partitionedLock' is non-NULL, and a request can only
402  // transition from 'partitionedLock' to 'lock', never the other way around.
403  //
404  // Written by LockManager on any thread
405  // Read by LockManager on any thread
406  // Protected by LockHead bucket's mutex
408 
409  // The linked list chain on which this request hangs off the owning lock head. The reason
410  // intrusive linked list is used instead of the std::list class is to allow for entries to be
411  // removed from the middle of the list in O(1) time, if they are known instead of having to
412  // search for them and we cannot persist iterators, because the list can be modified while an
413  // iterator is held.
414  //
415  // Written by LockManager on any thread
416  // Read by LockManager on any thread
417  // Protected by LockHead bucket's mutex
420 
421  // The current status of this request. Always starts at STATUS_NEW.
422  //
423  // Written by LockManager on any thread
424  // Read by LockManager on any thread
425  // Protected by LockHead bucket's mutex
427 
428  // If this request is not granted, the mode which has been requested for this lock. If granted,
429  // the mode in which it is currently granted.
430  //
431  // Written by LockManager on any thread
432  // Read by LockManager on any thread
433  // Protected by LockHead bucket's mutex
434  // Read by Locker on Locker thread
435  // It is safe for the Locker to read this without taking the bucket mutex provided that the
436  // LockRequest status is not WAITING or CONVERTING.
438 
439  // This value is different from MODE_NONE only if a conversion is requested for a lock and that
440  // conversion cannot be immediately granted.
441  //
442  // Written by LockManager on any thread
443  // Read by LockManager on any thread
444  // Protected by LockHead bucket's mutex
446 
447  // This unsigned represents the number of pending unlocks for this LockRequest. It is greater
448  // than 0 when the LockRequest is participating in two-phase lock and unlock() is called on it.
449  // It can be greater than 1 if this lock is participating in two-phase-lock and has been
450  // converted to a different mode that also participates in two-phase-lock. unlock() may be
451  // called multiple times on the same resourceId within the same WriteUnitOfWork in this case, so
452  // the number of unlocks() to execute at the end of this WUOW is tracked with this unsigned.
453  //
454  // Written by Locker on Locker thread
455  // Read by Locker on Locker thread
456  // No synchronization
457  unsigned unlockPending = 0;
458 };
459 
464 
465 } // namespace mongo
466 
467 
468 MONGO_HASH_NAMESPACE_START
469 template <>
470 struct hash<mongo::ResourceId> {
471  size_t operator()(const mongo::ResourceId& resource) const {
472  return resource;
473  }
474 };
475 MONGO_HASH_NAMESPACE_END
ResourceType
Hierarchy of resource types.
Definition: lock_manager_defs.h:159
const ResourceId resourceIdLocalDB
Definition: lock_state.cpp:1115
LockGrantNotification * notify
Definition: lock_manager_defs.h:351
SingletonHashIds
Assign hash ids for special resources to avoid accidental reuse of ids.
Definition: lock_manager_defs.h:199
Status status
Definition: database_impl.cpp:1020
Interface for acquiring locks.
Definition: locker.h:47
virtual ~LockGrantNotification()
Definition: lock_manager_defs.h:291
Definition: lock_manager_defs.h:191
Collection *const const NamespaceString & ns
Definition: collection_info_cache_impl.cpp:53
Interface on which granted lock requests will be notified.
Definition: lock_manager_defs.h:289
LockMode mode
Definition: lock_manager_defs.h:437
Definition: lock_manager_defs.h:322
MONGO_STATIC_ASSERT(ResourceTypesCount<=(1<< resourceTypeBits))
Copyright (C) 2014 MongoDB Inc.
Definition: bson_collection_catalog_entry.cpp:38
Intent exclusive.
Definition: lock_manager_defs.h:67
Necessary only for the MMAPv1 engine.
Definition: lock_manager_defs.h:167
const ResourceId resourceIdAdminDB
Definition: lock_state.cpp:1117
Intent shared.
Definition: lock_manager_defs.h:65
bool operator<(const ResourceId &rhs) const
Definition: lock_manager_defs.h:220
uint64_t LockerId
Definition: lock_manager_defs.h:259
Definition: lock_manager_defs.h:171
Definition: lock_manager_defs.h:172
static uint64_t fullHash(ResourceType type, uint64_t hashId)
Definition: lock_manager.cpp:1121
There is one of these objects for each resource that has a lock request.
Definition: lock_manager.cpp:140
const ResourceId resourceIdOplog
Definition: lock_state.cpp:1116
ResourceType getType() const
Definition: lock_manager_defs.h:224
std::string toString() const
Definition: lock_manager.cpp:1142
void initNew(Locker *locker, LockGrantNotification *notify)
Used for initialization of a LockRequest, which might have been retrieved from cache.
Definition: lock_manager.cpp:1163
MONGO_STATIC_ASSERT(sizeof(void *)==sizeof(size_t))
This is used as an initializer value.
Definition: lock_manager_defs.h:142
bool enqueueAtFront
Definition: lock_manager_defs.h:360
Uniquely identifies a lockable resource.
Definition: lock_manager_defs.h:189
unsigned recursiveCount
Definition: lock_manager_defs.h:388
Definition: lock_manager_defs.h:200
virtual void notify(ResourceId resId, LockResult result)=0
This method is invoked at most once for each lock request and indicates the outcome of the lock acqui...
Counts the rest.
Definition: lock_manager_defs.h:178
bool isSharedLockMode(LockMode mode)
Returns whether the passed in mode is S or IS.
Definition: lock_manager_defs.h:100
const ResourceId resourceIdParallelBatchWriterMode
Definition: lock_state.cpp:1118
Shared.
Definition: lock_manager_defs.h:69
Definition: lock_manager_defs.h:325
uint64_t _fullHash
The top 'resourceTypeBits' bits of '_fullHash' represent the resource type, while the remaining bits ...
Definition: lock_manager_defs.h:240
Definition: lock_manager_defs.h:203
size_t operator()(const mongo::ResourceId &resource) const
Definition: lock_manager_defs.h:471
LockResult
Return values for the locking functions of the lock manager.
Definition: lock_manager_defs.h:108
LockMode
LockMode compatibility matrix.
Definition: lock_manager_defs.h:61
const char * resourceTypeName(ResourceType resourceType)
Returns a human-readable name for the specified resource type.
Definition: lock_manager.cpp:1199
LockHead * lock
Definition: lock_manager_defs.h:398
Locker * locker
Definition: lock_manager_defs.h:342
const char * legacyModeName(LockMode mode)
Legacy lock mode names in parity for 2.6 reports.
Definition: lock_manager.cpp:1190
Definition: lock_manager_defs.h:328
Definition: lock_manager_defs.h:323
bool isModeCovered(LockMode mode, LockMode coveringMode)
Mode A is covered by mode B if the set of conflicts for mode A is a subset of the set of conflicts fo...
Definition: lock_manager.cpp:1194
LockRequest * prev
Definition: lock_manager_defs.h:418
Definition: lock_manager_defs.h:324
Generic resources, used for multi-granularity locking, together with RESOURCE_GLOBAL.
Definition: lock_manager_defs.h:170
Definition: lock_manager_defs.h:202
PartitionedLockHead * partitionedLock
Definition: lock_manager_defs.h:407
const char * lockRequestStatusName(LockRequest::Status status)
Returns a human readable status name for the specified LockRequest status.
Definition: lock_manager.cpp:1203
The PartitionedLockHead allows optimizing the case where requests overwhelmingly use the intent lock ...
Definition: lock_manager.cpp:352
The lock request waited, but timed out before it could be granted.
Definition: lock_manager_defs.h:128
The lock request was not granted because it would result in a deadlock.
Definition: lock_manager_defs.h:137
LockRequest * next
Definition: lock_manager_defs.h:419
LockMode convertMode
Definition: lock_manager_defs.h:445
None.
Definition: lock_manager_defs.h:63
Counts the lock modes.
Definition: lock_manager_defs.h:77
The lock request was granted and is now on the granted list for the specified resource.
Definition: lock_manager_defs.h:113
Status
Definition: lock_manager_defs.h:321
bool partitioned
Definition: lock_manager_defs.h:379
There is one of those entries per each request for a lock.
Definition: lock_manager_defs.h:320
unsigned unlockPending
Definition: lock_manager_defs.h:457
The lock request was not granted because of conflict.
Definition: lock_manager_defs.h:121
Resource type used for locking general resources not related to the storage hierarchy.
Definition: lock_manager_defs.h:175
Types used for special resources, use with a hash id from ResourceId::SingletonHashIds.
Definition: lock_manager_defs.h:161
uint64_t getHashId() const
Definition: lock_manager_defs.h:228
Used for mode changes or global exclusive operations.
Definition: lock_manager_defs.h:164
const char * modeName(LockMode mode)
Returns a human-readable name for the specified lock mode.
Definition: lock_manager.cpp:1186
Exclusive.
Definition: lock_manager_defs.h:71
bool compatibleFirst
Definition: lock_manager_defs.h:370
Status status
Definition: lock_manager_defs.h:426
ResourceId()
Definition: lock_manager_defs.h:206
bool isValid() const
Definition: lock_manager_defs.h:211