LogCabin
|
00001 /* Copyright (c) 2015 Diego Ongaro 00002 * 00003 * Permission to use, copy, modify, and distribute this software for any 00004 * purpose with or without fee is hereby granted, provided that the above 00005 * copyright notice and this permission notice appear in all copies. 00006 * 00007 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00008 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00009 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00010 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00011 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00012 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00013 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00014 */ 00015 00016 #ifndef LOGCABIN_CLIENT_SESSIONMANAGER_H 00017 #define LOGCABIN_CLIENT_SESSIONMANAGER_H 00018 00019 #include <cstdint> 00020 #include <memory> 00021 #include <mutex> 00022 #include <string> 00023 00024 #include "RPC/Address.h" 00025 00026 namespace LogCabin { 00027 00028 // forward declaration 00029 namespace Core { 00030 class Config; 00031 } 00032 00033 // forward declaration 00034 namespace Event { 00035 class Loop; 00036 } 00037 00038 // forward declaration 00039 namespace RPC { 00040 class ClientSession; 00041 } 00042 00043 namespace Client { 00044 00045 /** 00046 * Used to create RPC::ClientSession objects and then immediately call 00047 * VerifyRecipient RPCs on them. 00048 * 00049 * TODO(ongaro): Consider encapsulating Backoff mechanism in here as well, 00050 * since session creation ought to be paired with Backoff. 00051 */ 00052 class SessionManager { 00053 public: 00054 00055 /** 00056 * Gets and sets a value while holding a mutex. 00057 */ 00058 template<typename T> 00059 class LockedAssignment { 00060 public: 00061 /** 00062 * Default constructor: empty. 00063 */ 00064 LockedAssignment() 00065 : mutex() 00066 , empty(true) 00067 , value() 00068 { 00069 } 00070 00071 /** 00072 * Constructor that initializes this object with the given value. 00073 */ 00074 explicit LockedAssignment(T value) 00075 : mutex() 00076 , empty(false) 00077 , value(value) 00078 { 00079 } 00080 00081 /** 00082 * Returns true and the value if there is one, or false and a default 00083 * constructed value otherwise. 00084 */ 00085 std::pair<bool, T> get() const { 00086 std::lock_guard<std::mutex> lockGuard(mutex); 00087 if (empty) 00088 return {false, T()}; 00089 T copy = value; 00090 return {true, copy}; 00091 } 00092 00093 /** 00094 * Returns the value if there is one, or a default constructed value 00095 * otherwise. 00096 */ 00097 T getOrDefault() const { 00098 std::lock_guard<std::mutex> lockGuard(mutex); 00099 if (empty) 00100 return T(); 00101 T copy = value; 00102 return copy; 00103 } 00104 00105 /** 00106 * Clears out the value, if any. 00107 */ 00108 void clear() { 00109 std::lock_guard<std::mutex> lockGuard(mutex); 00110 empty = true; 00111 value = T(); 00112 } 00113 00114 /** 00115 * Overwrites the value with the given one. 00116 */ 00117 void set(const T& newValue) { 00118 std::lock_guard<std::mutex> lockGuard(mutex); 00119 empty = false; 00120 value = newValue; 00121 } 00122 00123 private: 00124 mutable std::mutex mutex; 00125 bool empty; 00126 T value; 00127 }; 00128 00129 typedef LockedAssignment<std::string> ClusterUUID; 00130 typedef LockedAssignment<uint64_t> ServerId; 00131 00132 /** 00133 * Construtor. Takes a couple of parameters that are common to all sessions 00134 * so that you don't have to repeatedly provide them to createSession. 00135 * \param eventLoop 00136 * Event::Loop that will be used to find out when the session's 00137 * underlying socket may be read from or written to without blocking. 00138 * This object keeps a reference. 00139 * \param config 00140 * General settings. This object keeps a reference. 00141 */ 00142 SessionManager(Event::Loop& eventLoop, 00143 const Core::Config& config); 00144 00145 00146 /** 00147 * Connect to the given address. 00148 * \param address 00149 * The RPC server address on which to connect. 00150 * \param timeout 00151 * After this time has elapsed, stop trying to initiate the connection 00152 * and leave the session in an error state. 00153 * \param[in,out] clusterUUID 00154 * If set, the recipient will confirm that it matches this cluster 00155 * UUID. If empty and the recipient returns one, this will be set. 00156 * \param[in,out] serverId 00157 * If set, the recipient will confirm that it has this server ID. If 00158 * empty and the recipient returns one, this will be set. 00159 */ 00160 std::shared_ptr<RPC::ClientSession> 00161 createSession(const RPC::Address& address, 00162 RPC::Address::TimePoint timeout, 00163 ClusterUUID* clusterUUID = NULL, 00164 ServerId* serverId = NULL); 00165 00166 Event::Loop& eventLoop; 00167 private: 00168 const Core::Config& config; 00169 /** 00170 * Used only for unit testing. Set to false, normally. 00171 */ 00172 bool skipVerify; 00173 }; 00174 00175 } // namespace LogCabin::Client 00176 } // namespace LogCabin 00177 00178 #endif /* LOGCABIN_CLIENT_SESSIONMANAGER_H */