1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage
32 
33 #include "mongo/platform/basic.h"
34 
35 #include <algorithm>
36 
37 #include "mongo/base/checked_cast.h"
38 #include "mongo/db/concurrency/write_conflict_exception.h"
39 #include "mongo/db/storage/wiredtiger/wiredtiger_oplog_manager.h"
40 #include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h"
41 #include "mongo/db/storage/wiredtiger/wiredtiger_recovery_unit.h"
42 #include "mongo/db/storage/wiredtiger/wiredtiger_session_cache.h"
43 #include "mongo/db/storage/wiredtiger/wiredtiger_snapshot_manager.h"
44 #include "mongo/util/log.h"
45 #include "mongo/util/mongoutils/str.h"
46 #include "mongo/util/scopeguard.h"
47 
48 namespace mongo {
49 
prepareForCreateSnapshot(OperationContext * opCtx)50 Status WiredTigerSnapshotManager::prepareForCreateSnapshot(OperationContext* opCtx) {
51     WiredTigerRecoveryUnit::get(opCtx)->prepareForCreateSnapshot(opCtx);
52     return Status::OK();
53 }
54 
setCommittedSnapshot(const Timestamp & timestamp)55 void WiredTigerSnapshotManager::setCommittedSnapshot(const Timestamp& timestamp) {
56     stdx::lock_guard<stdx::mutex> lock(_mutex);
57 
58     invariant(!_committedSnapshot || *_committedSnapshot <= timestamp);
59     _committedSnapshot = timestamp;
60 }
61 
cleanupUnneededSnapshots()62 void WiredTigerSnapshotManager::cleanupUnneededSnapshots() {}
63 
dropAllSnapshots()64 void WiredTigerSnapshotManager::dropAllSnapshots() {
65     stdx::lock_guard<stdx::mutex> lock(_mutex);
66     _committedSnapshot = boost::none;
67 }
68 
shutdown()69 void WiredTigerSnapshotManager::shutdown() {
70     stdx::lock_guard<stdx::mutex> lock(_mutex);
71     if (!_session)
72         return;
73     invariantWTOK(_session->close(_session, NULL));
74     _session = nullptr;
75 }
76 
getMinSnapshotForNextCommittedRead() const77 boost::optional<Timestamp> WiredTigerSnapshotManager::getMinSnapshotForNextCommittedRead() const {
78     stdx::lock_guard<stdx::mutex> lock(_mutex);
79     return _committedSnapshot;
80 }
81 
setTransactionReadTimestamp(Timestamp pointInTime,WT_SESSION * session) const82 Status WiredTigerSnapshotManager::setTransactionReadTimestamp(Timestamp pointInTime,
83                                                               WT_SESSION* session) const {
84     char readTSConfigString[15 /* read_timestamp= */ + 16 /* 16 hexadecimal digits */ +
85                             1 /* trailing null */];
86     auto size = std::snprintf(
87         readTSConfigString, sizeof(readTSConfigString), "read_timestamp=%llx", pointInTime.asULL());
88     if (size < 0) {
89         int e = errno;
90         error() << "error snprintf " << errnoWithDescription(e);
91         fassertFailedNoTrace(40664);
92     }
93     invariant(static_cast<std::size_t>(size) < sizeof(readTSConfigString));
94 
95     return wtRCToStatus(session->timestamp_transaction(session, readTSConfigString));
96 }
97 
beginTransactionOnCommittedSnapshot(WT_SESSION * session) const98 Timestamp WiredTigerSnapshotManager::beginTransactionOnCommittedSnapshot(
99     WT_SESSION* session) const {
100     invariantWTOK(session->begin_transaction(session, nullptr));
101     auto rollbacker =
102         MakeGuard([&] { invariant(session->rollback_transaction(session, nullptr) == 0); });
103 
104     stdx::lock_guard<stdx::mutex> lock(_mutex);
105     uassert(ErrorCodes::ReadConcernMajorityNotAvailableYet,
106             "Committed view disappeared while running operation",
107             _committedSnapshot);
108 
109     auto status = setTransactionReadTimestamp(_committedSnapshot.get(), session);
110     fassertStatusOK(30635, status);
111     rollbacker.Dismiss();
112     return *_committedSnapshot;
113 }
114 
beginTransactionOnOplog(WiredTigerOplogManager * oplogManager,WT_SESSION * session) const115 void WiredTigerSnapshotManager::beginTransactionOnOplog(WiredTigerOplogManager* oplogManager,
116                                                         WT_SESSION* session) const {
117     invariantWTOK(session->begin_transaction(session, nullptr));
118     auto rollbacker =
119         MakeGuard([&] { invariant(session->rollback_transaction(session, nullptr) == 0); });
120 
121     stdx::lock_guard<stdx::mutex> lock(_mutex);
122     auto allCommittedTimestamp = oplogManager->getOplogReadTimestamp();
123     invariant(Timestamp(static_cast<unsigned long long>(allCommittedTimestamp)).asULL() ==
124               allCommittedTimestamp);
125     auto status = setTransactionReadTimestamp(
126         Timestamp(static_cast<unsigned long long>(allCommittedTimestamp)), session);
127 
128     // If we failed to set the read timestamp, we assume it is due to the oldest_timestamp racing
129     // ahead.  Rather than synchronizing for this rare case, if requested, throw a
130     // WriteConflictException which will be retried.
131     if (!status.isOK() && status.code() == ErrorCodes::BadValue) {
132         throw WriteConflictException();
133     }
134     fassert(50771, status);
135     rollbacker.Dismiss();
136 }
137 
138 }  // namespace mongo
139