LogCabin
Server/ServerStats.h
Go to the documentation of this file.
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 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines