diff options
author | Andy Schwerin <schwerin@10gen.com> | 2013-07-12 18:05:35 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2013-07-12 18:08:19 -0400 |
commit | 6e3ccc5649d16fd9940bc8fd1b490556d5767bf8 (patch) | |
tree | 6485289521af46ae932edb12a54c39737bea03f4 /src/mongo/logger/ramlog.h | |
parent | 15333b2a308fd26c28448810780b06407328a795 (diff) | |
download | mongo-6e3ccc5649d16fd9940bc8fd1b490556d5767bf8.tar.gz |
SERVER-10172 Refactor RamLog to make it thread-safe.
Also prevent accidental creation of duplicate ramlogs of the same name.
Diffstat (limited to 'src/mongo/logger/ramlog.h')
-rw-r--r-- | src/mongo/logger/ramlog.h | 105 |
1 files changed, 93 insertions, 12 deletions
diff --git a/src/mongo/logger/ramlog.h b/src/mongo/logger/ramlog.h index 2b78d91daaa..16263055c38 100644 --- a/src/mongo/logger/ramlog.h +++ b/src/mongo/logger/ramlog.h @@ -17,7 +17,6 @@ #pragma once -#include <map> #include <sstream> #include <string> #include <vector> @@ -32,23 +31,61 @@ namespace mongo { + /** + * Fixed-capacity log of line-oriented messages. + * + * Holds up to RamLog::N lines of up to RamLog::C bytes, each. + * + * RamLogs are stored in a global registry, accessed via RamLog::get() and + * RamLog::getIfExists(). + * + * RamLogs and their registry are self-synchronizing. See documentary comments. + * To read a RamLog, instantiate a RamLog::LineIterator, documented below. + */ class RamLog : public logger::Tee { MONGO_DISALLOW_COPYING(RamLog); public: - RamLog( const std::string& name ); + class LineIterator; + friend class RamLog::LineIterator; + + /** + * Returns a pointer to the ramlog named "name", creating one if it did not already exist. + * + * Synchronizes on the RamLog catalog lock, _namedLock. + */ + static RamLog* get(const std::string& name); + + /** + * Returns a pointer to the ramlog named "name", or NULL if no such ramlog exists. + * + * Synchronizes on the RamLog catalog lock, _namedLock. + */ + static RamLog* getIfExists(const std::string& name); + + /** + * Writes the names of all existing ramlogs into "names". + * + * Synchronizes on the RamLog catalog lock, _namedLock. + */ + static void getNames( std::vector<std::string>& names ); + /** + * Writes "str" as a line into the RamLog. If "str" is longer than the maximum + * line size, RamLog::C, truncates the line to the first C bytes. If "str" + * is shorter than RamLog::C and has a terminal '\n', it omits that character. + * + * Synchronized on the instance's own mutex, _mutex. + */ void write(const std::string& str); - void get( std::vector<const char*>& v); + /** + * Writes an HTML representation of the log to "s". + * + * Synchronized on the instance's own mutex, _mutex. + */ void toHTML(std::stringstream& s); - static RamLog* get( const std::string& name ); - static void getNames( std::vector<std::string>& names ); - - time_t lastWrite(); - long long getTotalLinesWritten(); - private: static int repeats(const std::vector<const char *>& v, int i); static string clean(const std::vector<const char *>& v, int i, string line=""); @@ -57,6 +94,7 @@ namespace mongo { /* turn http:... into an anchor */ static string linkify(const char *s); + explicit RamLog( const std::string& name ); ~RamLog(); // want this private as we want to leak so we can use them till the very end enum { @@ -64,6 +102,8 @@ namespace mongo { C = 512 // max size of line }; + const char* getLine_inlock(unsigned lineNumber) const; + boost::mutex _mutex; // Guards all non-static data. char lines[N][C]; unsigned h; // current position @@ -71,12 +111,53 @@ namespace mongo { string _name; long long _totalLinesWritten; - typedef std::map<string,RamLog*> RM; - static mongo::mutex* _namedLock; - static RM* _named; time_t _lastWrite; }; + /** + * Iterator over the lines of a RamLog. + * + * Also acts as a means of inspecting other properites of a ramlog consistently. + * + * Instances of LineIterator hold the lock for the underlying RamLog for their whole lifetime, + * and so should not be kept around. + */ + class RamLog::LineIterator { + MONGO_DISALLOW_COPYING(LineIterator); + public: + explicit LineIterator(RamLog* ramlog); + + /** + * Returns true if there are more lines available to return by calls to next(). + */ + bool more() const { return _nextLineIndex < _ramlog->n; } + + /** + * Returns the next line and advances the iterator. + */ + const char* next() { + return _ramlog->getLine_inlock(_nextLineIndex++); // Postfix increment. + } + + /** + * Returns the time of the last write to the ramlog. + */ + time_t lastWrite(); + + /** + * Returns the total number of lines ever written to the ramlog. + */ + long long getTotalLinesWritten(); + + private: + const RamLog* _ramlog; + boost::lock_guard<boost::mutex> _lock; + unsigned _nextLineIndex; + }; + + /** + * Appender for appending MessageEvents to a RamLog. + */ class RamLogAppender : public logger::Appender<logger::MessageEventEphemeral> { public: explicit RamLogAppender(RamLog* ramlog); |