1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding
32 
33 #include "mongo/platform/basic.h"
34 
35 #include "mongo/db/s/sharded_connection_info.h"
36 
37 #include <boost/optional.hpp>
38 #include <boost/utility/in_place_factory.hpp>
39 
40 #include "mongo/client/global_conn_pool.h"
41 #include "mongo/db/client.h"
42 #include "mongo/db/logical_time_metadata_hook.h"
43 #include "mongo/db/operation_context.h"
44 #include "mongo/db/s/sharding_egress_metadata_hook_for_mongod.h"
45 #include "mongo/db/service_context.h"
46 #include "mongo/platform/atomic_word.h"
47 #include "mongo/rpc/metadata/egress_metadata_hook_list.h"
48 #include "mongo/s/chunk_version.h"
49 #include "mongo/s/client/shard_connection.h"
50 #include "mongo/s/client/sharding_connection_hook.h"
51 #include "mongo/stdx/memory.h"
52 #include "mongo/util/log.h"
53 
54 namespace mongo {
55 namespace {
56 
57 const auto clientSCI = Client::declareDecoration<boost::optional<ShardedConnectionInfo>>();
58 
59 stdx::mutex addHookMutex;
60 
61 AtomicUInt32 alreadyAddedHook{0};
62 
63 }  // namespace
64 
ShardedConnectionInfo()65 ShardedConnectionInfo::ShardedConnectionInfo() {
66     _forceVersionOk = false;
67 }
68 
69 ShardedConnectionInfo::~ShardedConnectionInfo() = default;
70 
get(Client * client,bool create)71 ShardedConnectionInfo* ShardedConnectionInfo::get(Client* client, bool create) {
72     auto& current = clientSCI(client);
73 
74     if (!current && create) {
75         LOG(1) << "entering shard mode for connection";
76         current = boost::in_place();
77     }
78 
79     return current ? &current.value() : nullptr;
80 }
81 
reset(Client * client)82 void ShardedConnectionInfo::reset(Client* client) {
83     clientSCI(client) = boost::none;
84 }
85 
getVersion(const std::string & ns) const86 ChunkVersion ShardedConnectionInfo::getVersion(const std::string& ns) const {
87     NSVersionMap::const_iterator it = _versions.find(ns);
88     if (it != _versions.end()) {
89         return it->second;
90     } else {
91         return ChunkVersion::UNSHARDED();
92     }
93 }
94 
setVersion(const std::string & ns,const ChunkVersion & version)95 void ShardedConnectionInfo::setVersion(const std::string& ns, const ChunkVersion& version) {
96     _versions[ns] = version;
97 }
98 
addHook(ServiceContext * service)99 void ShardedConnectionInfo::addHook(ServiceContext* service) {
100     if (alreadyAddedHook.loadRelaxed()) {
101         return;
102     }
103 
104     stdx::lock_guard<stdx::mutex> lk{addHookMutex};
105     if (alreadyAddedHook.load()) {
106         return;
107     }
108 
109     log() << "first cluster operation detected, adding sharding hook to enable versioning "
110              "and authentication to remote servers";
111 
112     {
113         auto unshardedHookList = stdx::make_unique<rpc::EgressMetadataHookList>();
114         unshardedHookList->addHook(stdx::make_unique<rpc::LogicalTimeMetadataHook>(service));
115         unshardedHookList->addHook(
116             stdx::make_unique<rpc::ShardingEgressMetadataHookForMongod>(service));
117 
118         globalConnPool.addHook(new ShardingConnectionHook(false, std::move(unshardedHookList)));
119     }
120 
121     {
122         auto shardedHookList = stdx::make_unique<rpc::EgressMetadataHookList>();
123         shardedHookList->addHook(stdx::make_unique<rpc::LogicalTimeMetadataHook>(service));
124         shardedHookList->addHook(
125             stdx::make_unique<rpc::ShardingEgressMetadataHookForMongod>(service));
126 
127         shardConnectionPool.addHook(new ShardingConnectionHook(true, std::move(shardedHookList)));
128     }
129 
130     alreadyAddedHook.store(1);
131 }
132 
133 }  // namespace mongo
134