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_SERVER_SERVERSTATS_H 00017 #define LOGCABIN_SERVER_SERVERSTATS_H 00018 00019 #include <memory> 00020 #include <thread> 00021 00022 #include "build/Protocol/ServerStats.pb.h" 00023 00024 #include "Core/Mutex.h" 00025 #include "Core/Time.h" 00026 #include "Event/Signal.h" 00027 #include "Event/Timer.h" 00028 00029 namespace LogCabin { 00030 namespace Server { 00031 00032 // forward declaration 00033 class Globals; 00034 00035 /** 00036 * Manages creation of server statistics, which are used for diagnostics. 00037 * 00038 * Server statistics are gathered in two ways. First, this object maintains a 00039 * #stats structure that modules can fill in by acquiring a Lock and modifying 00040 * directly. This #stats structure is copied every time stats are requested. 00041 * Second, when stats are requested, #getCurrent() will ask certain modules 00042 * (such as RaftConsensus) to fill in the current information into a copy of 00043 * the stats structure. 00044 */ 00045 class ServerStats { 00046 public: 00047 /// Constructor. 00048 explicit ServerStats(Globals& globals); 00049 /// Destructor. 00050 ~ServerStats(); 00051 00052 /** 00053 * Called after Globals are initialized to finish setting up this class. 00054 * Attaches signal handler and starts stats dumper thread. Starts calling 00055 * other modules for their state in getCurrent(). 00056 */ 00057 void enable(); 00058 00059 /** 00060 * Prepare for shutdown. Waits for the statsDumper thread to exit, and 00061 * destroys the #deferred object (the opposite of #enable()). 00062 */ 00063 void exit(); 00064 00065 /** 00066 * Write the current stats to the debug log (NOTICE level). 00067 * This is preferred over calling getCurrent() followed by NOTICE(), since 00068 * it will arrange for the next periodic stats dump to be delayed (there's 00069 * not much sense in a periodic stats dump immediately following a manual 00070 * stats dump). 00071 */ 00072 void dumpToDebugLog() const; 00073 00074 /** 00075 * Calculate and return the current server stats. 00076 */ 00077 Protocol::ServerStats getCurrent() const; 00078 00079 /** 00080 * Provides read/write access to #stats, protected against concurrent 00081 * access. 00082 */ 00083 class Lock { 00084 public: 00085 /// Constructor. 00086 explicit Lock(ServerStats& wrapper); 00087 /// Destructor. 00088 ~Lock(); 00089 /// Structure dereference operator. Returns stats pointer. 00090 Protocol::ServerStats* operator->(); 00091 /// Indirection (dereference) operator. Returns stats reference. 00092 Protocol::ServerStats& operator*(); 00093 private: 00094 /// Handle to containing class. 00095 ServerStats& wrapper; 00096 /// Locks #mutex for the lifetime of this object. 00097 std::lock_guard<Core::Mutex> lockGuard; 00098 }; 00099 00100 private: 00101 /** 00102 * Used to dump stats periodically. 00103 */ 00104 typedef Core::Time::SteadyClock SteadyClock; 00105 00106 /** 00107 * Used to include wall time in stats. 00108 */ 00109 typedef Core::Time::SystemClock SystemClock; 00110 00111 /** 00112 * Asks statsDumper thread to dumps stats to the debug log (NOTICE level) 00113 * on SIGUSR1 signal. 00114 * (We don't ever want to collect stats from the Event Loop thread, since 00115 * that might stall the event loop for too long and/or acquire mutexes in 00116 * incorrect orders, opening up the possibility for deadlock.) 00117 */ 00118 class SignalHandler : public Event::Signal { 00119 public: 00120 /// Constructor. Registers itself as SIGUSR1 handler. 00121 explicit SignalHandler(ServerStats& serverStats); 00122 /// Fires when SIGUSR1 is received. Prints the stats to the log. 00123 void handleSignalEvent(); 00124 /// Handle to containing class. 00125 ServerStats& serverStats; 00126 }; 00127 00128 /** 00129 * Members that are constructed later, during enable(). 00130 * Whereas the ServerStats is constructed early in the server startup 00131 * process, these members get to access globals and globals.config in their 00132 * constructors. 00133 */ 00134 struct Deferred { 00135 /** 00136 * Constructor. Called during enable(). 00137 */ 00138 explicit Deferred(ServerStats& serverStats); 00139 00140 /** 00141 * See SignalHandler. 00142 */ 00143 SignalHandler signalHandler; 00144 00145 /** 00146 * Registers signalHandler with event loop. 00147 */ 00148 Event::Signal::Monitor signalMonitor; 00149 00150 /** 00151 * If nonzero, the #statsDumper thread will write the current stats to 00152 * the debug log if this duration has elapsed since the last dump. 00153 */ 00154 std::chrono::nanoseconds dumpInterval; 00155 00156 /** 00157 * This thread dumps the stats periodically and when signalled. 00158 * Dumping the stats is done from a separate thread so that the event 00159 * loop thread does not acquire locks in higher-level modules (which 00160 * could result in deadlocks or delays). Introduced for 00161 * https://github.com/logcabin/logcabin/issues/159 . 00162 */ 00163 std::thread statsDumper; 00164 }; 00165 00166 /** 00167 * See public #dumpToDebugLog() above. 00168 * Internally releases and reacquires the lock for concurrency and to avoid 00169 * deadlock. 00170 */ 00171 void dumpToDebugLog(std::unique_lock<Core::Mutex>& lockGuard) const; 00172 00173 /** 00174 * See public #getCurrent() above. 00175 * Internally releases and reacquires the lock for concurrency and to avoid 00176 * deadlock. 00177 */ 00178 Protocol::ServerStats 00179 getCurrent(std::unique_lock<Core::Mutex>& lockGuard) const; 00180 00181 void statsDumperMain(); 00182 00183 /** 00184 * Server-wide objects. 00185 */ 00186 Globals& globals; 00187 00188 /** 00189 * Protects all of the following members of this class. 00190 */ 00191 mutable Core::Mutex mutex; 00192 00193 /** 00194 * Notified when #isStatsDumpRequested is set and when #exiting is set. 00195 * statsDumper waits on this. 00196 */ 00197 Core::ConditionVariable statsDumpRequested; 00198 00199 /** 00200 * Set to true when statsDumper should exit. 00201 */ 00202 bool exiting; 00203 00204 /** 00205 * Set to true when statsDumper should write the entire stats to the debug 00206 * log. Mutable so that it can be reset to false in const methods such as 00207 * dumpToDebugLog(). 00208 */ 00209 mutable bool isStatsDumpRequested; 00210 00211 /** 00212 * The last time when the stats were written to the debug log. 00213 * Monotonically increases. 00214 */ 00215 mutable Core::Time::SteadyClock::time_point lastDumped; 00216 00217 /** 00218 * Partially filled-in structure that is copied as the basis of all calls 00219 * to getCurrent(). 00220 */ 00221 Protocol::ServerStats stats; 00222 00223 /** 00224 * See Deferred. If non-NULL, enabled() has already been called, and other 00225 * modules should be queried for stats during getCurrent(). 00226 */ 00227 std::unique_ptr<Deferred> deferred; 00228 }; 00229 00230 } // namespace LogCabin::Server 00231 } // namespace LogCabin 00232 00233 #endif /* LOGCABIN_SERVER_SERVERSTATS_H */