diff options
author | Eric Milkie <milkie@10gen.com> | 2014-10-02 16:17:25 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2014-10-03 15:39:19 -0400 |
commit | e0509e511bdbac2329d32a7238b51cd6b5ddd591 (patch) | |
tree | e566d6a137c55483e3a17200b1e4dbd67e1f5ead | |
parent | d32dc5f88567b11eb503a8343cb8b4b3d8c68c76 (diff) | |
download | mongo-e0509e511bdbac2329d32a7238b51cd6b5ddd591.tar.gz |
SERVER-15312 move replIndexPrefetch parameter out of legacy and into Applier (BGSync)
-rw-r--r-- | src/mongo/db/prefetch.cpp | 243 | ||||
-rw-r--r-- | src/mongo/db/prefetch.h | 13 | ||||
-rw-r--r-- | src/mongo/db/repl/bgsync.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/bgsync.h | 93 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_impl.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_impl.h | 14 | ||||
-rw-r--r-- | src/mongo/db/repl/rs.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_sync.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/repl/sync_tail.cpp | 1 |
9 files changed, 233 insertions, 230 deletions
diff --git a/src/mongo/db/prefetch.cpp b/src/mongo/db/prefetch.cpp index 21b0d15d770..0f4a6c76a77 100644 --- a/src/mongo/db/prefetch.cpp +++ b/src/mongo/db/prefetch.cpp @@ -26,123 +26,53 @@ * it in the license file. */ -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kQuery +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kReplication #include "mongo/platform/basic.h" #include "mongo/db/prefetch.h" +#include "mongo/db/catalog/collection.h" +#include "mongo/db/commands/server_status_metric.h" #include "mongo/db/dbhelpers.h" -#include "mongo/db/diskloc.h" #include "mongo/db/index/index_access_method.h" -#include "mongo/db/catalog/collection.h" #include "mongo/db/jsobj.h" -#include "mongo/db/repl/rs.h" +#include "mongo/db/repl/bgsync.h" +#include "mongo/db/repl/repl_coordinator.h" +#include "mongo/db/repl/repl_coordinator_global.h" +#include "mongo/db/server_parameters.h" #include "mongo/db/stats/timer_stats.h" -#include "mongo/db/commands/server_status_metric.h" #include "mongo/util/log.h" +#include "mongo/util/mmap.h" namespace mongo { - +namespace repl { +namespace { // todo / idea: the prefetcher, when it fetches _id, on an upsert, will see if the record exists. if it does not, // at write time, we can just do an insert, which will be faster. //The count (of batches) and time spent fetching pages before application // -- meaning depends on the prefetch behavior: all, _id index, none, etc.) - static TimerStats prefetchIndexStats; - static ServerStatusMetricField<TimerStats> displayPrefetchIndexPages( - "repl.preload.indexes", - &prefetchIndexStats ); - static TimerStats prefetchDocStats; - static ServerStatusMetricField<TimerStats> displayPrefetchDocPages( - "repl.preload.docs", - &prefetchDocStats ); - - void prefetchIndexPages(OperationContext* txn, - Collection* collection, - const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, - const BSONObj& obj); - - void prefetchRecordPages(OperationContext* txn, const char* ns, const BSONObj& obj); - - - // prefetch for an oplog operation - void prefetchPagesForReplicatedOp(OperationContext* txn, - Database* db, - const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, - const BSONObj& op) { - const char *opField; - const char *opType = op.getStringField("op"); - switch (*opType) { - case 'i': // insert - case 'd': // delete - opField = "o"; - break; - case 'u': // update - opField = "o2"; - break; - default: - // prefetch ignores other ops - return; - } - - BSONObj obj = op.getObjectField(opField); - const char *ns = op.getStringField("ns"); - - Collection* collection = db->getCollection( txn, ns ); - if ( !collection ) - return; - - LOG(4) << "index prefetch for op " << *opType << endl; - - DEV txn->lockState()->assertAtLeastReadLocked(ns); - - // should we prefetch index pages on updates? if the update is in-place and doesn't change - // indexed values, it is actually slower - a lot slower if there are a dozen indexes or - // lots of multikeys. possible variations (not all mutually exclusive): - // 1) current behavior: full prefetch - // 2) don't do it for updates - // 3) don't do multikey indexes for updates - // 4) don't prefetchIndexPages on some heuristic; e.g., if it's an $inc. - // 5) if not prefetching index pages (#2), we should do it if we are upsertings and it - // will be an insert. to do that we could do the prefetchRecordPage first and if DNE - // then we do #1. - // - // note that on deletes 'obj' does not have all the keys we would want to prefetch on. - // a way to achieve that would be to prefetch the record first, and then afterwards do - // this part. - // - prefetchIndexPages(txn, collection, prefetchConfig, obj); - - // do not prefetch the data for inserts; it doesn't exist yet - // - // we should consider doing the record prefetch for the delete op case as we hit the record - // when we delete. note if done we only want to touch the first page. - // - // update: do record prefetch. - if ((*opType == 'u') && - // do not prefetch the data for capped collections because - // they typically do not have an _id index for findById() to use. - !collection->isCapped()) { - prefetchRecordPages(txn, ns, obj); - } - } + TimerStats prefetchIndexStats; + ServerStatusMetricField<TimerStats> displayPrefetchIndexPages("repl.preload.indexes", + &prefetchIndexStats ); + TimerStats prefetchDocStats; + ServerStatusMetricField<TimerStats> displayPrefetchDocPages("repl.preload.docs", + &prefetchDocStats ); // page in pages needed for all index lookups on a given object void prefetchIndexPages(OperationContext* txn, Collection* collection, - const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, + const BackgroundSync::IndexPrefetchConfig& prefetchConfig, const BSONObj& obj) { - DiskLoc unusedDl; // unused - BSONObjSet unusedKeys; // do we want prefetchConfig to be (1) as-is, (2) for update ops only, or (3) configured per op type? // One might want PREFETCH_NONE for updates, but it's more rare that it is a bad idea for inserts. // #3 (per op), a big issue would be "too many knobs". switch (prefetchConfig) { - case repl::ReplSetImpl::PREFETCH_NONE: + case BackgroundSync::PREFETCH_NONE: return; - case repl::ReplSetImpl::PREFETCH_ID_ONLY: + case BackgroundSync::PREFETCH_ID_ONLY: { TimerHolder timer( &prefetchIndexStats); // on the update op case, the call to prefetchRecordPages will touch the _id index. @@ -160,7 +90,7 @@ namespace mongo { } break; } - case repl::ReplSetImpl::PREFETCH_ALL: + case BackgroundSync::PREFETCH_ALL: { // indexCount includes all indexes, including ones // in the process of being built @@ -178,7 +108,6 @@ namespace mongo { catch (const DBException& e) { LOG(2) << "ignoring exception in prefetchIndexPages(): " << e.what() << endl; } - unusedKeys.clear(); } break; } @@ -215,4 +144,134 @@ namespace mongo { } } } -} +} // namespace + + // prefetch for an oplog operation + void prefetchPagesForReplicatedOp(OperationContext* txn, + Database* db, + const BSONObj& op) { + const BackgroundSync::IndexPrefetchConfig prefetchConfig = + BackgroundSync::get()->getIndexPrefetchConfig(); + const char *opField; + const char *opType = op.getStringField("op"); + switch (*opType) { + case 'i': // insert + case 'd': // delete + opField = "o"; + break; + case 'u': // update + opField = "o2"; + break; + default: + // prefetch ignores other ops + return; + } + + BSONObj obj = op.getObjectField(opField); + const char *ns = op.getStringField("ns"); + + Collection* collection = db->getCollection( txn, ns ); + if ( !collection ) + return; + + LOG(4) << "index prefetch for op " << *opType << endl; + + DEV txn->lockState()->assertAtLeastReadLocked(ns); + + // should we prefetch index pages on updates? if the update is in-place and doesn't change + // indexed values, it is actually slower - a lot slower if there are a dozen indexes or + // lots of multikeys. possible variations (not all mutually exclusive): + // 1) current behavior: full prefetch + // 2) don't do it for updates + // 3) don't do multikey indexes for updates + // 4) don't prefetchIndexPages on some heuristic; e.g., if it's an $inc. + // 5) if not prefetching index pages (#2), we should do it if we are upsertings and it + // will be an insert. to do that we could do the prefetchRecordPage first and if DNE + // then we do #1. + // + // note that on deletes 'obj' does not have all the keys we would want to prefetch on. + // a way to achieve that would be to prefetch the record first, and then afterwards do + // this part. + // + prefetchIndexPages(txn, collection, prefetchConfig, obj); + + // do not prefetch the data for inserts; it doesn't exist yet + // + // we should consider doing the record prefetch for the delete op case as we hit the record + // when we delete. note if done we only want to touch the first page. + // + // update: do record prefetch. + if ((*opType == 'u') && + // do not prefetch the data for capped collections because + // they typically do not have an _id index for findById() to use. + !collection->isCapped()) { + prefetchRecordPages(txn, ns, obj); + } + } + + class ReplIndexPrefetch : public ServerParameter { + public: + ReplIndexPrefetch() + : ServerParameter( ServerParameterSet::getGlobal(), "replIndexPrefetch" ) { + } + + virtual ~ReplIndexPrefetch() { + } + + const char * _value() { + if (getGlobalReplicationCoordinator()->getReplicationMode() != + ReplicationCoordinator::modeReplSet) { + return "uninitialized"; + } + BackgroundSync::IndexPrefetchConfig ip = + BackgroundSync::get()->getIndexPrefetchConfig(); + switch (ip) { + case BackgroundSync::PREFETCH_NONE: + return "none"; + case BackgroundSync::PREFETCH_ID_ONLY: + return "_id_only"; + case BackgroundSync::PREFETCH_ALL: + return "all"; + default: + return "invalid"; + } + } + + virtual void append(OperationContext* txn, BSONObjBuilder& b, const string& name) { + b.append( name, _value() ); + } + + virtual Status set( const BSONElement& newValueElement ) { + if (getGlobalReplicationCoordinator()->getReplicationMode() != + ReplicationCoordinator::modeReplSet) { + return Status( ErrorCodes::BadValue, "replication is not enabled" ); + } + + std::string prefetch = newValueElement.valuestrsafe(); + return setFromString( prefetch ); + } + + virtual Status setFromString( const string& prefetch ) { + log() << "changing replication index prefetch behavior to " << prefetch << endl; + + BackgroundSync::IndexPrefetchConfig prefetchConfig; + + if (prefetch == "none") + prefetchConfig = BackgroundSync::PREFETCH_NONE; + else if (prefetch == "_id_only") + prefetchConfig = BackgroundSync::PREFETCH_ID_ONLY; + else if (prefetch == "all") + prefetchConfig = BackgroundSync::PREFETCH_ALL; + else { + return Status( ErrorCodes::BadValue, + str::stream() << "unrecognized indexPrefetch setting: " << prefetch ); + } + + BackgroundSync::get()->setIndexPrefetchConfig(prefetchConfig); + return Status::OK(); + } + + } replIndexPrefetch; + +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/prefetch.h b/src/mongo/db/prefetch.h index 89ac800bea4..97a826092e6 100644 --- a/src/mongo/db/prefetch.h +++ b/src/mongo/db/prefetch.h @@ -27,18 +27,15 @@ */ #pragma once -#include "mongo/db/jsobj.h" -#include "mongo/db/diskloc.h" -#include "mongo/db/repl/repl_set_impl.h" - namespace mongo { - class Collection; + class BSONObj; class Database; class OperationContext; +namespace repl { - // page in both index and data pages for an op from the oplog + // page in possible index and/or data pages for an op from the oplog void prefetchPagesForReplicatedOp(OperationContext* txn, Database* db, - const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, const BSONObj& op); -} +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp index d25f2690ddf..743a7d6300e 100644 --- a/src/mongo/db/repl/bgsync.cpp +++ b/src/mongo/db/repl/bgsync.cpp @@ -108,7 +108,8 @@ namespace { _appliedBuffer(true), _assumingPrimary(false), _replCoord(getGlobalReplicationCoordinator()), - _initialSyncRequestedFlag(false) { + _initialSyncRequestedFlag(false), + _indexPrefetchConfig(PREFETCH_ALL) { } BackgroundSync* BackgroundSync::get() { diff --git a/src/mongo/db/repl/bgsync.h b/src/mongo/db/repl/bgsync.h index 5548204a3db..67b9a74d0d1 100644 --- a/src/mongo/db/repl/bgsync.h +++ b/src/mongo/db/repl/bgsync.h @@ -67,6 +67,60 @@ namespace repl { * 3. BackgroundSync::_mutex */ class BackgroundSync : public BackgroundSyncInterface { + public: + // Allow index prefetching to be turned on/off + enum IndexPrefetchConfig { + PREFETCH_NONE=0, PREFETCH_ID_ONLY=1, PREFETCH_ALL=2 + }; + + static BackgroundSync* get(); + + // stop syncing (when this node becomes a primary, e.g.) + void stop(); + bool isAssumingPrimary_inlock(); + + + void shutdown(); + void notify(); + + virtual ~BackgroundSync() {} + + // starts the producer thread + void producerThread(); + // starts the sync target notifying thread + void notifierThread(); + + HostAndPort getSyncTarget(); + + // Interface implementation + + virtual bool peek(BSONObj* op); + virtual void consume(); + virtual void clearSyncTarget(); + virtual void waitForMore(); + + // For monitoring + BSONObj getCounters(); + + // Wait for replication to finish and buffer to be applied so that the member can become + // primary. + void stopReplicationAndFlushBuffer(); + + long long getLastAppliedHash() const; + void setLastAppliedHash(long long oldH); + void loadLastAppliedHash(OperationContext* txn); + + bool getInitialSyncRequestedFlag(); + void setInitialSyncRequestedFlag(bool value); + + void setIndexPrefetchConfig(const IndexPrefetchConfig cfg) { + _indexPrefetchConfig = cfg; + } + + IndexPrefetchConfig getIndexPrefetchConfig() { + return _indexPrefetchConfig; + } + private: static BackgroundSync *s_instance; // protects creation of s_instance @@ -121,44 +175,9 @@ namespace repl { bool _initialSyncRequestedFlag; boost::mutex _initialSyncMutex; - public: - // stop syncing (when this node becomes a primary, e.g.) - void stop(); - bool isAssumingPrimary_inlock(); - - static BackgroundSync* get(); - void shutdown(); - void notify(); - - virtual ~BackgroundSync() {} - - // starts the producer thread - void producerThread(); - // starts the sync target notifying thread - void notifierThread(); - - HostAndPort getSyncTarget(); - - // Interface implementation - - virtual bool peek(BSONObj* op); - virtual void consume(); - virtual void clearSyncTarget(); - virtual void waitForMore(); - - // For monitoring - BSONObj getCounters(); - - // Wait for replication to finish and buffer to be applied so that the member can become - // primary. - void stopReplicationAndFlushBuffer(); - - long long getLastAppliedHash() const; - void setLastAppliedHash(long long oldH); - void loadLastAppliedHash(OperationContext* txn); + // This setting affects the Applier prefetcher behavior. + IndexPrefetchConfig _indexPrefetchConfig; - bool getInitialSyncRequestedFlag(); - void setInitialSyncRequestedFlag(bool value); }; diff --git a/src/mongo/db/repl/repl_set_impl.cpp b/src/mongo/db/repl/repl_set_impl.cpp index 186df3c2ce7..86e880151ef 100644 --- a/src/mongo/db/repl/repl_set_impl.cpp +++ b/src/mongo/db/repl/repl_set_impl.cpp @@ -379,21 +379,6 @@ namespace { << " is not present in the current repl set config" << rsLog; } } - - // Figure out indexPrefetch setting - std::string& prefetch = getGlobalReplicationCoordinator()->getSettings().rsIndexPrefetch; - if (!prefetch.empty()) { - IndexPrefetchConfig prefetchConfig = PREFETCH_ALL; - if (prefetch == "none") - prefetchConfig = PREFETCH_NONE; - else if (prefetch == "_id_only") - prefetchConfig = PREFETCH_ID_ONLY; - else if (prefetch == "all") - prefetchConfig = PREFETCH_ALL; - else - warning() << "unrecognized indexPrefetch setting: " << prefetch << endl; - setIndexPrefetchConfig(prefetchConfig); - } } ReplSetImpl::ReplSetImpl() : @@ -402,8 +387,7 @@ namespace { _hbmsgTime(0), _self(0), _maintenanceMode(0), - mgr(0), - _indexPrefetchConfig(PREFETCH_ALL) { + mgr(0) { } void ReplSetImpl::loadLastOpTimeWritten(OperationContext* txn, bool quiet) { diff --git a/src/mongo/db/repl/repl_set_impl.h b/src/mongo/db/repl/repl_set_impl.h index 75fc8ca56e4..79c909c194e 100644 --- a/src/mongo/db/repl/repl_set_impl.h +++ b/src/mongo/db/repl/repl_set_impl.h @@ -281,18 +281,6 @@ namespace repl { // keep a list of hosts that we've tried recently that didn't work map<string,time_t> _veto; - // Allow index prefetching to be turned on/off - enum IndexPrefetchConfig { - PREFETCH_NONE=0, PREFETCH_ID_ONLY=1, PREFETCH_ALL=2 - }; - - void setIndexPrefetchConfig(const IndexPrefetchConfig cfg) { - _indexPrefetchConfig = cfg; - } - IndexPrefetchConfig getIndexPrefetchConfig() { - return _indexPrefetchConfig; - } - const ReplSetConfig::MemberCfg& myConfig() const { return _config; } const OpTime lastOtherOpTime() const; /** @@ -301,8 +289,6 @@ namespace repl { const OpTime lastOtherElectableOpTime() const; BSONObj getLastErrorDefault; - private: - IndexPrefetchConfig _indexPrefetchConfig; }; } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/rs.cpp b/src/mongo/db/repl/rs.cpp index 026814ee39e..7644e5c9ae9 100644 --- a/src/mongo/db/repl/rs.cpp +++ b/src/mongo/db/repl/rs.cpp @@ -139,64 +139,5 @@ namespace repl { cc().getAuthorizationSession()->grantInternalAuthorization(); } - class ReplIndexPrefetch : public ServerParameter { - public: - ReplIndexPrefetch() - : ServerParameter( ServerParameterSet::getGlobal(), "replIndexPrefetch" ) { - } - - virtual ~ReplIndexPrefetch() { - } - - const char * _value() { - if (!theReplSet) - return "uninitialized"; - ReplSetImpl::IndexPrefetchConfig ip = theReplSet->getIndexPrefetchConfig(); - switch (ip) { - case ReplSetImpl::PREFETCH_NONE: - return "none"; - case ReplSetImpl::PREFETCH_ID_ONLY: - return "_id_only"; - case ReplSetImpl::PREFETCH_ALL: - return "all"; - default: - return "invalid"; - } - } - - virtual void append(OperationContext* txn, BSONObjBuilder& b, const string& name) { - b.append( name, _value() ); - } - - virtual Status set( const BSONElement& newValueElement ) { - if (!theReplSet) { - return Status( ErrorCodes::BadValue, "replication is not enabled" ); - } - - std::string prefetch = newValueElement.valuestrsafe(); - return setFromString( prefetch ); - } - - virtual Status setFromString( const string& prefetch ) { - log() << "changing replication index prefetch behavior to " << prefetch << endl; - - ReplSetImpl::IndexPrefetchConfig prefetchConfig; - - if (prefetch == "none") - prefetchConfig = ReplSetImpl::PREFETCH_NONE; - else if (prefetch == "_id_only") - prefetchConfig = ReplSetImpl::PREFETCH_ID_ONLY; - else if (prefetch == "all") - prefetchConfig = ReplSetImpl::PREFETCH_ALL; - else { - return Status( ErrorCodes::BadValue, - str::stream() << "unrecognized indexPrefetch setting: " << prefetch ); - } - - theReplSet->setIndexPrefetchConfig(prefetchConfig); - return Status::OK(); - } - - } replIndexPrefetch; } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/rs_sync.cpp b/src/mongo/db/repl/rs_sync.cpp index d670de456c9..ad47956aa91 100644 --- a/src/mongo/db/repl/rs_sync.cpp +++ b/src/mongo/db/repl/rs_sync.cpp @@ -41,7 +41,6 @@ #include "mongo/db/curop.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/prefetch.h" #include "mongo/db/repl/bgsync.h" #include "mongo/db/repl/member.h" #include "mongo/db/repl/minvalid.h" @@ -159,6 +158,24 @@ namespace repl { Client::initThread("rsSync"); replLocalAuth(); ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator(); + + // Set initial indexPrefetch setting + std::string& prefetch = replCoord->getSettings().rsIndexPrefetch; + if (!prefetch.empty()) { + BackgroundSync::IndexPrefetchConfig prefetchConfig = BackgroundSync::PREFETCH_ALL; + if (prefetch == "none") + prefetchConfig = BackgroundSync::PREFETCH_NONE; + else if (prefetch == "_id_only") + prefetchConfig = BackgroundSync::PREFETCH_ID_ONLY; + else if (prefetch == "all") + prefetchConfig = BackgroundSync::PREFETCH_ALL; + else { + warning() << "unrecognized indexPrefetch setting " << prefetch << ", defaulting " + << "to \"all\""; + } + BackgroundSync::get()->setIndexPrefetchConfig(prefetchConfig); + } + while (!inShutdown()) { // After a reconfig, we may not be in the replica set anymore, so // check that we are in the set (and not an arbiter) before diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index 7de91643586..fceafc04b6e 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -150,7 +150,6 @@ namespace repl { Client::ReadContext ctx(&txn, ns); prefetchPagesForReplicatedOp(&txn, ctx.ctx().db(), - theReplSet->getIndexPrefetchConfig(), op); } catch (const DBException& e) { |