summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage/mmap_v1/dur.h
blob: e4aec954749e14b32dfaca9eba051ffeb5bc6736 (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
/**
 *    Copyright (C) 2009-2014 MongoDB 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 <string>
#include <vector>

#include "mongo/base/disallow_copying.h"
#include "mongo/db/storage/journal_listener.h"

namespace mongo {

class ClockSource;
class OperationContext;

namespace dur {

// a smaller limit is likely better on 32 bit
const unsigned UncommittedBytesLimit = (sizeof(void*) == 4) ? 50 * 1024 * 1024 : 512 * 1024 * 1024;

class DurableInterface {
    MONGO_DISALLOW_COPYING(DurableInterface);

public:
    virtual ~DurableInterface();

    /**
     * Declare that a file has been created. Normally writes are applied only after journaling
     * for safety. But here the file is created first, and the journal will just replay the
     * creation if the create didn't happen due to a crash.
     */
    virtual void createdFile(const std::string& filename, unsigned long long len) = 0;

    // Declare write intents. Use these methods to declare "i'm about to write to x and it
    // should be logged for redo."
    //
    // Failure to call declare write intents is checked in MONGO_CONFIG_DEBUG_BUILD mode by
    // using a read only mapped view (i.e., you'll segfault if the code is covered in that
    // situation).  The debug check doesn't verify that your length is correct though.
    virtual void declareWriteIntents(const std::vector<std::pair<void*, unsigned>>& intents) = 0;

    /** Wait for acknowledgement of the next group commit.
        @return true if --dur is on.  There will be delay.
        @return false if --dur is off.
        */
    virtual bool waitUntilDurable() = 0;

    /** Commit immediately.

        Generally, you do not want to do this often, as highly granular committing may affect
        performance.

        Does not return until the commit is complete.

        You must be at least read locked when you call this.  Ideally, you are not write locked
        and then read operations can occur concurrently.

        Do not use this. Use commitIfNeeded() instead.

        @return true if --dur is on.
        @return false if --dur is off. (in which case there is action)
        */
    virtual bool commitNow(OperationContext* txn) = 0;

    /** Commit if enough bytes have been modified. Current threshold is 50MB

        The idea is that long running write operations that don't yield
        (like creating an index or update with $atomic) can call this
        whenever the db is in a sane state and it will prevent commits
        from growing too large.
        @return true if commited
        */
    virtual bool commitIfNeeded() = 0;


    /**
     * Called when a DurableMappedFile is closing. Asserts that there are no unwritten changes,
     * because that would mean journal replay on recovery would try to write to non-existent
     * files and fail.
     */
    virtual void closingFileNotification() = 0;

    /**
        * Invoked at clean shutdown time. Performs one last commit/flush and terminates the
        * flush thread.
        *
        * Must be called under the global X lock.
        */
    virtual void commitAndStopDurThread(OperationContext* txn) = 0;

    /**
     * Commits pending changes, flushes all changes to main data files, then removes the
     * journal.
     *
     * WARNING: Data *must* be in a crash-recoverable state when this is called and must
     *          not be inside of a write unit of work.
     *
     * This is useful as a "barrier" to ensure that writes before this call will never go
     * through recovery and be applied to files that have had changes made after this call
     * applied.
     */
    virtual void syncDataAndTruncateJournal(OperationContext* txn) = 0;

    virtual bool isDurable() const = 0;

    static DurableInterface& getDur() {
        return *_impl;
    }

protected:
    DurableInterface();

private:
    friend void startup(ClockSource* cs, int64_t serverStartMs);

    static DurableInterface* _impl;
};


/**
 * Called during startup to startup the durability module.
 * Does nothing if storageGlobalParams.dur is false
 */
void startup(ClockSource* cs, int64_t serverStartMs);

// Sets a new JournalListener, which is used to alert the rest of the system about
// journaled write progress.
void setJournalListener(JournalListener* jl);

// Expose the JournalListener, needed for the journal writer thread.
JournalListener* getJournalListener();

}  // namespace dur


/**
 * Provides a reference to the active durability interface.
 *
 * TODO: The only reason this is an inline function is that tests try to link it and fail if
 *       the MMAP V1 engine is not included.
 */
inline dur::DurableInterface& getDur() {
    return dur::DurableInterface::getDur();
}

}  // namespace mongo