diff options
author | Randolph Tan <randolph@10gen.com> | 2018-12-17 15:15:43 -0500 |
---|---|---|
committer | Randolph Tan <randolph@10gen.com> | 2019-01-11 14:32:51 -0500 |
commit | 891ca0c23f979268fa0b9403500a8a582646613b (patch) | |
tree | 36040158a601bd52385ff01effb78f4deeb9d56b | |
parent | 3b028cfc6f5ced60c180c340a46d4d06f7ac9815 (diff) | |
download | mongo-891ca0c23f979268fa0b9403500a8a582646613b.tar.gz |
SERVER-38179 Refactor RemoveSaver out of dbhelpers
-rw-r--r-- | src/mongo/db/dbhelpers.cpp | 128 | ||||
-rw-r--r-- | src/mongo/db/dbhelpers.h | 46 | ||||
-rw-r--r-- | src/mongo/db/repl/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/repl/rollback_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/rs_rollback.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/collection_range_deleter.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/storage/SConscript | 12 | ||||
-rw-r--r-- | src/mongo/db/storage/remove_saver.cpp | 179 | ||||
-rw-r--r-- | src/mongo/db/storage/remove_saver.h | 85 |
11 files changed, 288 insertions, 181 deletions
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index d1b5b9518fa..6598b445dcc 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -34,9 +34,6 @@ #include "mongo/db/dbhelpers.h" -#include <boost/filesystem/operations.hpp> -#include <fstream> - #include "mongo/db/db_raii.h" #include "mongo/db/exec/working_set_common.h" #include "mongo/db/index/btree_access_method.h" @@ -55,9 +52,6 @@ #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/service_context.h" -#include "mongo/db/storage/data_protector.h" -#include "mongo/db/storage/encryption_hooks.h" -#include "mongo/db/storage/storage_options.h" #include "mongo/db/write_concern.h" #include "mongo/db/write_concern_options.h" #include "mongo/util/log.h" @@ -67,11 +61,8 @@ namespace mongo { using std::unique_ptr; -using std::ios_base; -using std::ofstream; using std::set; using std::string; -using std::stringstream; /* fetch a single object from collection ns that matches query set your db SavedContext first @@ -276,123 +267,4 @@ void Helpers::emptyCollection(OperationContext* opCtx, const NamespaceString& ns deleteObjects(opCtx, collection, nss, BSONObj(), false); } -Helpers::RemoveSaver::RemoveSaver(const string& a, const string& b, const string& why) { - static int NUM = 0; - - _root = storageGlobalParams.dbpath; - if (a.size()) - _root /= a; - if (b.size()) - _root /= b; - verify(a.size() || b.size()); - - _file = _root; - - stringstream ss; - ss << why << "." << terseCurrentTime(false) << "." << NUM++ << ".bson"; - _file /= ss.str(); - - auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); - if (encryptionHooks->enabled()) { - _protector = encryptionHooks->getDataProtector(); - _file += encryptionHooks->getProtectedPathSuffix(); - } -} - -Helpers::RemoveSaver::~RemoveSaver() { - if (_protector && _out) { - auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); - invariant(encryptionHooks->enabled()); - - size_t protectedSizeMax = encryptionHooks->additionalBytesForProtectedBuffer(); - std::unique_ptr<uint8_t[]> protectedBuffer(new uint8_t[protectedSizeMax]); - - size_t resultLen; - Status status = _protector->finalize(protectedBuffer.get(), protectedSizeMax, &resultLen); - if (!status.isOK()) { - severe() << "Unable to finalize DataProtector while closing RemoveSaver: " - << redact(status); - fassertFailed(34350); - } - - _out->write(reinterpret_cast<const char*>(protectedBuffer.get()), resultLen); - if (_out->fail()) { - severe() << "Couldn't write finalized DataProtector data to: " << _file.string() - << " for remove saving: " << redact(errnoWithDescription()); - fassertFailed(34351); - } - - protectedBuffer.reset(new uint8_t[protectedSizeMax]); - status = _protector->finalizeTag(protectedBuffer.get(), protectedSizeMax, &resultLen); - if (!status.isOK()) { - severe() << "Unable to get finalizeTag from DataProtector while closing RemoveSaver: " - << redact(status); - fassertFailed(34352); - } - if (resultLen != _protector->getNumberOfBytesReservedForTag()) { - severe() << "Attempted to write tag of size " << resultLen - << " when DataProtector only reserved " - << _protector->getNumberOfBytesReservedForTag() << " bytes"; - fassertFailed(34353); - } - _out->seekp(0); - _out->write(reinterpret_cast<const char*>(protectedBuffer.get()), resultLen); - if (_out->fail()) { - severe() << "Couldn't write finalizeTag from DataProtector to: " << _file.string() - << " for remove saving: " << redact(errnoWithDescription()); - fassertFailed(34354); - } - } -} - -Status Helpers::RemoveSaver::goingToDelete(const BSONObj& o) { - if (!_out) { - // We don't expect to ever pass "" to create_directories below, but catch - // this anyway as per SERVER-26412. - invariant(!_root.empty()); - boost::filesystem::create_directories(_root); - _out.reset(new ofstream(_file.string().c_str(), ios_base::out | ios_base::binary)); - if (_out->fail()) { - string msg = str::stream() << "couldn't create file: " << _file.string() - << " for remove saving: " << redact(errnoWithDescription()); - error() << msg; - _out.reset(); - _out = 0; - return Status(ErrorCodes::FileNotOpen, msg); - } - } - - const uint8_t* data = reinterpret_cast<const uint8_t*>(o.objdata()); - size_t dataSize = o.objsize(); - - std::unique_ptr<uint8_t[]> protectedBuffer; - if (_protector) { - auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); - invariant(encryptionHooks->enabled()); - - size_t protectedSizeMax = dataSize + encryptionHooks->additionalBytesForProtectedBuffer(); - protectedBuffer.reset(new uint8_t[protectedSizeMax]); - - size_t resultLen; - Status status = _protector->protect( - data, dataSize, protectedBuffer.get(), protectedSizeMax, &resultLen); - if (!status.isOK()) { - return status; - } - - data = protectedBuffer.get(); - dataSize = resultLen; - } - - _out->write(reinterpret_cast<const char*>(data), dataSize); - if (_out->fail()) { - string msg = str::stream() << "couldn't write document to file: " << _file.string() - << " for remove saving: " << redact(errnoWithDescription()); - error() << msg; - return Status(ErrorCodes::OperationFailed, msg); - } - return Status::OK(); -} - - } // namespace mongo diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h index 5f7344bb3b5..ecaa5f7af8e 100644 --- a/src/mongo/db/dbhelpers.h +++ b/src/mongo/db/dbhelpers.h @@ -30,18 +30,13 @@ #pragma once -#include <boost/filesystem/path.hpp> -#include <memory> - #include "mongo/db/namespace_string.h" #include "mongo/db/record_id.h" -#include "mongo/db/storage/data_protector.h" namespace mongo { class Collection; class Database; -class DataProtector; class OperationContext; class QueryRequest; @@ -52,7 +47,6 @@ class QueryRequest; * all helpers assume locking is handled above them */ struct Helpers { - class RemoveSaver; /* fetch a single object from collection ns that matches query. set your db SavedContext first. @@ -150,46 +144,6 @@ struct Helpers { * Does not oplog the operation. */ static void emptyCollection(OperationContext* opCtx, const NamespaceString& nss); - - /** - * for saving deleted bson objects to a flat file - */ - class RemoveSaver { - MONGO_DISALLOW_COPYING(RemoveSaver); - - public: - RemoveSaver(const std::string& type, const std::string& ns, const std::string& why); - ~RemoveSaver(); - - /** - * Writes document to file. File is created lazily before writing the first document. - * Returns error status if the file could not be created or if there were errors writing - * to the file. - */ - Status goingToDelete(const BSONObj& o); - - /** - * A path object describing the directory containing the file with deleted documents. - */ - const auto& root() const& { - return _root; - } - void root() && = delete; - - /** - * A path object describing the actual file containing BSON documents. - */ - const auto& file() const& { - return _file; - } - void file() && = delete; - - private: - boost::filesystem::path _root; - boost::filesystem::path _file; - std::unique_ptr<DataProtector> _protector; - std::unique_ptr<std::ostream> _out; - }; }; } // namespace mongo diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index ae8989e9702..1221abc160d 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -522,6 +522,7 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/catalog_helpers', '$BUILD_DIR/mongo/db/catalog/database_holder', '$BUILD_DIR/mongo/db/s/sharding_runtime_d', + '$BUILD_DIR/mongo/db/storage/remove_saver', '$BUILD_DIR/mongo/util/fail_point', '$BUILD_DIR/mongo/db/dbhelpers', '$BUILD_DIR/mongo/db/query_exec', diff --git a/src/mongo/db/repl/rollback_impl.cpp b/src/mongo/db/repl/rollback_impl.cpp index 511660973a0..7c7bc94cf38 100644 --- a/src/mongo/db/repl/rollback_impl.cpp +++ b/src/mongo/db/repl/rollback_impl.cpp @@ -41,7 +41,6 @@ #include "mongo/db/commands.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/db_raii.h" -#include "mongo/db/dbhelpers.h" #include "mongo/db/kill_sessions_local.h" #include "mongo/db/logical_time_validator.h" #include "mongo/db/operation_context.h" @@ -57,6 +56,7 @@ #include "mongo/db/server_parameters.h" #include "mongo/db/server_recovery.h" #include "mongo/db/server_transactions_metrics.h" +#include "mongo/db/storage/remove_saver.h" #include "mongo/s/catalog/type_config_version.h" #include "mongo/util/log.h" #include "mongo/util/scopeguard.h" @@ -973,7 +973,7 @@ void RollbackImpl::_writeRollbackFileForNamespace(OperationContext* opCtx, UUID uuid, NamespaceString nss, const SimpleBSONObjUnorderedSet& idSet) { - Helpers::RemoveSaver removeSaver(kRollbackRemoveSaverType, nss.ns(), kRollbackRemoveSaverWhy); + RemoveSaver removeSaver(kRollbackRemoveSaverType, nss.ns(), kRollbackRemoveSaverWhy); log() << "Preparing to write deleted documents to a rollback file for collection " << nss.ns() << " with uuid " << uuid.toString() << " to " << removeSaver.file().generic_string(); diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index eae4a7b87cb..6896955ec78 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -72,6 +72,7 @@ #include "mongo/db/repl/rslog.h" #include "mongo/db/s/shard_identity_rollback_notifier.h" #include "mongo/db/session_catalog_mongod.h" +#include "mongo/db/storage/remove_saver.h" #include "mongo/db/transaction_participant.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" @@ -747,7 +748,7 @@ void dropCollection(OperationContext* opCtx, Collection* collection, Database* db) { if (RollbackImpl::shouldCreateDataFiles()) { - Helpers::RemoveSaver removeSaver("rollback", "", nss.ns()); + RemoveSaver removeSaver("rollback", "", nss.ns()); // Performs a collection scan and writes all documents in the collection to disk // in order to keep an archive of items that were rolled back. @@ -1259,13 +1260,13 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, // while rolling back createCollection operations. const auto& uuid = nsAndGoodVersionsByDocID.first; - unique_ptr<Helpers::RemoveSaver> removeSaver; + unique_ptr<RemoveSaver> removeSaver; invariant(!fixUpInfo.collectionsToDrop.count(uuid)); NamespaceString nss = catalog.lookupNSSByUUID(uuid); if (RollbackImpl::shouldCreateDataFiles()) { - removeSaver = std::make_unique<Helpers::RemoveSaver>("rollback", "", nss.ns()); + removeSaver = std::make_unique<RemoveSaver>("rollback", "", nss.ns()); } const auto& goodVersionsByDocID = nsAndGoodVersionsByDocID.second; diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index e348ad6e4ad..128f6985853 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -75,6 +75,7 @@ env.Library( '$BUILD_DIR/mongo/db/ops/write_ops_exec', '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', + '$BUILD_DIR/mongo/db/storage/remove_saver', '$BUILD_DIR/mongo/db/rw_concern_d', '$BUILD_DIR/mongo/s/client/shard_local', '$BUILD_DIR/mongo/s/sharding_initialization', diff --git a/src/mongo/db/s/collection_range_deleter.cpp b/src/mongo/db/s/collection_range_deleter.cpp index 8856d53d8a2..ead8f441758 100644 --- a/src/mongo/db/s/collection_range_deleter.cpp +++ b/src/mongo/db/s/collection_range_deleter.cpp @@ -55,6 +55,7 @@ #include "mongo/db/s/sharding_statistics.h" #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" +#include "mongo/db/storage/remove_saver.h" #include "mongo/db/write_concern.h" #include "mongo/executor/task_executor.h" #include "mongo/util/log.h" @@ -386,7 +387,7 @@ StatusWith<int> CollectionRangeDeleter::_doDeletion(OperationContext* opCtx, return {ErrorCodes::InternalError, msg}; } - boost::optional<Helpers::RemoveSaver> saver; + boost::optional<RemoveSaver> saver; if (serverGlobalParams.moveParanoia) { saver.emplace("moveChunk", nss.ns(), "cleaning"); } diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index cacf25a608c..69f62df8751 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -57,6 +57,7 @@ #include "mongo/db/s/start_chunk_clone_request.h" #include "mongo/db/server_parameters.h" #include "mongo/db/service_context.h" +#include "mongo/db/storage/remove_saver.h" #include "mongo/s/catalog/type_chunk.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" @@ -1040,7 +1041,7 @@ bool MigrationDestinationManager::_applyMigrateOp(OperationContext* opCtx, // Deleted documents if (xfer["deleted"].isABSONObj()) { - boost::optional<Helpers::RemoveSaver> rs; + boost::optional<RemoveSaver> rs; if (serverGlobalParams.moveParanoia) { rs.emplace("moveChunk", _nss.ns(), "removedDuring"); } diff --git a/src/mongo/db/storage/SConscript b/src/mongo/db/storage/SConscript index 8cd5b9cb4f4..e82a86d5cdb 100644 --- a/src/mongo/db/storage/SConscript +++ b/src/mongo/db/storage/SConscript @@ -341,3 +341,15 @@ env.Benchmark( '$BUILD_DIR/mongo/base', ], ) + +env.Library( + target='remove_saver', + source=[ + 'remove_saver.cpp', + ], + LIBDEPS=[ + 'encryption_hooks', + 'storage_options', + '$BUILD_DIR/mongo/base', + ] +) diff --git a/src/mongo/db/storage/remove_saver.cpp b/src/mongo/db/storage/remove_saver.cpp new file mode 100644 index 00000000000..505e9083b75 --- /dev/null +++ b/src/mongo/db/storage/remove_saver.cpp @@ -0,0 +1,179 @@ + +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * 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 Server Side 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/remove_saver.h" + +#include <boost/filesystem/operations.hpp> +#include <fstream> + +#include "mongo/db/service_context.h" +#include "mongo/db/storage/encryption_hooks.h" +#include "mongo/db/storage/storage_options.h" +#include "mongo/util/errno_util.h" +#include "mongo/util/log.h" + + +using std::ios_base; +using std::ofstream; +using std::stringstream; +using std::string; + +namespace mongo { + +RemoveSaver::RemoveSaver(const string& a, const string& b, const string& why) { + static int NUM = 0; + + _root = storageGlobalParams.dbpath; + if (a.size()) + _root /= a; + if (b.size()) + _root /= b; + verify(a.size() || b.size()); + + _file = _root; + + stringstream ss; + ss << why << "." << terseCurrentTime(false) << "." << NUM++ << ".bson"; + _file /= ss.str(); + + auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); + if (encryptionHooks->enabled()) { + _protector = encryptionHooks->getDataProtector(); + _file += encryptionHooks->getProtectedPathSuffix(); + } +} + +RemoveSaver::~RemoveSaver() { + if (_protector && _out) { + auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); + invariant(encryptionHooks->enabled()); + + size_t protectedSizeMax = encryptionHooks->additionalBytesForProtectedBuffer(); + std::unique_ptr<uint8_t[]> protectedBuffer(new uint8_t[protectedSizeMax]); + + size_t resultLen; + Status status = _protector->finalize(protectedBuffer.get(), protectedSizeMax, &resultLen); + if (!status.isOK()) { + severe() << "Unable to finalize DataProtector while closing RemoveSaver: " + << redact(status); + fassertFailed(34350); + } + + _out->write(reinterpret_cast<const char*>(protectedBuffer.get()), resultLen); + if (_out->fail()) { + severe() << "Couldn't write finalized DataProtector data to: " << _file.string() + << " for remove saving: " << redact(errnoWithDescription()); + fassertFailed(34351); + } + + protectedBuffer.reset(new uint8_t[protectedSizeMax]); + status = _protector->finalizeTag(protectedBuffer.get(), protectedSizeMax, &resultLen); + if (!status.isOK()) { + severe() << "Unable to get finalizeTag from DataProtector while closing RemoveSaver: " + << redact(status); + fassertFailed(34352); + } + + if (resultLen != _protector->getNumberOfBytesReservedForTag()) { + severe() << "Attempted to write tag of size " << resultLen + << " when DataProtector only reserved " + << _protector->getNumberOfBytesReservedForTag() << " bytes"; + fassertFailed(34353); + } + + _out->seekp(0); + _out->write(reinterpret_cast<const char*>(protectedBuffer.get()), resultLen); + + if (_out->fail()) { + severe() << "Couldn't write finalizeTag from DataProtector to: " << _file.string() + << " for remove saving: " << redact(errnoWithDescription()); + fassertFailed(34354); + } + } +} + +Status RemoveSaver::goingToDelete(const BSONObj& o) { + if (!_out) { + // We don't expect to ever pass "" to create_directories below, but catch + // this anyway as per SERVER-26412. + invariant(!_root.empty()); + boost::filesystem::create_directories(_root); + _out.reset(new ofstream(_file.string().c_str(), ios_base::out | ios_base::binary)); + + if (_out->fail()) { + string msg = str::stream() << "couldn't create file: " << _file.string() + << " for remove saving: " << redact(errnoWithDescription()); + error() << msg; + _out.reset(); + _out = 0; + return Status(ErrorCodes::FileNotOpen, msg); + } + } + + const uint8_t* data = reinterpret_cast<const uint8_t*>(o.objdata()); + size_t dataSize = o.objsize(); + + std::unique_ptr<uint8_t[]> protectedBuffer; + if (_protector) { + auto encryptionHooks = EncryptionHooks::get(getGlobalServiceContext()); + invariant(encryptionHooks->enabled()); + + size_t protectedSizeMax = dataSize + encryptionHooks->additionalBytesForProtectedBuffer(); + protectedBuffer.reset(new uint8_t[protectedSizeMax]); + + size_t resultLen; + Status status = _protector->protect( + data, dataSize, protectedBuffer.get(), protectedSizeMax, &resultLen); + + if (!status.isOK()) { + return status; + } + + data = protectedBuffer.get(); + dataSize = resultLen; + } + + _out->write(reinterpret_cast<const char*>(data), dataSize); + + if (_out->fail()) { + string msg = str::stream() << "couldn't write document to file: " << _file.string() + << " for remove saving: " << redact(errnoWithDescription()); + error() << msg; + return Status(ErrorCodes::OperationFailed, msg); + } + + return Status::OK(); +} + +} // namespace mongo diff --git a/src/mongo/db/storage/remove_saver.h b/src/mongo/db/storage/remove_saver.h new file mode 100644 index 00000000000..78057622444 --- /dev/null +++ b/src/mongo/db/storage/remove_saver.h @@ -0,0 +1,85 @@ + +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * 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 Server Side 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/filesystem/path.hpp> +#include <memory> +#include <ostream> +#include <string> + +#include "mongo/base/disallow_copying.h" +#include "mongo/base/status.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/storage/data_protector.h" + +namespace mongo { + +/** + * for saving deleted bson objects to a flat file + */ +class RemoveSaver { + MONGO_DISALLOW_COPYING(RemoveSaver); + +public: + RemoveSaver(const std::string& type, const std::string& ns, const std::string& why); + ~RemoveSaver(); + + /** + * Writes document to file. File is created lazily before writing the first document. + * Returns error status if the file could not be created or if there were errors writing + * to the file. + */ + Status goingToDelete(const BSONObj& o); + + /** + * A path object describing the directory containing the file with deleted documents. + */ + const auto& root() const& { + return _root; + } + void root() && = delete; + + /** + * A path object describing the actual file containing BSON documents. + */ + const auto& file() const& { + return _file; + } + void file() && = delete; + +private: + boost::filesystem::path _root; + boost::filesystem::path _file; + std::unique_ptr<DataProtector> _protector; + std::unique_ptr<std::ostream> _out; +}; + +} // namespace mongo |