summaryrefslogtreecommitdiff
path: root/db/repl.h
blob: 635265b6e5fc3d5efd37fd229759a3a0abaa5318 (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
// repl.h - replication

/**
*    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/>.
*/

/* replication data overview

   at the slave:
     local.sources { host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: ..., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }

   at the master:
     local.oplog.$<source>
*/

#pragma once

#include "pdfile.h"
#include "db.h"
#include "dbhelpers.h"
#include "../client/dbclient.h"
#include "../util/optime.h"
#include "oplog.h"
#include "../util/concurrency/thread_pool.h"
#include "oplogreader.h"
#include "cloner.h"

namespace mongo {

    /* replication slave? (possibly with slave)
       --slave cmd line setting -> SimpleSlave
    */
    typedef enum { NotSlave=0, SimpleSlave } SlaveTypes;

    class ReplSettings {
    public:
        SlaveTypes slave;

        /** true means we are master and doing replication.  if we are not writing to oplog, this won't be true. */
        bool master;

        bool fastsync;

        bool autoresync;

        int slavedelay;

        set<string> discoveredSeeds;
        BSONObj reconfig;

        ReplSettings()
            : slave(NotSlave) , master(false) , fastsync() , autoresync(false), slavedelay(), discoveredSeeds() {
        }

    };

    extern ReplSettings replSettings;

    /* A replication exception */
    class SyncException : public DBException {
    public:
        SyncException() : DBException( "sync exception" , 10001 ) {}
    };

    /* A Source is a source from which we can pull (replicate) data.
       stored in collection local.sources.

       Can be a group of things to replicate for several databases.

          { host: ..., source: ..., only: ..., syncedTo: ..., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }

       'source' defaults to 'main'; support for multiple source names is
       not done (always use main for now).
    */
    class ReplSource {
        shared_ptr<ThreadPool> tp;

        void resync(string db);

        /** @param alreadyLocked caller already put us in write lock if true */
        void sync_pullOpLog_applyOperation(BSONObj& op, bool alreadyLocked);

        /* pull some operations from the master's oplog, and apply them.
           calls sync_pullOpLog_applyOperation
        */
        int sync_pullOpLog(int& nApplied);

        /* we only clone one database per pass, even if a lot need done.  This helps us
           avoid overflowing the master's transaction log by doing too much work before going
           back to read more transactions. (Imagine a scenario of slave startup where we try to
           clone 100 databases in one pass.)
        */
        set<string> addDbNextPass;

        set<string> incompleteCloneDbs;

        ReplSource();

        // returns the dummy ns used to do the drop
        string resyncDrop( const char *db, const char *requester );
        // call without the db mutex
        void syncToTailOfRemoteLog();
        string ns() const { return string( "local.oplog.$" ) + sourceName(); }
        unsigned _sleepAdviceTime;

        /**
         * If 'db' is a new database and its name would conflict with that of
         * an existing database, synchronize these database names with the
         * master.
         * @return true iff an op with the specified ns may be applied.
         */
        bool handleDuplicateDbName( const BSONObj &op, const char *ns, const char *db );

    public:
        OplogReader oplogReader;

        void applyOperation(const BSONObj& op);
        string hostName;    // ip addr or hostname plus optionally, ":<port>"
        string _sourceName;  // a logical source name.
        string sourceName() const { return _sourceName.empty() ? "main" : _sourceName; }
        string only; // only a certain db. note that in the sources collection, this may not be changed once you start replicating.

        /* the last time point we have already synced up to (in the remote/master's oplog). */
        OpTime syncedTo;

        int nClonedThisPass;

        typedef vector< shared_ptr< ReplSource > > SourceVector;
        static void loadAll(SourceVector&);
        explicit ReplSource(BSONObj);

        /* -1 = error */
        int sync(int& nApplied);

        void save(); // write ourself to local.sources

        // make a jsobj from our member fields of the form
        //   { host: ..., source: ..., syncedTo: ... }
        BSONObj jsobj();

        bool operator==(const ReplSource&r) const {
            return hostName == r.hostName && sourceName() == r.sourceName();
        }
        string toString() const { return sourceName() + "@" + hostName; }

        bool haveMoreDbsToSync() const { return !addDbNextPass.empty(); }
        int sleepAdvice() const {
            if ( !_sleepAdviceTime )
                return 0;
            int wait = _sleepAdviceTime - unsigned( time( 0 ) );
            return wait > 0 ? wait : 0;
        }

        static bool throttledForceResyncDead( const char *requester );
        static void forceResyncDead( const char *requester );
        void forceResync( const char *requester );
    };

    bool anyReplEnabled();
    void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 );

    /**
     * Helper class used to set and query an ignore state for a named database.
     * The ignore state will expire after a specified OpTime.
     */
    class DatabaseIgnorer {
    public:
        /** Indicate that operations for 'db' should be ignored until after 'futureOplogTime' */
        void doIgnoreUntilAfter( const string &db, const OpTime &futureOplogTime );
        /**
         * Query ignore state of 'db'; if 'currentOplogTime' is after the ignore
         * limit, the ignore state will be cleared.
         */
        bool ignoreAt( const string &db, const OpTime &currentOplogTime );
    private:
        map< string, OpTime > _ignores;
    };

} // namespace mongo