summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/index_create.h
blob: d3dccb20b46005ceaa362aa676d080c43d4f3e39 (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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// index_create.h

/**
*    Copyright (C) 2008 10gen Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    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
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*    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 GNU Affero General 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 <memory>
#include <set>
#include <string>
#include <vector>

#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/record_id.h"

namespace mongo {

class BackgroundOperation;
class BSONObj;
class Collection;
class OperationContext;

/**
 * Builds one or more indexes.
 *
 * If any method other than insert() returns a not-ok Status, this MultiIndexBlock should be
 * considered failed and must be destroyed.
 *
 * If a MultiIndexBlock is destroyed before commit() or if commit() is rolled back, it will
 * clean up all traces of the indexes being constructed. MultiIndexBlocks should not be
 * destructed from inside of a WriteUnitOfWork as any cleanup needed should never be rolled back
 * (as it is itself essentially a form of rollback, you don't want to "rollback the rollback").
 */
class MultiIndexBlock {
    MONGO_DISALLOW_COPYING(MultiIndexBlock);

public:
    /**
     * Neither pointer is owned.
     */
    MultiIndexBlock(OperationContext* txn, Collection* collection);
    ~MultiIndexBlock();

    /**
     * By default we ignore the 'background' flag in specs when building an index. If this is
     * called before init(), we will build the indexes in the background as long as *all* specs
     * call for background indexing. If any spec calls for foreground indexing all indexes will
     * be built in the foreground, as there is no concurrency benefit to building a subset of
     * indexes in the background, but there is a performance benefit to building all in the
     * foreground.
     */
    void allowBackgroundBuilding() {
        _buildInBackground = true;
    }

    /**
     * Call this before init() to allow the index build to be interrupted.
     * This only affects builds using the insertAllDocumentsInCollection helper.
     */
    void allowInterruption() {
        _allowInterruption = true;
    }

    /**
     * By default we enforce the 'unique' flag in specs when building an index by failing.
     * If this is called before init(), we will ignore unique violations. This has no effect if
     * no specs are unique.
     *
     * If this is called, any dupsOut sets passed in will never be filled.
     */
    void ignoreUniqueConstraint() {
        _ignoreUnique = true;
    }

    /**
     * Removes pre-existing indexes from 'specs'. If this isn't done, init() may fail with
     * IndexAlreadyExists.
     */
    void removeExistingIndexes(std::vector<BSONObj>* specs) const;

    /**
     * Prepares the index(es) for building.
     *
     * Does not need to be called inside of a WriteUnitOfWork (but can be due to nesting).
     *
     * Requires holding an exclusive database lock.
     */
    Status init(const std::vector<BSONObj>& specs);
    Status init(const BSONObj& spec) {
        return init(std::vector<BSONObj>(1, spec));
    }

    /**
     * Inserts all documents in the Collection into the indexes and logs with timing info.
     *
     * This is a simplified replacement for insert and doneInserting. Do not call this if you
     * are calling either of them.
     *
     * If dupsOut is passed as non-NULL, violators of uniqueness constraints will be added to
     * the set rather than failing the build. Documents added to this set are not indexed, so
     * callers MUST either fail this index build or delete the documents from the collection.
     *
     * Can throw an exception if interrupted.
     *
     * Should not be called inside of a WriteUnitOfWork.
     */
    Status insertAllDocumentsInCollection(std::set<RecordId>* dupsOut = NULL);

    /**
     * Call this after init() for each document in the collection.
     *
     * Do not call if you called insertAllDocumentsInCollection();
     *
     * Should be called inside of a WriteUnitOfWork.
     */
    Status insert(const BSONObj& wholeDocument, const RecordId& loc);

    /**
     * Call this after the last insert(). This gives the index builder a chance to do any
     * long-running operations in separate units of work from commit().
     *
     * Do not call if you called insertAllDocumentsInCollection();
     *
     * If dupsOut is passed as non-NULL, violators of uniqueness constraints will be added to
     * the set. Documents added to this set are not indexed, so callers MUST either fail this
     * index build or delete the documents from the collection.
     *
     * Should not be called inside of a WriteUnitOfWork.
     */
    Status doneInserting(std::set<RecordId>* dupsOut = NULL);

    /**
     * Marks the index ready for use. Should only be called as the last method after
     * doneInserting() or insertAllDocumentsInCollection() return success.
     *
     * Should be called inside of a WriteUnitOfWork. If the index building is to be logOp'd,
     * logOp() should be called from the same unit of work as commit().
     *
     * Requires holding an exclusive database lock.
     */
    void commit();

    /**
     * May be called at any time after construction but before a successful commit(). Suppresses
     * the default behavior on destruction of removing all traces of uncommitted index builds.
     *
     * The most common use of this is if the indexes were already dropped via some other
     * mechanism such as the whole collection being dropped. In that case, it would be invalid
     * to try to remove the indexes again. Also, replication uses this to ensure that indexes
     * that are being built on shutdown are resumed on startup.
     *
     * Do not use this unless you are really sure you need to.
     *
     * Does not matter whether it is called inside of a WriteUnitOfWork. Will not be rolled
     * back.
     */
    void abortWithoutCleanup();

    bool getBuildInBackground() const {
        return _buildInBackground;
    }

private:
    class SetNeedToCleanupOnRollback;
    class CleanupIndexesVectorOnRollback;

    struct IndexToBuild {
#if defined(_MSC_VER) && _MSC_VER < 1900  // MVSC++ <= 2013 can't generate default move operations
        IndexToBuild() = default;
        IndexToBuild(IndexToBuild&& other)
            : block(std::move(other.block)),
              real(std::move(other.real)),
              bulk(std::move(other.bulk)),
              options(std::move(other.options)),
              filterExpression(std::move(other.filterExpression)) {}

        IndexToBuild& operator=(IndexToBuild&& other) {
            block = std::move(other.block);
            real = std::move(other.real);
            filterExpression = std::move(other.filterExpression);
            bulk = std::move(other.bulk);
            options = std::move(other.options);
            return *this;
        }
#endif

        std::unique_ptr<IndexCatalog::IndexBuildBlock> block;

        IndexAccessMethod* real = NULL;           // owned elsewhere
        const MatchExpression* filterExpression;  // might be NULL, owned elsewhere
        std::unique_ptr<IndexAccessMethod::BulkBuilder> bulk;

        InsertDeleteOptions options;
    };

    std::vector<IndexToBuild> _indexes;

    std::unique_ptr<BackgroundOperation> _backgroundOperation;

    // Pointers not owned here and must outlive 'this'
    Collection* _collection;
    OperationContext* _txn;

    bool _buildInBackground;
    bool _allowInterruption;
    bool _ignoreUnique;

    bool _needToCleanup;
};

}  // namespace mongo