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 #pragma once
32 
33 #include <boost/optional.hpp>
34 
35 #include "mongo/db/ops/write_ops.h"
36 #include "mongo/s/chunk_version.h"
37 #include "mongo/stdx/memory.h"
38 #include "mongo/util/net/op_msg.h"
39 
40 namespace mongo {
41 
42 /**
43  * This class wraps the different kinds of command requests into a generically usable write command
44  * request that can be passed around.
45  */
46 class BatchedCommandRequest {
47 public:
48     enum BatchType { BatchType_Insert, BatchType_Update, BatchType_Delete };
49 
BatchedCommandRequest(write_ops::Insert insertOp)50     BatchedCommandRequest(write_ops::Insert insertOp)
51         : _batchType(BatchType_Insert),
52           _insertReq(stdx::make_unique<write_ops::Insert>(std::move(insertOp))) {}
53 
BatchedCommandRequest(write_ops::Update updateOp)54     BatchedCommandRequest(write_ops::Update updateOp)
55         : _batchType(BatchType_Update),
56           _updateReq(stdx::make_unique<write_ops::Update>(std::move(updateOp))) {}
57 
BatchedCommandRequest(write_ops::Delete deleteOp)58     BatchedCommandRequest(write_ops::Delete deleteOp)
59         : _batchType(BatchType_Delete),
60           _deleteReq(stdx::make_unique<write_ops::Delete>(std::move(deleteOp))) {}
61 
62     BatchedCommandRequest(BatchedCommandRequest&&) = default;
63 
64     static BatchedCommandRequest parseInsert(const OpMsgRequest& request);
65     static BatchedCommandRequest parseUpdate(const OpMsgRequest& request);
66     static BatchedCommandRequest parseDelete(const OpMsgRequest& request);
67 
getBatchType()68     BatchType getBatchType() const {
69         return _batchType;
70     }
71 
72     const NamespaceString& getNS() const;
73     NamespaceString getTargetingNS() const;
74 
75     /**
76      * Index creation can be expressed as an insert into the 'system.indexes' namespace.
77      */
78     bool isInsertIndexRequest() const;
79 
getInsertRequest()80     const auto& getInsertRequest() const {
81         invariant(_insertReq);
82         return *_insertReq;
83     }
84 
getUpdateRequest()85     const auto& getUpdateRequest() const {
86         invariant(_updateReq);
87         return *_updateReq;
88     }
89 
getDeleteRequest()90     const auto& getDeleteRequest() const {
91         invariant(_deleteReq);
92         return *_deleteReq;
93     }
94 
95     std::size_t sizeWriteOps() const;
96 
setWriteConcern(const BSONObj & writeConcern)97     void setWriteConcern(const BSONObj& writeConcern) {
98         _writeConcern = writeConcern.getOwned();
99     }
100 
hasWriteConcern()101     bool hasWriteConcern() const {
102         return _writeConcern.is_initialized();
103     }
104 
getWriteConcern()105     const BSONObj& getWriteConcern() const {
106         invariant(_writeConcern);
107         return *_writeConcern;
108     }
109 
110     bool isVerboseWC() const;
111 
setShardVersion(ChunkVersion shardVersion)112     void setShardVersion(ChunkVersion shardVersion) {
113         _shardVersion = std::move(shardVersion);
114     }
115 
hasShardVersion()116     bool hasShardVersion() const {
117         return _shardVersion.is_initialized();
118     }
119 
getShardVersion()120     const ChunkVersion& getShardVersion() const {
121         invariant(_shardVersion);
122         return *_shardVersion;
123     }
124 
125     const write_ops::WriteCommandBase& getWriteCommandBase() const;
126     void setWriteCommandBase(write_ops::WriteCommandBase writeCommandBase);
127 
128     void serialize(BSONObjBuilder* builder) const;
129     BSONObj toBSON() const;
130     std::string toString() const;
131 
132     /**
133      * Generates a new request, the same as the old, but with insert _ids if required.
134      */
135     static BatchedCommandRequest cloneInsertWithIds(BatchedCommandRequest origCmdRequest);
136 
137 private:
138     BatchType _batchType;
139 
140     std::unique_ptr<write_ops::Insert> _insertReq;
141     std::unique_ptr<write_ops::Update> _updateReq;
142     std::unique_ptr<write_ops::Delete> _deleteReq;
143 
144     boost::optional<ChunkVersion> _shardVersion;
145 
146     boost::optional<BSONObj> _writeConcern;
147 };
148 
149 /**
150  * Similar to above, this class wraps the write items of a command request into a generically
151  * usable type.  Very thin wrapper, does not own the write item itself.
152  *
153  * TODO: Use in BatchedCommandRequest above
154  */
155 class BatchItemRef {
156 public:
BatchItemRef(const BatchedCommandRequest * request,int itemIndex)157     BatchItemRef(const BatchedCommandRequest* request, int itemIndex)
158         : _request(request), _itemIndex(itemIndex) {}
159 
getRequest()160     const BatchedCommandRequest* getRequest() const {
161         return _request;
162     }
163 
getItemIndex()164     int getItemIndex() const {
165         return _itemIndex;
166     }
167 
getOpType()168     BatchedCommandRequest::BatchType getOpType() const {
169         return _request->getBatchType();
170     }
171 
getDocument()172     const auto& getDocument() const {
173         dassert(_itemIndex < static_cast<int>(_request->sizeWriteOps()));
174         return _request->getInsertRequest().getDocuments().at(_itemIndex);
175     }
176 
getUpdate()177     const auto& getUpdate() const {
178         dassert(_itemIndex < static_cast<int>(_request->sizeWriteOps()));
179         return _request->getUpdateRequest().getUpdates().at(_itemIndex);
180     }
181 
getDelete()182     const auto& getDelete() const {
183         dassert(_itemIndex < static_cast<int>(_request->sizeWriteOps()));
184         return _request->getDeleteRequest().getDeletes().at(_itemIndex);
185     }
186 
187 private:
188     const BatchedCommandRequest* _request;
189     const int _itemIndex;
190 };
191 
192 }  // namespace mongo
193