summaryrefslogtreecommitdiff
path: root/src/mongo/logger/ramlog.h
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-07-12 18:05:35 -0400
committerAndy Schwerin <schwerin@10gen.com>2013-07-12 18:08:19 -0400
commit6e3ccc5649d16fd9940bc8fd1b490556d5767bf8 (patch)
tree6485289521af46ae932edb12a54c39737bea03f4 /src/mongo/logger/ramlog.h
parent15333b2a308fd26c28448810780b06407328a795 (diff)
downloadmongo-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.h105
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);