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 
59 enum LockMode {
60  MODE_NONE = 0,
61  MODE_IS = 1,
62  MODE_IX = 2,
63  MODE_S = 3,
64  MODE_X = 4,
65 
66  // Counts the lock modes. Used for array size allocations, etc. Always insert new lock
67  // modes above this entry.
69 };
70 
74 const char* modeName(LockMode mode);
75 
79 const char* legacyModeName(LockMode mode);
80 
86 bool isModeCovered(LockMode mode, LockMode coveringMode);
87 
91 inline bool isSharedLockMode(LockMode mode) {
92  return (mode == MODE_IS || mode == MODE_S);
93 }
94 
95 
99 enum LockResult {
100 
105 
113 
120 
129 
134 };
135 
136 
151  // Types used for special resources, use with a hash id from ResourceId::SingletonHashIds.
153  RESOURCE_GLOBAL, // Used for mode changes or global exclusive operations
154  RESOURCE_MMAPV1_FLUSH, // Necessary only for the MMAPv1 engine
155 
156  // Generic resources, used for multi-granularity locking, together with RESOURCE_GLOBAL
160 
161  // Resource type used for locking general resources not related to the storage hierarchy.
163 
164  // Counts the rest. Always insert new resource types above this entry.
166 };
167 
171 const char* resourceTypeName(ResourceType resourceType);
172 
176 class ResourceId {
177  // We only use 3 bits for the resource type in the ResourceId hash
178  enum { resourceTypeBits = 3 };
180 
181 public:
191  };
192 
194  ResourceId(ResourceType type, StringData ns);
195  ResourceId(ResourceType type, const std::string& ns);
196  ResourceId(ResourceType type, uint64_t hashId);
197 
198  bool isValid() const {
199  return getType() != RESOURCE_INVALID;
200  }
201 
202  operator uint64_t() const {
203  return _fullHash;
204  }
205 
206  // This defines the canonical locking order, first by type and then hash id
207  bool operator<(const ResourceId& rhs) const {
208  return _fullHash < rhs._fullHash;
209  }
210 
212  return static_cast<ResourceType>(_fullHash >> (64 - resourceTypeBits));
213  }
214 
215  uint64_t getHashId() const {
216  return _fullHash & (std::numeric_limits<uint64_t>::max() >> resourceTypeBits);
217  }
218 
219  std::string toString() const;
220 
221 private:
227  uint64_t _fullHash;
228 
229  static uint64_t fullHash(ResourceType type, uint64_t hashId);
230 
231 #ifdef MONGO_CONFIG_DEBUG_BUILD
232  // Keep the complete namespace name for debugging purposes (TODO: this will be
233  // removed once we are confident in the robustness of the lock manager).
234  std::string _nsCopy;
235 #endif
236 };
237 
238 #ifndef MONGO_CONFIG_DEBUG_BUILD
239 // Treat the resource ids as 64-bit integers in release mode in order to ensure we do
240 // not spend too much time doing comparisons for hashing.
241 MONGO_STATIC_ASSERT(sizeof(ResourceId) == sizeof(uint64_t));
242 #endif
243 
244 
245 // Type to uniquely identify a given locker object
246 typedef uint64_t LockerId;
247 
248 // Hardcoded resource id for the oplog collection, which is special-cased both for resource
249 // acquisition purposes and for statistics reporting.
250 extern const ResourceId resourceIdLocalDB;
251 extern const ResourceId resourceIdOplog;
252 
253 // Hardcoded resource id for admin db. This is to ensure direct writes to auth collections
254 // are serialized (see SERVER-16092)
255 extern const ResourceId resourceIdAdminDB;
256 
257 // Hardcoded resource id for ParallelBatchWriterMode. We use the same resource type
258 // as resourceIdGlobal. This will also ensure the waits are reported as global, which
259 // is appropriate. The lock will never be contended unless the parallel batch writers
260 // must stop all other accesses globally. This resource must be locked before all other
261 // resources (including resourceIdGlobal). Replication applier threads don't take this
262 // lock.
263 // TODO: Merge this with resourceIdGlobal
265 
277 public:
279 
295  virtual void notify(ResourceId resId, LockResult result) = 0;
296 };
297 
298 
307 struct LockRequest {
308  enum Status {
313 
314  // Counts the rest. Always insert new status types above this entry.
315  StatusCount
316  };
317 
321  void initNew(Locker* locker, LockGrantNotification* notify);
322 
323  // This is the Locker, which created this LockRequest. Pointer is not owned, just referenced.
324  // Must outlive the LockRequest.
325  //
326  // Written at construction time by Locker
327  // Read by LockManager on any thread
328  // No synchronization
330 
331  // Notification to be invoked when the lock is granted. Pointer is not owned, just referenced.
332  // If a request is in the WAITING or CONVERTING state, must live at least until
333  // LockManager::unlock is cancelled or the notification has been invoked.
334  //
335  // Written at construction time by Locker
336  // Read by LockManager
337  // No synchronization
339 
340  // If the request cannot be granted right away, whether to put it at the front or at the end of
341  // the queue. By default, requests are put at the back. If a request is requested to be put at
342  // the front, this effectively bypasses fairness. Default is FALSE.
343  //
344  // Written at construction time by Locker
345  // Read by LockManager on any thread
346  // No synchronization
348 
349  // When this request is granted and as long as it is on the granted queue, the particular
350  // resource's policy will be changed to "compatibleFirst". This means that even if there are
351  // pending requests on the conflict queue, if a compatible request comes in it will be granted
352  // immediately. This effectively turns off fairness.
353  //
354  // Written at construction time by Locker
355  // Read by LockManager on any thread
356  // No synchronization
358 
359  // When set, an attempt is made to execute this request using partitioned lockheads. This speeds
360  // up the common case where all requested locking modes are compatible with each other, at the
361  // cost of extra overhead for conflicting modes.
362  //
363  // Written at construction time by LockManager
364  // Read by LockManager on any thread
365  // No synchronization
367 
368  // How many times has LockManager::lock been called for this request. Locks are released when
369  // their recursive count drops to zero.
370  //
371  // Written by LockManager on Locker thread
372  // Read by LockManager on Locker thread
373  // Read by Locker on Locker thread
374  // No synchronization
375  unsigned recursiveCount;
376 
377  // Pointer to the lock to which this request belongs, or null if this request has not yet been
378  // assigned to a lock or if it belongs to the PartitionedLockHead for locker (in which case
379  // partitionedLock must be set). The LockHead should be alive as long as there are LockRequests
380  // on it, so it is safe to have this pointer hanging around.
381  //
382  // Written by LockManager on any thread
383  // Read by LockManager on any thread
384  // Protected by LockHead bucket's mutex
386 
387  // Pointer to the partitioned lock to which this request belongs, or null if it is not
388  // partitioned. Only one of 'lock' and 'partitionedLock' is non-NULL, and a request can only
389  // transition from 'partitionedLock' to 'lock', never the other way around.
390  //
391  // Written by LockManager on any thread
392  // Read by LockManager on any thread
393  // Protected by LockHead bucket's mutex
395 
396  // The linked list chain on which this request hangs off the owning lock head. The reason
397  // intrusive linked list is used instead of the std::list class is to allow for entries to be
398  // removed from the middle of the list in O(1) time, if they are known instead of having to
399  // search for them and we cannot persist iterators, because the list can be modified while an
400  // iterator is held.
401  //
402  // Written by LockManager on any thread
403  // Read by LockManager on any thread
404  // Protected by LockHead bucket's mutex
407 
408  // The current status of this request. Always starts at STATUS_NEW.
409  //
410  // Written by LockManager on any thread
411  // Read by LockManager on any thread
412  // Protected by LockHead bucket's mutex
414 
415  // If this request is not granted, the mode which has been requested for this lock. If granted,
416  // the mode in which it is currently granted.
417  //
418  // Written by LockManager on any thread
419  // Read by LockManager on any thread
420  // Protected by LockHead bucket's mutex
421  // Read by Locker on Locker thread
422  // It is safe for the Locker to read this without taking the bucket mutex provided that the
423  // LockRequest status is not WAITING or CONVERTING.
425 
426  // This value is different from MODE_NONE only if a conversion is requested for a lock and that
427  // conversion cannot be immediately granted.
428  //
429  // Written by LockManager on any thread
430  // Read by LockManager on any thread
431  // Protected by LockHead bucket's mutex
433 
434  // This unsigned represents the number of pending unlocks for this LockRequest. It is greater
435  // than 0 when the LockRequest is participating in two-phase lock and unlock() is called on it.
436  // It can be greater than 1 if this lock is participating in two-phase-lock and has been
437  // converted to a different mode that also participates in two-phase-lock. unlock() may be
438  // called multiple times on the same resourceId within the same WriteUnitOfWork in this case, so
439  // the number of unlocks() to execute at the end of this WUOW is tracked with this unsigned.
440  //
441  // Written by Locker on Locker thread
442  // Read by Locker on Locker thread
443  // No synchronization
444  unsigned unlockPending = 0;
445 };
446 
451 
452 } // namespace mongo
453 
454 
455 MONGO_HASH_NAMESPACE_START
456 template <>
457 struct hash<mongo::ResourceId> {
458  size_t operator()(const mongo::ResourceId& resource) const {
459  return resource;
460  }
461 };
462 MONGO_HASH_NAMESPACE_END
ResourceType
Hierarchy of resource types.
Definition: lock_manager_defs.h:150
const ResourceId resourceIdLocalDB
Definition: lock_state.cpp:1107
LockGrantNotification * notify
Definition: lock_manager_defs.h:338
SingletonHashIds
Assign hash ids for special resources to avoid accidental reuse of ids.
Definition: lock_manager_defs.h:186
Interface for acquiring locks.
Definition: locker.h:47
virtual ~LockGrantNotification()
Definition: lock_manager_defs.h:278
Definition: lock_manager_defs.h:178
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:276
LockMode mode
Definition: lock_manager_defs.h:424
Definition: lock_manager_defs.h:309
MONGO_STATIC_ASSERT(ResourceTypesCount<=(1<< resourceTypeBits))
Copyright (C) 2014 MongoDB Inc.
Definition: bson_collection_catalog_entry.cpp:38
Definition: lock_manager_defs.h:62
Definition: lock_manager_defs.h:154
const ResourceId resourceIdAdminDB
Definition: lock_state.cpp:1109
Definition: lock_manager_defs.h:61
bool operator<(const ResourceId &rhs) const
Definition: lock_manager_defs.h:207
uint64_t LockerId
Definition: lock_manager_defs.h:246
Definition: lock_manager_defs.h:158
Definition: lock_manager_defs.h:159
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:1108
ResourceType getType() const
Definition: lock_manager_defs.h:211
std::string toString() const
Definition: lock_manager.cpp:1142
This is used as an initializer value.
Definition: lock_manager_defs.h:133
bool enqueueAtFront
Definition: lock_manager_defs.h:347
Uniquely identifies a lockable resource.
Definition: lock_manager_defs.h:176
unsigned recursiveCount
Definition: lock_manager_defs.h:375
Definition: lock_manager_defs.h:187
Definition: lock_manager_defs.h:165
bool isSharedLockMode(LockMode mode)
Returns whether the passed in mode is S or IS.
Definition: lock_manager_defs.h:91
Status status
Definition: database_impl.cpp:975
const ResourceId resourceIdParallelBatchWriterMode
Definition: lock_state.cpp:1110
Definition: lock_manager_defs.h:63
Definition: lock_manager_defs.h:312
uint64_t _fullHash
The top &#39;resourceTypeBits&#39; bits of &#39;_fullHash&#39; represent the resource type, while the remaining bits ...
Definition: lock_manager_defs.h:227
Definition: lock_manager_defs.h:190
size_t operator()(const mongo::ResourceId &resource) const
Definition: lock_manager_defs.h:458
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
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:385
Locker * locker
Definition: lock_manager_defs.h:329
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:310
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
std::array< DefaultLockerImpl, kMaxPerfThreads > locker
Definition: d_concurrency_bm.cpp:66
LockRequest * prev
Definition: lock_manager_defs.h:405
Definition: lock_manager_defs.h:311
Definition: lock_manager_defs.h:157
Definition: lock_manager_defs.h:189
PartitionedLockHead * partitionedLock
Definition: lock_manager_defs.h:394
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:119
The lock request was not granted because it would result in a deadlock.
Definition: lock_manager_defs.h:128
LockRequest * next
Definition: lock_manager_defs.h:406
LockMode convertMode
Definition: lock_manager_defs.h:432
Definition: lock_manager_defs.h:60
Definition: lock_manager_defs.h:68
The lock request was granted and is now on the granted list for the specified resource.
Definition: lock_manager_defs.h:104
Status
Definition: lock_manager_defs.h:308
bool partitioned
Definition: lock_manager_defs.h:366
There is one of those entries per each request for a lock.
Definition: lock_manager_defs.h:307
The lock request was not granted because of conflict.
Definition: lock_manager_defs.h:112
Definition: lock_manager_defs.h:162
Definition: lock_manager_defs.h:152
uint64_t getHashId() const
Definition: lock_manager_defs.h:215
Definition: lock_manager_defs.h:153
const char * modeName(LockMode mode)
Returns a human-readable name for the specified lock mode.
Definition: lock_manager.cpp:1186
Definition: lock_manager_defs.h:64
bool compatibleFirst
Definition: lock_manager_defs.h:357
Status status
Definition: lock_manager_defs.h:413
ResourceId()
Definition: lock_manager_defs.h:193
bool isValid() const
Definition: lock_manager_defs.h:198