summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage
diff options
context:
space:
mode:
authorDaniel Gottlieb <daniel.gottlieb@mongodb.com>2018-09-20 15:00:47 -0400
committerDaniel Gottlieb <daniel.gottlieb@mongodb.com>2018-09-20 15:00:47 -0400
commit630eabac0591f207b29b6be014257387a9a7a904 (patch)
tree463bd23d64f3dec795b2fcf769d88a8fbe10ef50 /src/mongo/db/storage
parent4ec12c35a07a8c0f3a30692aec413a71fdab30de (diff)
downloadmongo-630eabac0591f207b29b6be014257387a9a7a904.tar.gz
SERVER-37192: Move $backupCursor to enterprise.
Diffstat (limited to 'src/mongo/db/storage')
-rw-r--r--src/mongo/db/storage/SConscript45
-rw-r--r--src/mongo/db/storage/backup_cursor_hooks.cpp87
-rw-r--r--src/mongo/db/storage/backup_cursor_hooks.h69
-rw-r--r--src/mongo/db/storage/backup_cursor_service.cpp212
-rw-r--r--src/mongo/db/storage/backup_cursor_service.h122
-rw-r--r--src/mongo/db/storage/backup_cursor_service_test.cpp157
-rw-r--r--src/mongo/db/storage/backup_cursor_state.h45
7 files changed, 215 insertions, 522 deletions
diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript
index 50c884dd6e6..366a429e58d 100644
--- a/src/mongo/db/storage/SConscript
+++ b/src/mongo/db/storage/SConscript
@@ -95,6 +95,20 @@ env.Library(
)
env.Library(
+ target='backup_cursor_hooks',
+ source=[
+ 'backup_cursor_hooks.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/service_context',
+ ],
+ LIBDEPS_DEPENDENTS=[
+ '$BUILD_DIR/mongo/mongodmain',
+ ],
+)
+
+env.Library(
target='test_harness_helper',
source=[
'test_harness_helper.cpp',
@@ -291,27 +305,6 @@ env.CppUnitTest(
],
)
-
-env.Library(
- target='backup_cursor_service',
- source=[
- 'backup_cursor_service.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- ],
- LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/db_raii',
- '$BUILD_DIR/mongo/db/dbhelpers',
- '$BUILD_DIR/mongo/db/namespace_string',
- '$BUILD_DIR/mongo/db/pipeline/document_value',
- '$BUILD_DIR/mongo/db/repl/oplog_entry',
- '$BUILD_DIR/mongo/db/repl/optime',
- 'encryption_hooks',
- 'storage_options',
- ],
-)
-
env.CppUnitTest(
target= 'storage_engine_metadata_test',
source = 'storage_engine_metadata_test.cpp',
@@ -337,13 +330,3 @@ env.Benchmark(
'$BUILD_DIR/mongo/base',
],
)
-
-env.CppUnitTest(
- target='backup_cursor_service_test',
- source='backup_cursor_service_test.cpp',
- LIBDEPS=[
- '$BUILD_DIR/mongo/db/auth/authmocks',
- '$BUILD_DIR/mongo/db/service_context_d_test_fixture',
- 'backup_cursor_service',
- ],
-)
diff --git a/src/mongo/db/storage/backup_cursor_hooks.cpp b/src/mongo/db/storage/backup_cursor_hooks.cpp
new file mode 100644
index 00000000000..d4c4a863fb2
--- /dev/null
+++ b/src/mongo/db/storage/backup_cursor_hooks.cpp
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2018 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/storage/backup_cursor_hooks.h"
+
+#include "mongo/base/init.h"
+#include "mongo/db/service_context.h"
+
+namespace mongo {
+
+namespace {
+BackupCursorHooks::InitializerFunction initializer = [](StorageEngine* storageEngine) {
+ return stdx::make_unique<BackupCursorHooks>();
+};
+
+struct BackupCursorHooksHolder {
+ std::unique_ptr<BackupCursorHooks> ptr = std::make_unique<BackupCursorHooks>();
+};
+
+const auto getBackupCursorHooks = ServiceContext::declareDecoration<BackupCursorHooksHolder>();
+} // namespace
+
+void BackupCursorHooks::registerInitializer(InitializerFunction func) {
+ initializer = func;
+}
+
+void BackupCursorHooks::initialize(ServiceContext* service, StorageEngine* storageEngine) {
+ getBackupCursorHooks(service).ptr = initializer(storageEngine);
+}
+
+BackupCursorHooks* BackupCursorHooks::get(ServiceContext* service) {
+ return getBackupCursorHooks(service).ptr.get();
+}
+
+BackupCursorHooks::~BackupCursorHooks() {}
+
+bool BackupCursorHooks::enabled() const {
+ return false;
+}
+
+/**
+ * The following methods cannot be called when BackupCursorHooks is not enabled.
+ */
+void BackupCursorHooks::fsyncLock(OperationContext* opCtx) {
+ MONGO_UNREACHABLE;
+}
+
+void BackupCursorHooks::fsyncUnlock(OperationContext* opCtx) {
+ MONGO_UNREACHABLE;
+}
+
+BackupCursorState BackupCursorHooks::openBackupCursor(OperationContext* opCtx) {
+ MONGO_UNREACHABLE;
+}
+
+void BackupCursorHooks::closeBackupCursor(OperationContext* opCtx, std::uint64_t cursorId) {
+ MONGO_UNREACHABLE;
+}
+} // namespace mongo
diff --git a/src/mongo/db/storage/backup_cursor_hooks.h b/src/mongo/db/storage/backup_cursor_hooks.h
new file mode 100644
index 00000000000..7344e5d391e
--- /dev/null
+++ b/src/mongo/db/storage/backup_cursor_hooks.h
@@ -0,0 +1,69 @@
+/**
+ * Copyright (C) 2018 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 <memory>
+#include <vector>
+
+#include "mongo/db/storage/backup_cursor_state.h"
+
+namespace mongo {
+class OperationContext;
+class ServiceContext;
+class StorageEngine;
+
+class BackupCursorHooks {
+public:
+ using InitializerFunction = std::function<std::unique_ptr<BackupCursorHooks>(StorageEngine*)>;
+
+ static void registerInitializer(InitializerFunction func);
+
+ static void initialize(ServiceContext* service, StorageEngine* storageEngine);
+
+ static BackupCursorHooks* get(ServiceContext* service);
+
+ virtual ~BackupCursorHooks();
+
+ /**
+ * Returns true if the backup cursor hooks are enabled. If this returns false, none of the
+ * other methods on this class may be called.
+ */
+ virtual bool enabled() const;
+
+ virtual void fsyncLock(OperationContext* opCtx);
+
+ virtual void fsyncUnlock(OperationContext* opCtx);
+
+ virtual BackupCursorState openBackupCursor(OperationContext* opCtx);
+
+ virtual void closeBackupCursor(OperationContext* opCtx, std::uint64_t cursorId);
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/storage/backup_cursor_service.cpp b/src/mongo/db/storage/backup_cursor_service.cpp
deleted file mode 100644
index e83dc22cfc9..00000000000
--- a/src/mongo/db/storage/backup_cursor_service.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * Copyright (C) 2018 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.
- */
-
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/storage/backup_cursor_service.h"
-
-#include "mongo/db/db_raii.h"
-#include "mongo/db/dbhelpers.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/db/repl/oplog_entry.h"
-#include "mongo/db/service_context.h"
-#include "mongo/db/storage/encryption_hooks.h"
-#include "mongo/db/storage/storage_engine.h"
-#include "mongo/db/storage/storage_options.h"
-#include "mongo/util/fail_point.h"
-#include "mongo/util/log.h"
-#include "mongo/util/scopeguard.h"
-
-namespace mongo {
-namespace {
-
-MONGO_FAIL_POINT_DEFINE(backupCursorErrorAfterOpen);
-
-const auto getBackupCursorService =
- ServiceContext::declareDecoration<std::unique_ptr<BackupCursorService>>();
-} // namespace
-
-BackupCursorService* BackupCursorService::get(ServiceContext* service) {
- return getBackupCursorService(service).get();
-}
-
-void BackupCursorService::set(ServiceContext* service,
- std::unique_ptr<BackupCursorService> backupCursorService) {
- auto& decoration = getBackupCursorService(service);
- decoration = std::move(backupCursorService);
-}
-
-void BackupCursorService::fsyncLock(OperationContext* opCtx) {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- uassert(50885, "The node is already fsyncLocked.", _state != kFsyncLocked);
- uassert(50884,
- "The existing backup cursor must be closed before fsyncLock can succeed.",
- _state != kBackupCursorOpened);
- uassertStatusOK(_storageEngine->beginBackup(opCtx));
- _state = kFsyncLocked;
-}
-
-void BackupCursorService::fsyncUnlock(OperationContext* opCtx) {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- uassert(50888, "The node is not fsyncLocked.", _state == kFsyncLocked);
- _storageEngine->endBackup(opCtx);
- _state = kInactive;
-}
-
-BackupCursorState BackupCursorService::openBackupCursor(OperationContext* opCtx) {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- uassert(50887, "The node is currently fsyncLocked.", _state != kFsyncLocked);
- uassert(50886,
- "The existing backup cursor must be closed before $backupCursor can succeed.",
- _state != kBackupCursorOpened);
-
- // Replica sets must also return the opTime's of the earliest and latest oplog entry. The
- // range represented by the oplog start/end values must exist in the backup copy, but are not
- // expected to be exact.
- repl::OpTime oplogStart;
- repl::OpTime oplogEnd;
-
- // If the oplog exists, capture the last oplog entry before opening the backup cursor. This
- // value will be checked again after the cursor is established to guarantee it still exists
- // (and was not truncated before the backup cursor was established.
- {
- AutoGetCollectionForRead coll(opCtx, NamespaceString::kRsOplogNamespace);
- if (coll.getCollection()) {
- BSONObj lastEntry;
- uassert(50914,
- str::stream() << "No oplog records were found.",
- Helpers::getLast(
- opCtx, NamespaceString::kRsOplogNamespace.ns().c_str(), lastEntry));
- auto oplogEntry = fassertNoTrace(50913, repl::OplogEntry::parse(lastEntry));
- oplogEnd = oplogEntry.getOpTime();
- }
- }
-
- // Capture the checkpointTimestamp before and after opening a cursor. If it hasn't moved, the
- // checkpointTimestamp is known to be exact. If it has moved, uassert and have the user retry.
- boost::optional<Timestamp> checkpointTimestamp;
- if (_storageEngine->supportsRecoverToStableTimestamp()) {
- checkpointTimestamp = _storageEngine->getLastStableRecoveryTimestamp();
- };
-
- auto filesToBackup = uassertStatusOK(_storageEngine->beginNonBlockingBackup(opCtx));
- _state = kBackupCursorOpened;
- _openCursor = ++_cursorIdGenerator;
- log() << "Opened backup cursor. ID: " << _openCursor.get();
-
- // A backup cursor is open. Any exception code path must leave the BackupCursorService in an
- // inactive state.
- auto closeCursorGuard =
- MakeGuard([this, opCtx, &lk] { _closeBackupCursor(opCtx, _openCursor.get(), lk); });
-
- uassert(50919,
- "Failpoint hit after opening the backup cursor.",
- !MONGO_FAIL_POINT(backupCursorErrorAfterOpen));
-
- // Ensure the checkpointTimestamp hasn't moved. A subtle case to catch is the first stable
- // checkpoint coming out of initial sync racing with opening the backup cursor.
- if (checkpointTimestamp && _storageEngine->supportsRecoverToStableTimestamp()) {
- auto requeriedCheckpointTimestamp = _storageEngine->getLastStableRecoveryTimestamp();
- if (!requeriedCheckpointTimestamp ||
- requeriedCheckpointTimestamp.get() < checkpointTimestamp.get()) {
- severe() << "The last stable recovery timestamp went backwards. Original: "
- << checkpointTimestamp.get() << " Found: " << requeriedCheckpointTimestamp;
- fassertFailed(50916);
- }
-
- uassert(50915,
- str::stream() << "A checkpoint took place while opening a backup cursor.",
- checkpointTimestamp == requeriedCheckpointTimestamp);
- };
-
- // If the oplog exists, capture the first oplog entry after opening the backup cursor. Ensure
- // it is before the `oplogEnd` value.
- if (!oplogEnd.isNull()) {
- BSONObj firstEntry;
- uassert(50912,
- str::stream() << "No oplog records were found.",
- Helpers::getSingleton(
- opCtx, NamespaceString::kRsOplogNamespace.ns().c_str(), firstEntry));
- auto oplogEntry = fassertNoTrace(50918, repl::OplogEntry::parse(firstEntry));
- oplogStart = oplogEntry.getOpTime();
- uassert(50917,
- str::stream() << "Oplog rolled over while establishing the backup cursor.",
- oplogStart < oplogEnd);
- }
-
- auto encHooks = EncryptionHooks::get(opCtx->getServiceContext());
- if (encHooks->enabled()) {
- auto eseFiles = uassertStatusOK(encHooks->beginNonBlockingBackup());
- filesToBackup.insert(filesToBackup.end(), eseFiles.begin(), eseFiles.end());
- }
-
- BSONObjBuilder builder;
- builder << "dbpath" << storageGlobalParams.dbpath;
- if (!oplogStart.isNull()) {
- builder << "oplogStart" << oplogStart.toBSON();
- builder << "oplogEnd" << oplogEnd.toBSON();
- }
-
- // Notably during initial sync, a node may have an oplog without a stable checkpoint.
- if (checkpointTimestamp) {
- builder << "checkpointTimestamp" << checkpointTimestamp.get();
- }
-
- Document preamble{{"metadata", builder.obj()}};
-
- closeCursorGuard.Dismiss();
- return {_openCursor.get(), preamble, filesToBackup};
-}
-
-void BackupCursorService::closeBackupCursor(OperationContext* opCtx, std::uint64_t cursorId) {
- stdx::lock_guard<stdx::mutex> lk(_mutex);
- _closeBackupCursor(opCtx, cursorId, lk);
-}
-
-void BackupCursorService::_closeBackupCursor(OperationContext* opCtx,
- std::uint64_t cursorId,
- WithLock) {
- uassert(50880, "There is no backup cursor to close.", _state == kBackupCursorOpened);
- uassert(50879,
- str::stream() << "Can only close the running backup cursor. To close: " << cursorId
- << " Running: "
- << _openCursor.get(),
- cursorId == _openCursor.get());
- _storageEngine->endNonBlockingBackup(opCtx);
- auto encHooks = EncryptionHooks::get(opCtx->getServiceContext());
- if (encHooks->enabled()) {
- fassert(50934, encHooks->endNonBlockingBackup());
- }
- log() << "Closed backup cursor. ID: " << cursorId;
- _state = kInactive;
- _openCursor = boost::none;
-}
-
-} // namespace mongo
diff --git a/src/mongo/db/storage/backup_cursor_service.h b/src/mongo/db/storage/backup_cursor_service.h
deleted file mode 100644
index aa6e4a562cf..00000000000
--- a/src/mongo/db/storage/backup_cursor_service.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Copyright (C) 2018 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 <boost/optional.hpp>
-#include <memory>
-#include <vector>
-
-#include "mongo/base/disallow_copying.h"
-#include "mongo/db/pipeline/document.h"
-#include "mongo/stdx/mutex.h"
-#include "mongo/util/concurrency/with_lock.h"
-
-namespace mongo {
-
-class OperationContext;
-class ServiceContext;
-class StorageEngine;
-
-struct BackupCursorState {
- std::uint64_t cursorId;
- boost::optional<Document> preamble;
- std::vector<std::string> filenames;
-};
-
-/**
- * MongoDB exposes two separate client APIs for locking down files on disk for a file-system based
- * backup that require only one pass of the data to complete. First is using the `fsync` command
- * with `lock: true`. The second is using the `$backupCursor` aggregation stage. It does not make
- * sense for both techniques to be concurrently engaged. This class will manage access to these
- * resources such that their lifetimes do not overlap. More specifically, an `fsyncLock` mode can
- * only be freed by `fsyncUnlock` and `openBackupCursor` by `closeBackupCursor`.
- *
- * Failure to comply is expected to be due to user error and this class is best situated to detect
- * such errors. For this reason, callers should assume all method calls can only fail with
- * uassert exceptions.
- */
-class BackupCursorService {
- MONGO_DISALLOW_COPYING(BackupCursorService);
-
-public:
- static BackupCursorService* get(ServiceContext* service);
- static void set(ServiceContext* service,
- std::unique_ptr<BackupCursorService> backupCursorService);
-
- BackupCursorService(StorageEngine* storageEngine) : _storageEngine(storageEngine) {}
-
- /**
- * This method will uassert if `_state` is not `kInactive`. Otherwise, the method forwards to
- * `StorageEngine::beginBackup`.
- */
- void fsyncLock(OperationContext* opCtx);
-
- /**
- * This method will uassert if `_state` is not `kFsyncLocked`. Otherwise, the method forwards
- * to `StorageEngine::endBackup`.
- */
- void fsyncUnlock(OperationContext* opCtx);
-
- /**
- * This method will uassert if `_state` is not `kInactive`. Otherwise, the method forwards to
- * `StorageEngine::beginNonBlockingBackup`.
- *
- * Returns a BackupCursorState. The structure's `cursorId` must be passed to
- * `closeBackupCursor` to successfully exit this backup mode. `filenames` is a list of files
- * relative to the server's `dbpath` that must be copied by the application to complete a
- * backup.
- */
- BackupCursorState openBackupCursor(OperationContext* opCtx);
-
- /**
- * This method will uassert if `_state` is not `kBackupCursorOpened`, or the `cursorId` input
- * is not the active backup cursor open known to `_openCursor`.
- */
- void closeBackupCursor(OperationContext* opCtx, std::uint64_t cursorId);
-
-private:
- void _closeBackupCursor(OperationContext* opCtx, std::uint64_t cursorId, WithLock);
-
- StorageEngine* _storageEngine;
-
- enum State { kInactive, kFsyncLocked, kBackupCursorOpened };
-
- // This mutex serializes all access into this class.
- stdx::mutex _mutex;
- State _state = kInactive;
- // When state is `kBackupCursorOpened`, _openCursor contains the cursorId of the active backup
- // cursor. Otherwise it is boost::none.
- boost::optional<std::uint64_t> _openCursor = boost::none;
- // _cursorIdGenerator is incremented and returned each time a new backup cursor is
- // opened. While `fsyncLock`ing a system does open a WT backup cursor, the terminology keeps
- // the two separate here.
- std::uint64_t _cursorIdGenerator = 0;
-};
-
-} // namespace mongo
diff --git a/src/mongo/db/storage/backup_cursor_service_test.cpp b/src/mongo/db/storage/backup_cursor_service_test.cpp
deleted file mode 100644
index 9f6a1958fa7..00000000000
--- a/src/mongo/db/storage/backup_cursor_service_test.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * Copyright (C) 2018 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.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/storage/backup_cursor_service.h"
-
-#include "mongo/db/client.h"
-#include "mongo/db/service_context.h"
-#include "mongo/db/service_context_d_test_fixture.h"
-#include "mongo/db/storage/devnull/devnull_kv_engine.h"
-#include "mongo/db/storage/kv/kv_storage_engine.h"
-#include "mongo/unittest/unittest.h"
-
-namespace mongo {
-namespace {
-
-class BackupCursorServiceTest : public ServiceContextMongoDTest {
-public:
- BackupCursorServiceTest()
- : ServiceContextMongoDTest("devnull"),
- _opCtx(cc().makeOperationContext()),
- _storageEngine(getServiceContext()->getStorageEngine()),
- _backupCursorService(stdx::make_unique<BackupCursorService>(_storageEngine)) {}
-
-protected:
- ServiceContext::UniqueOperationContext _opCtx;
- StorageEngine* _storageEngine;
- std::unique_ptr<BackupCursorService> _backupCursorService;
-};
-
-TEST_F(BackupCursorServiceTest, TestTypicalFsyncLifetime) {
- _backupCursorService->fsyncLock(_opCtx.get());
- _backupCursorService->fsyncUnlock(_opCtx.get());
-
- _backupCursorService->fsyncLock(_opCtx.get());
- _backupCursorService->fsyncUnlock(_opCtx.get());
-}
-
-TEST_F(BackupCursorServiceTest, TestDoubleLock) {
- _backupCursorService->fsyncLock(_opCtx.get());
- ASSERT_THROWS_WHAT(_backupCursorService->fsyncLock(_opCtx.get()),
- DBException,
- "The node is already fsyncLocked.");
- _backupCursorService->fsyncUnlock(_opCtx.get());
-}
-
-TEST_F(BackupCursorServiceTest, TestDoubleUnlock) {
- ASSERT_THROWS_WHAT(_backupCursorService->fsyncUnlock(_opCtx.get()),
- DBException,
- "The node is not fsyncLocked.");
-
- _backupCursorService->fsyncLock(_opCtx.get());
- _backupCursorService->fsyncUnlock(_opCtx.get());
- ASSERT_THROWS_WHAT(_backupCursorService->fsyncUnlock(_opCtx.get()),
- DBException,
- "The node is not fsyncLocked.");
-}
-
-TEST_F(BackupCursorServiceTest, TestTypicalCursorLifetime) {
- auto backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
- ASSERT_EQUALS(1u, backupCursorState.cursorId);
- ASSERT_EQUALS(1u, backupCursorState.filenames.size());
- ASSERT_EQUALS("filename.wt", backupCursorState.filenames[0]);
-
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
-
- backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
- ASSERT_EQUALS(2u, backupCursorState.cursorId);
- ASSERT_EQUALS(1u, backupCursorState.filenames.size());
- ASSERT_EQUALS("filename.wt", backupCursorState.filenames[0]);
-
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
-}
-
-TEST_F(BackupCursorServiceTest, TestDoubleOpenCursor) {
- auto backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
- ASSERT_THROWS_WHAT(
- _backupCursorService->openBackupCursor(_opCtx.get()),
- DBException,
- "The existing backup cursor must be closed before $backupCursor can succeed.");
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
-}
-
-TEST_F(BackupCursorServiceTest, TestDoubleCloseCursor) {
- ASSERT_THROWS_WHAT(_backupCursorService->closeBackupCursor(_opCtx.get(), 10),
- DBException,
- "There is no backup cursor to close.");
-
- auto backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
- ASSERT_THROWS_WHAT(
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId),
- DBException,
- "There is no backup cursor to close.");
-}
-
-TEST_F(BackupCursorServiceTest, TestCloseWrongCursor) {
- auto backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
-
- ASSERT_THROWS_WITH_CHECK(
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId + 1),
- DBException,
- [](const DBException& exc) {
- ASSERT_STRING_CONTAINS(exc.what(), "Can only close the running backup cursor.");
- });
-
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
-}
-
-TEST_F(BackupCursorServiceTest, TestMixingFsyncAndCursors) {
- _backupCursorService->fsyncLock(_opCtx.get());
- ASSERT_THROWS_WHAT(_backupCursorService->openBackupCursor(_opCtx.get()),
- DBException,
- "The node is currently fsyncLocked.");
- ASSERT_THROWS_WHAT(_backupCursorService->closeBackupCursor(_opCtx.get(), 1),
- DBException,
- "There is no backup cursor to close.");
- _backupCursorService->fsyncUnlock(_opCtx.get());
-
- auto backupCursorState = _backupCursorService->openBackupCursor(_opCtx.get());
- ASSERT_THROWS_WHAT(_backupCursorService->fsyncLock(_opCtx.get()),
- DBException,
- "The existing backup cursor must be closed before fsyncLock can succeed.");
- ASSERT_THROWS_WHAT(_backupCursorService->fsyncUnlock(_opCtx.get()),
- DBException,
- "The node is not fsyncLocked.");
- _backupCursorService->closeBackupCursor(_opCtx.get(), backupCursorState.cursorId);
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/storage/backup_cursor_state.h b/src/mongo/db/storage/backup_cursor_state.h
new file mode 100644
index 00000000000..584d61e800d
--- /dev/null
+++ b/src/mongo/db/storage/backup_cursor_state.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2018 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 <boost/optional.hpp>
+#include <string>
+#include <vector>
+
+#include "mongo/db/pipeline/document.h"
+
+namespace mongo {
+
+struct BackupCursorState {
+ std::uint64_t cursorId;
+ boost::optional<Document> preamble;
+ std::vector<std::string> filenames;
+};
+
+} // namespace mongo