2
* Copyright (C) 2012 10gen Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Affero General Public License, version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Affero General Public License for more details.
13
* You should have received a copy of the GNU Affero General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
#include "mongo/db/index_rebuilder.h"
19
#include "mongo/db/instance.h"
20
#include "mongo/db/pdfile.h"
21
#include "mongo/util/scopeguard.h"
25
// Disabled until locking at startup can be ironed out.
26
// See SERVER-8344 and SERVER-8536
27
//IndexRebuilder indexRebuilder;
29
IndexRebuilder::IndexRebuilder() {}
32
* This resets memory tracking to its original value after all indexes are rebuilt.
34
* Before the server starts listening, all memory accesses are counted as taking 0 time (because
35
* the timer hasn't started yet). The Record class warns about these 0-time accesses (actually,
36
* the warning is in Rolling, which is used by Record) so run() turns off the tracking to
37
* silence these warnings. We want to make sure that they're turned back on, though, no matter
40
static void resetMemoryTracking(bool originalTracking) {
41
Record::MemoryTrackingEnabled = originalTracking;
44
void IndexRebuilder::run() {
45
// Disable record access timer warnings
46
ON_BLOCK_EXIT(resetMemoryTracking, Record::MemoryTrackingEnabled);
47
Record::MemoryTrackingEnabled = false;
52
bool firstTime = true;
53
std::vector<std::string> dbNames;
54
getDatabaseNames(dbNames);
56
for (std::vector<std::string>::const_iterator it = dbNames.begin();
59
checkDB(*it, &firstTime);
65
void IndexRebuilder::checkDB(const std::string& dbName, bool* firstTime) {
66
const std::string systemNS = dbName + ".system.namespaces";
68
scoped_ptr<DBClientCursor> cursor(cli.query(systemNS, Query()));
70
// This depends on system.namespaces not changing while we iterate
71
while (cursor->more()) {
72
BSONObj nsDoc = cursor->next();
73
const char* ns = nsDoc["name"].valuestrsafe();
75
Client::WriteContext ctx(ns);
76
NamespaceDetails* nsd = nsdetails(ns);
78
if (!nsd || !nsd->indexBuildsInProgress) {
82
log() << "Found interrupted index build on " << ns << endl;
84
log() << "Restart the server with --noIndexBuildRetry to skip index rebuilds"
89
// If the indexBuildRetry flag isn't set, just clear the inProg flag
90
if (!cmdLine.indexBuildRetry) {
91
// If we crash between unsetting the inProg flag and cleaning up the index, the
92
// index space will be lost.
93
int inProg = nsd->indexBuildsInProgress;
94
getDur().writingInt(nsd->indexBuildsInProgress) = 0;
96
for (int i = 0; i < inProg; i++) {
97
nsd->idx(nsd->nIndexes+i).kill_idx();
103
// We go from right to left building these indexes, so that indexBuildInProgress-- has
104
// the correct effect of "popping" an index off the list.
105
while (nsd->indexBuildsInProgress > 0) {
106
retryIndexBuild(dbName, nsd, nsd->nIndexes+nsd->indexBuildsInProgress-1);
111
void IndexRebuilder::retryIndexBuild(const std::string& dbName,
112
NamespaceDetails* nsd,
114
// details.info is always a valid system.indexes entry because DataFileMgr::insert journals
115
// creating the index doc and then insert_makeIndex durably assigns its DiskLoc to info.
116
// indexBuildsInProgress is set after that, so if it is set, info must be set.
117
IndexDetails& details = nsd->idx(index);
119
// First, clean up the in progress index build. Save the system.indexes entry so that we
120
// can add it again afterwards.
121
BSONObj indexObj = details.info.obj().getOwned();
123
// Clean up the in-progress index build
124
getDur().writingInt(nsd->indexBuildsInProgress) -= 1;
126
// The index has now been removed from system.indexes, so the only record of it is in-
127
// memory. If there is a journal commit between now and when insert() rewrites the entry and
128
// the db crashes before the new system.indexes entry is journalled, the index will be lost
129
// forever. Thus, we're assuming no journaling will happen between now and the entry being
132
// We need to force a foreground index build to prevent replication from replaying an
133
// incompatible op (like a drop) during a yield.
134
// TODO: once commands can interrupt/wait for index builds, this can be removed.
135
indexObj = indexObj.removeField("background");
138
const std::string ns = dbName + ".system.indexes";
139
theDataFileMgr.insert(ns.c_str(), indexObj.objdata(), indexObj.objsize(), false, true);
141
catch (const DBException& e) {
142
log() << "Rebuilding index failed: " << e.what() << " (" << e.getCode() << ")"