summaryrefslogtreecommitdiff
path: root/src/mongo/db/transaction/transaction_operations.h
blob: 4cfa0ffd55a94bf05fc3ffadefb4acf774517dbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/**
 *    Copyright (C) 2022-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
 *    <http://www.mongodb.com/licensing/server-side-public-license>.
 *
 *    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 <boost/optional.hpp>
#include <cstddef>
#include <vector>

#include "mongo/base/status.h"
#include "mongo/db/repl/oplog.h"        // for OplogSlot
#include "mongo/db/repl/oplog_entry.h"  // for ReplOperation
#include "mongo/stdx/unordered_set.h"
#include "mongo/util/uuid.h"

namespace mongo {

/**
 * Container for ReplOperation used in multi-doc transactions and batched writer context.
 * Includes statistics on operations held in this container.
 * Provides methods for exporting ReplOperations in one or more applyOps oplog entries.
 * Concurrency control for this class is maintained by the TransactionParticipant.
 */
class TransactionOperations {
public:
    using TransactionOperation = repl::ReplOperation;
    using CollectionUUIDs = stdx::unordered_set<UUID, UUID::Hash>;

    /**
     * Contains "applyOps" oplog entries for a transaction. "applyOps" entries are not actual
     * "applyOps" entries to be written to the oplog, but comprise certain parts of those entries -
     * BSON serialized operations, and the assigned oplog slot. The operations in field
     * 'ApplyOpsEntry::operations' should be considered opaque outside the OpObserver.
     */
    struct ApplyOpsInfo {
        // Conservative BSON array element overhead assuming maximum 6 digit array index.
        static constexpr std::size_t kBSONArrayElementOverhead = 8U;

        struct ApplyOpsEntry {
            OplogSlot oplogSlot;
            std::vector<BSONObj> operations;
        };

        // Representation of "applyOps" oplog entries.
        std::vector<ApplyOpsEntry> applyOpsEntries;

        // Number of oplog slots utilized.
        std::size_t numberOfOplogSlotsUsed;
    };

    /**
     * Accepts an empty BSON builder and appends the given transaction statements to an 'applyOps'
     * array field (and their corresponding statement ids to 'stmtIdsWritten'). The transaction
     * statements are represented as range ['stmtBegin', 'stmtEnd') and BSON serialized objects
     * 'operations'. If any of the statements has a pre-image or post-image that needs to be
     * stored in the image collection, stores it to 'imageToWrite'.
     *
     * Used to implement logOplogEntries().
     */
    static void packTransactionStatementsForApplyOps(
        std::vector<TransactionOperation>::const_iterator stmtBegin,
        std::vector<TransactionOperation>::const_iterator stmtEnd,
        const std::vector<BSONObj>& operations,
        BSONObjBuilder* applyOpsBuilder,
        std::vector<StmtId>* stmtIdsWritten,
        boost::optional<repl::ReplOperation::ImageBundle>* imageToWrite);

    TransactionOperations() = default;

    /**
     * Returns true if '_transactionsOperations' is empty.
     */
    bool isEmpty() const;

    /**
     * Returns number of items in '_transactionOperations'.
     */
    std::size_t numOperations() const;

    /**
     * Total size in bytes of all operations within the _transactionOperations vector.
     * See DurableOplogEntry::getDurableReplOperationSize().
     */
    std::size_t getTotalOperationBytes() const;

    /**
     * Returns number of operations that have pre-images or post-images to be written to
     * noop oplog entries or the image collection.
     */
    std::size_t getNumberOfPrePostImagesToWrite() const;

    /**
     * Clears the operations stored in this container along with corresponding statistics.
     */
    void clear();

    /**
     * Adds an operation to this container and updates relevant statistics.
     *
     * Ensures that statement ids in operation do not conflict with the operations
     * already added.
     *
     * Ensures that total size of collected operations after adding operation does not
     * exceed 'transactionSizeLimitBytes' (if provided).
     */
    Status addOperation(const TransactionOperation& operation,
                        boost::optional<std::size_t> transactionSizeLimitBytes = boost::none);

    /**
     * Returns a set of collection UUIDs for the operations stored in this container.
     *
     * This allows the caller to check which collections will be modified as a resulting of
     * executing this transaction. The set of UUIDs returned by this function does not include
     * collection UUIDs for no-op operations, e.g. {op: 'n', ...}.
     */
    CollectionUUIDs getCollectionUUIDs() const;

    /**
     * Returns oplog slots to be used for "applyOps" oplog entries, BSON serialized operations,
     * their assignments to "applyOps" entries, and oplog slots to be used for writing pre- and
     * post- image oplog entries for the transaction consisting of 'operations'. Allocates oplog
     * slots from 'oplogSlots'. The 'prepare' indicates if the function is called when preparing a
     * transaction.
     */
    ApplyOpsInfo getApplyOpsInfo(const std::vector<OplogSlot>& oplogSlots,
                                 std::size_t oplogEntryCountLimit,
                                 std::size_t oplogEntrySizeLimitBytes,
                                 bool prepare) const;

    /**
     * Returns pointer to vector of operations for integrating with
     * BatchedWriteContext, TransactionParticipant, and OpObserver interfaces
     * for multi-doc transactions.
     *
     * Caller assumes responsibility for keeping contents referenced by the pointer
     * in sync with statistics maintained in this container.
     *
     * This function can be removed when we have migrated callers of BatchedWriteContext
     * and TransactionParticipant to use the methods on this class directly.
     */
    std::vector<TransactionOperation>* getMutableOperationsForOpObserver();

    /**
     * Returns copy of operations for TransactionParticipant testing.
     */
    std::vector<TransactionOperation> getOperationsForTest() const;

private:
    std::vector<TransactionOperation> _transactionOperations;

    // Holds stmtIds for operations which have been applied in the current multi-document
    // transaction.
    stdx::unordered_set<StmtId> _transactionStmtIds;

    // Size of operations in _transactionOperations as calculated by
    // DurableOplogEntry::getDurableReplOperationSize().
    std::size_t _totalOperationBytes{0};

    // Number of operations that have pre-images or post-images to be written to noop oplog
    // entries or the image collection.
    std::size_t _numberOfPrePostImagesToWrite{0};
};

}  // namespace mongo