summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authordaveh86 <howsdav@gmail.com>2014-08-05 10:13:49 +1000
committerBenety Goh <benety@mongodb.com>2014-08-11 10:30:06 -0400
commitcf2917a1e94959a696642407425f89fe14ccb1b4 (patch)
tree713039bd3ef82f4978f44dfa8d6a0cb130e60342 /src/mongo
parent4f5703ae45f05576fac5261dc985aabd142a0a78 (diff)
downloadmongo-cf2917a1e94959a696642407425f89fe14ccb1b4.tar.gz
SERVER-8752 Add config.actionlog
Closes #739 Signed-off-by: Benety Goh <benety@mongodb.com>
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/s/SConscript1
-rw-r--r--src/mongo/s/balance.cpp110
-rw-r--r--src/mongo/s/type_actionlog.cpp153
-rw-r--r--src/mongo/s/type_actionlog.h204
4 files changed, 468 insertions, 0 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 1514261b5f2..3b2852e8332 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -8,6 +8,7 @@ Import("env")
env.Library('base', ['mongo_version_range.cpp',
'range_arithmetic.cpp',
+ 'type_actionlog.cpp',
'type_changelog.cpp',
'type_chunk.cpp',
'type_collection.cpp',
diff --git a/src/mongo/s/balance.cpp b/src/mongo/s/balance.cpp
index 87f71781afb..7c47dd4ba54 100644
--- a/src/mongo/s/balance.cpp
+++ b/src/mongo/s/balance.cpp
@@ -43,6 +43,7 @@
#include "mongo/s/grid.h"
#include "mongo/s/server.h"
#include "mongo/s/shard.h"
+#include "mongo/s/type_actionlog.h"
#include "mongo/s/type_chunk.h"
#include "mongo/s/type_collection.h"
#include "mongo/s/type_mongos.h"
@@ -50,6 +51,7 @@
#include "mongo/s/type_tags.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
+#include "mongo/util/timer.h"
#include "mongo/util/version.h"
namespace mongo {
@@ -157,6 +159,95 @@ namespace mongo {
NULL );
}
+ /*
+ * Builds the details object for the actionlog.
+ * Current formats for detail are:
+ * Success: {
+ * "candidateChunks" : ,
+ * "chunksMoved" : ,
+ * "executionTimeMillis" : ,
+ * "errorOccured" : false
+ * }
+ * Failure: {
+ * "executionTimeMillis" : ,
+ * "errmsg" : ,
+ * "errorOccured" : true
+ * }
+ * @param didError, did this round end in an error?
+ * @param executionTime, the time this round took to run
+ * @param candidateChunks, the number of chunks identified to be moved
+ * @param chunksMoved, the number of chunks moved
+ * @param errmsg, the error message for this round
+ */
+
+ static BSONObj _buildDetails( bool didError, int executionTime,
+ int candidateChunks, int chunksMoved, const std::string& errmsg ) {
+
+ BSONObjBuilder builder;
+ builder.append("executionTimeMillis", executionTime);
+ builder.append("errorOccured", didError);
+
+ if ( didError ) {
+ builder.append("errmsg", errmsg);
+ } else {
+ builder.append("candidateChunks", candidateChunks);
+ builder.append("chunksMoved", chunksMoved);
+ }
+ return builder.obj();
+ }
+
+ /**
+ * Reports the result of the balancer round into config.actionlog
+ *
+ * @param actionLog, which contains the balancer round information to be logged
+ *
+ */
+
+ static void _reportRound( ActionLogType& actionLog) {
+ try {
+ ScopedDbConnection conn( configServer.getConnectionString(), 30 );
+
+ // send a copy of the message to the log in case it doesn't reach config.actionlog
+ actionLog.setTime(jsTime());
+
+ LOG(1) << "about to log balancer result: " << actionLog;
+
+ // The following method is not thread safe. However, there is only one balancer
+ // thread per mongos process. The create collection is a a no-op when the collection
+ // already exists
+ static bool createActionlog = false;
+ if ( ! createActionlog ) {
+ try {
+ static const int actionLogSizeBytes = 1024 * 1024 * 2;
+ conn->createCollection( ActionLogType::ConfigNS , actionLogSizeBytes , true );
+ }
+ catch ( const DBException& ex ) {
+ LOG(1) << "config.actionlog could not be created, another mongos process "
+ << "may have done so" << causedBy(ex);
+
+ }
+ createActionlog = true;
+ }
+
+ Status result = clusterInsert( ActionLogType::ConfigNS,
+ actionLog.toBSON(),
+ WriteConcernOptions::AllConfigs,
+ NULL );
+
+ if ( !result.isOK() ) {
+ log() << "Error encountered while logging action from balancer "
+ << result.reason();
+ }
+
+ conn.done();
+ }
+ catch ( const DBException& ex ) {
+ // if we got here, it means the config change is only in the log;
+ // the change didn't make it to config.actionlog
+ warning() << "could not log balancer result" << causedBy(ex);
+ }
+ }
+
bool Balancer::_checkOIDs() {
vector<Shard> all;
Shard::getAllShards( all );
@@ -458,6 +549,12 @@ namespace mongo {
while ( ! inShutdown() ) {
+ Timer balanceRoundTimer;
+ ActionLogType actionLog;
+
+ actionLog.setServer(getHostNameCached());
+ actionLog.setWhat("balancer.round");
+
try {
ScopedDbConnection conn(config.toString(), 30);
@@ -465,6 +562,8 @@ namespace mongo {
// ping has to be first so we keep things in the config server in sync
_ping();
+ BSONObj balancerResult;
+
// use fresh shard state
Shard::reloadShardInfo();
@@ -552,6 +651,11 @@ namespace mongo {
waitForDelete );
}
+ actionLog.setDetails( _buildDetails( false, balanceRoundTimer.millis(),
+ static_cast<int>(candidateChunks.size()), _balancedLastTime, "") );
+
+ _reportRound( actionLog );
+
LOG(1) << "*** end of balancing round" << endl;
}
@@ -568,6 +672,12 @@ namespace mongo {
// Just to match the opening statement if in log level 1
LOG(1) << "*** End of balancing round" << endl;
+ // This round failed, tell the world!
+ actionLog.setDetails( _buildDetails( true, balanceRoundTimer.millis(),
+ 0, 0, e.what()) );
+
+ _reportRound( actionLog );
+
sleepsecs( sleepTime ); // sleep a fair amount b/c of error
continue;
}
diff --git a/src/mongo/s/type_actionlog.cpp b/src/mongo/s/type_actionlog.cpp
new file mode 100644
index 00000000000..29dc9d97d66
--- /dev/null
+++ b/src/mongo/s/type_actionlog.cpp
@@ -0,0 +1,153 @@
+/**
+ * Copyright (C) 2014 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+#include "mongo/s/type_actionlog.h"
+
+#include "mongo/db/field_parser.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+
+ using mongo::str::stream;
+
+ const std::string ActionLogType::ConfigNS = "config.actionlog";
+
+ const BSONField<std::string> ActionLogType::server("server");
+ const BSONField<std::string> ActionLogType::what("what");
+ const BSONField<Date_t> ActionLogType::time("time");
+ const BSONField<BSONObj> ActionLogType::details("details");
+
+ ActionLogType::ActionLogType() {
+ clear();
+ }
+
+ ActionLogType::~ActionLogType() {
+ }
+
+ bool ActionLogType::isValid(std::string* errMsg) const {
+ std::string dummy;
+ if (errMsg == NULL) {
+ errMsg = &dummy;
+ }
+
+ // All the mandatory fields must be present.
+ if (!_isServerSet) {
+ *errMsg = stream() << "missing " << server.name() << " field";
+ return false;
+ }
+ if (!_isTimeSet) {
+ *errMsg = stream() << "missing " << time.name() << " field";
+ return false;
+ }
+ if (!_isWhatSet) {
+ *errMsg = stream() << "missing " << what.name() << " field";
+ return false;
+ }
+ if (!_isDetailsSet) {
+ *errMsg = stream() << "missing " << details.name() << " field";
+ return false;
+ }
+
+ return true;
+ }
+
+ BSONObj ActionLogType::toBSON() const {
+ BSONObjBuilder builder;
+
+ if (_isServerSet) builder.append(server(), _server);
+ if (_isTimeSet) builder.append(time(), _time);
+ if (_isWhatSet) builder.append(what(), _time);
+ if (_isDetailsSet) builder.append(details(), _details);
+
+ return builder.obj();
+ }
+
+ bool ActionLogType::parseBSON(const BSONObj& source, string* errMsg) {
+ clear();
+
+ std::string dummy;
+ if (!errMsg) errMsg = &dummy;
+
+ FieldParser::FieldState fieldState;
+
+ fieldState = FieldParser::extract(source, server, &_server, errMsg);
+ if (fieldState == FieldParser::FIELD_INVALID) return false;
+ _isServerSet = fieldState == FieldParser::FIELD_SET;
+
+ fieldState = FieldParser::extract(source, time, &_time, errMsg);
+ if (fieldState == FieldParser::FIELD_INVALID) return false;
+ _isTimeSet = fieldState == FieldParser::FIELD_SET;
+
+ fieldState = FieldParser::extract(source, what, &_what, errMsg);
+ if (fieldState == FieldParser::FIELD_INVALID) return false;
+ _isWhatSet = fieldState == FieldParser::FIELD_SET;
+
+ fieldState = FieldParser::extract(source, details, &_details, errMsg);
+ if (fieldState == FieldParser::FIELD_INVALID) return false;
+ _isDetailsSet = fieldState == FieldParser::FIELD_SET;
+
+ return true;
+ }
+
+ void ActionLogType::clear() {
+
+ _server.clear();
+ _isServerSet = false;
+
+ _what.clear();
+ _isWhatSet = false;
+
+ _time = 0ULL;
+ _isTimeSet = false;
+
+ _details = BSONObj();
+ _isDetailsSet = false;
+
+ }
+
+ void ActionLogType::cloneTo(ActionLogType* other) const {
+ other->clear();
+
+ other->_server = _server;
+ other->_isServerSet = _isServerSet;
+
+ other->_what = _what;
+ other->_isWhatSet = _isWhatSet;
+
+ other->_time = _time;
+ other->_isTimeSet = _isTimeSet;
+
+ other->_details = _details;
+ other->_isDetailsSet = _isDetailsSet;
+
+ }
+
+ std::string ActionLogType::toString() const {
+ return toBSON().toString();
+ }
+
+} // namespace mongo
diff --git a/src/mongo/s/type_actionlog.h b/src/mongo/s/type_actionlog.h
new file mode 100644
index 00000000000..3053657722e
--- /dev/null
+++ b/src/mongo/s/type_actionlog.h
@@ -0,0 +1,204 @@
+/**
+ * Copyright (C) 2014 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <string>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/string_data.h"
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+ /**
+ * This class represents the layout and contents of documents contained in the
+ * config.actionlog collection. All manipulation of documents coming from that
+ * collection should be done with this class.
+ *
+ * Usage Example:
+ *
+ * // Contact the config. 'conn' has been obtained before.
+ * DBClientBase* conn;
+ * BSONObj query = QUERY(ActionLogType::exampleField("exampleFieldName"));
+ * exampleDoc = conn->findOne(ActionLogType::ConfigNS, query);
+ *
+ * // Process the response.
+ * ActionLogType exampleType;
+ * std::string errMsg;
+ * if (!exampleType.parseBSON(exampleDoc, &errMsg) || !exampleType.isValid(&errMsg)) {
+ * // Can't use 'exampleType'. Take action.
+ * }
+ * // use 'exampleType'
+ *
+ */
+ class ActionLogType {
+ MONGO_DISALLOW_COPYING(ActionLogType);
+ public:
+
+ //
+ // schema declarations
+ //
+
+ // Name of the actionlog collection in the config server.
+ static const std::string ConfigNS;
+
+ // Field names and types in the actionlog collection type.
+ static const BSONField<std::string> server;
+ static const BSONField<std::string> what;
+ static const BSONField<Date_t> time;
+ static const BSONField<BSONObj> details;
+
+ // Common field names included under details
+ static const BSONField<int> candidateChunks;
+ static const BSONField<int> chunksMoved;
+ static const BSONField<bool> didError;
+ static const BSONField<long long> executionTimeMicros;
+ static const BSONField<std::string> errmsg;
+
+
+ //
+ // actionlog type methods
+ //
+
+ ActionLogType();
+ ~ActionLogType();
+
+ /**
+ * Returns true if all the mandatory fields are present and have valid
+ * representations. Otherwise returns false and fills in the optional 'errMsg' string.
+ */
+ bool isValid(std::string* errMsg) const;
+
+ /**
+ * Returns the BSON representation of the entry.
+ */
+ BSONObj toBSON() const;
+
+ void buildDetails();
+
+ /**
+ * Clears and populates the internal state using the 'source' BSON object if the
+ * latter contains valid values. Otherwise sets errMsg and returns false.
+ */
+ bool parseBSON(const BSONObj& source, std::string* errMsg);
+
+ /**
+ * Clears the internal state.
+ */
+ void clear();
+
+ /**
+ * Copies all the fields present in 'this' to 'other'.
+ */
+ void cloneTo(ActionLogType* other) const;
+
+ /**
+ * Returns a std::string representation of the current internal state.
+ */
+ std::string toString() const;
+
+ //
+ // individual field accessors
+ //
+
+ void setServer(const StringData& server) {
+ _server = server.toString();
+ _isServerSet = true;
+ }
+
+ void unsetServer() { _isServerSet = false; }
+
+ bool isServerSet() const { return _isServerSet; }
+
+ // Calling get*() methods when the member is not set results in undefined behavior
+ const std::string& getServer() const {
+ dassert(_isServerSet);
+ return _what;
+ }
+
+ void setWhat(const StringData& what) {
+ _server = what.toString();
+ _isWhatSet = true;
+ }
+
+ void unsetWhat() { _isWhatSet = false; }
+
+ bool isWhatSet() const { return _isWhatSet; }
+
+ // Calling get*() methods when the member is not set results in undefined behavior
+ const std::string& getWhat() const {
+ dassert(_isWhatSet);
+ return _what;
+ }
+
+ void setTime(const Date_t time) {
+ _time = time;
+ _isTimeSet = true;
+ }
+
+ void unsetTime() { _isTimeSet = false; }
+
+ bool isTimeSet() const { return _isTimeSet; }
+
+ // Calling get*() methods when the member is not set results in undefined behavior
+ const Date_t getTime() const {
+ dassert(_isTimeSet);
+ return _time;
+ }
+
+ void setDetails(const BSONObj& details) {
+ _details = details.getOwned();
+ _isDetailsSet = true;
+ }
+
+ void unsetDetails() { _isDetailsSet = false; }
+
+ bool isDetailsSet() const { return _isDetailsSet; }
+
+ // Calling get*() methods when the member is not set results in undefined behavior
+ const BSONObj getDetails() const {
+ dassert(_isDetailsSet);
+ return _details;
+ }
+
+ private:
+ // Convention: (M)andatory, (O)ptional, (S)pecial rule.
+ std::string _server; // (M) hostname of server that we are making the change on.
+ // Does not include port.
+ bool _isServerSet;
+ std::string _what; // (M) what the action being performed was.
+ bool _isWhatSet;
+ Date_t _time; // (M) time this change was made
+ bool _isTimeSet;
+ BSONObj _details; // (M) A BSONObj containing extra information about some operations
+ bool _isDetailsSet;
+
+ };
+
+} // namespace mongo