1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <deque> 34 #include <memory> 35 #include <string> 36 37 #include "mongo/base/string_data.h" 38 #include "mongo/s/catalog/dist_lock_catalog.h" 39 #include "mongo/s/catalog/dist_lock_manager.h" 40 #include "mongo/s/catalog/dist_lock_ping_info.h" 41 #include "mongo/stdx/chrono.h" 42 #include "mongo/stdx/condition_variable.h" 43 #include "mongo/stdx/mutex.h" 44 #include "mongo/stdx/thread.h" 45 #include "mongo/stdx/unordered_map.h" 46 47 namespace mongo { 48 49 class ServiceContext; 50 51 class ReplSetDistLockManager final : public DistLockManager { 52 public: 53 // How frequently should the dist lock pinger thread run and write liveness information about 54 // this instance of the dist lock manager 55 static const Seconds kDistLockPingInterval; 56 57 // How long should the lease on a distributed lock last 58 static const Minutes kDistLockExpirationTime; 59 60 ReplSetDistLockManager(ServiceContext* globalContext, 61 StringData processID, 62 std::unique_ptr<DistLockCatalog> catalog, 63 Milliseconds pingInterval, 64 Milliseconds lockExpiration); 65 66 virtual ~ReplSetDistLockManager(); 67 68 void startUp() override; 69 void shutDown(OperationContext* opCtx) override; 70 71 std::string getProcessID() override; 72 73 StatusWith<DistLockHandle> lockWithSessionID(OperationContext* opCtx, 74 StringData name, 75 StringData whyMessage, 76 const OID& lockSessionID, 77 Milliseconds waitFor) override; 78 79 StatusWith<DistLockHandle> tryLockWithLocalWriteConcern(OperationContext* opCtx, 80 StringData name, 81 StringData whyMessage, 82 const OID& lockSessionID) override; 83 84 void unlock(OperationContext* opCtx, const DistLockHandle& lockSessionID) override; 85 86 void unlock(OperationContext* opCtx, 87 const DistLockHandle& lockSessionID, 88 StringData name) override; 89 90 void unlockAll(OperationContext* opCtx, const std::string& processID) override; 91 92 protected: 93 Status checkStatus(OperationContext* opCtx, const DistLockHandle& lockSessionID) override; 94 95 private: 96 /** 97 * Queue a lock to be unlocked asynchronously with retry until it doesn't error. 98 */ 99 void queueUnlock(const DistLockHandle& lockSessionID, const boost::optional<std::string>& name); 100 101 /** 102 * Periodically pings and checks if there are locks queued that needs unlocking. 103 */ 104 void doTask(); 105 106 /** 107 * Returns true if shutDown was called. 108 */ 109 bool isShutDown(); 110 111 /** 112 * Returns true if the current process that owns the lock has no fresh pings since 113 * the lock expiration threshold. 114 */ 115 StatusWith<bool> isLockExpired(OperationContext* opCtx, 116 const LocksType lockDoc, 117 const Milliseconds& lockExpiration); 118 119 // 120 // All member variables are labeled with one of the following codes indicating the 121 // synchronization rules for accessing them. 122 // 123 // (F) Self synchronizing. 124 // (M) Must hold _mutex for access. 125 // (I) Immutable, no synchronization needed. 126 // (S) Can only be called inside startUp/shutDown. 127 // 128 129 ServiceContext* const _serviceContext; // (F) 130 131 const std::string _processID; // (I) 132 const std::unique_ptr<DistLockCatalog> _catalog; // (I) 133 const Milliseconds _pingInterval; // (I) 134 const Milliseconds _lockExpiration; // (I) 135 136 stdx::mutex _mutex; 137 std::unique_ptr<stdx::thread> _execThread; // (S) 138 139 // Contains the list of locks queued for unlocking. Cases when unlock operation can 140 // be queued include: 141 // 1. First attempt on unlocking resulted in an error. 142 // 2. Attempting to grab or overtake a lock resulted in an error where we are uncertain 143 // whether the modification was actually applied or not, and call unlock to make 144 // sure that it was cleaned up. 145 std::deque<std::pair<DistLockHandle, boost::optional<std::string>>> _unlockList; // (M) 146 147 bool _isShutDown = false; // (M) 148 stdx::condition_variable _shutDownCV; // (M) 149 150 // Map of lockName to last ping information. 151 stdx::unordered_map<std::string, DistLockPingInfo> _pingHistory; // (M) 152 }; 153 154 } // namespace mongo 155