/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * 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 * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * 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 Server Side 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 #include "mongo/db/ops/write_ops.h" #include "mongo/rpc/op_msg.h" #include "mongo/s/chunk_version.h" #include "mongo/stdx/memory.h" namespace mongo { /** * This class wraps the different kinds of command requests into a generically usable write command * request that can be passed around. */ class BatchedCommandRequest { public: enum BatchType { BatchType_Insert, BatchType_Update, BatchType_Delete }; BatchedCommandRequest(write_ops::Insert insertOp) : _batchType(BatchType_Insert), _insertReq(stdx::make_unique(std::move(insertOp))) {} BatchedCommandRequest(write_ops::Update updateOp) : _batchType(BatchType_Update), _updateReq(stdx::make_unique(std::move(updateOp))) {} BatchedCommandRequest(write_ops::Delete deleteOp) : _batchType(BatchType_Delete), _deleteReq(stdx::make_unique(std::move(deleteOp))) {} BatchedCommandRequest(BatchedCommandRequest&&) = default; static BatchedCommandRequest parseInsert(const OpMsgRequest& request); static BatchedCommandRequest parseUpdate(const OpMsgRequest& request); static BatchedCommandRequest parseDelete(const OpMsgRequest& request); BatchType getBatchType() const { return _batchType; } const NamespaceString& getNS() const; const auto& getInsertRequest() const { invariant(_insertReq); return *_insertReq; } const auto& getUpdateRequest() const { invariant(_updateReq); return *_updateReq; } const auto& getDeleteRequest() const { invariant(_deleteReq); return *_deleteReq; } std::size_t sizeWriteOps() const; void setWriteConcern(const BSONObj& writeConcern) { _writeConcern = writeConcern.getOwned(); } bool hasWriteConcern() const { return _writeConcern.is_initialized(); } const BSONObj& getWriteConcern() const { invariant(_writeConcern); return *_writeConcern; } bool isVerboseWC() const; void setShardVersion(ChunkVersion shardVersion) { _shardVersion = std::move(shardVersion); } bool hasShardVersion() const { return _shardVersion.is_initialized(); } const ChunkVersion& getShardVersion() const { invariant(_shardVersion); return *_shardVersion; } const write_ops::WriteCommandBase& getWriteCommandBase() const; void setWriteCommandBase(write_ops::WriteCommandBase writeCommandBase); void serialize(BSONObjBuilder* builder) const; BSONObj toBSON() const; std::string toString() const; void setAllowImplicitCreate(bool doAllow) { _allowImplicitCollectionCreation = doAllow; } bool isImplicitCreateAllowed() const { return _allowImplicitCollectionCreation; } /** * Generates a new request, the same as the old, but with insert _ids if required. */ static BatchedCommandRequest cloneInsertWithIds(BatchedCommandRequest origCmdRequest); private: template static decltype(auto) _visitImpl(Req&& r, F&& f, As&&... as) { switch (r._batchType) { case BatchedCommandRequest::BatchType_Insert: return std::forward(f)(*r._insertReq, std::forward(as)...); case BatchedCommandRequest::BatchType_Update: return std::forward(f)(*r._updateReq, std::forward(as)...); case BatchedCommandRequest::BatchType_Delete: return std::forward(f)(*r._deleteReq, std::forward(as)...); } MONGO_UNREACHABLE; } template decltype(auto) _visit(As&&... as) { return _visitImpl(*this, std::forward(as)...); } template decltype(auto) _visit(As&&... as) const { return _visitImpl(*this, std::forward(as)...); } BatchType _batchType; std::unique_ptr _insertReq; std::unique_ptr _updateReq; std::unique_ptr _deleteReq; boost::optional _shardVersion; boost::optional _writeConcern; bool _allowImplicitCollectionCreation = true; }; /** * Similar to above, this class wraps the write items of a command request into a generically * usable type. Very thin wrapper, does not own the write item itself. * * TODO: Use in BatchedCommandRequest above */ class BatchItemRef { public: BatchItemRef(const BatchedCommandRequest* request, int itemIndex) : _request(request), _itemIndex(itemIndex) {} const BatchedCommandRequest* getRequest() const { return _request; } int getItemIndex() const { return _itemIndex; } BatchedCommandRequest::BatchType getOpType() const { return _request->getBatchType(); } const auto& getDocument() const { dassert(_itemIndex < static_cast(_request->sizeWriteOps())); return _request->getInsertRequest().getDocuments().at(_itemIndex); } const auto& getUpdate() const { dassert(_itemIndex < static_cast(_request->sizeWriteOps())); return _request->getUpdateRequest().getUpdates().at(_itemIndex); } const auto& getDelete() const { dassert(_itemIndex < static_cast(_request->sizeWriteOps())); return _request->getDeleteRequest().getDeletes().at(_itemIndex); } private: const BatchedCommandRequest* _request; const int _itemIndex; }; } // namespace mongo