diff options
Diffstat (limited to 'src/mongo/db/storage/mmap_v1/dur.h')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/dur.h | 352 |
1 files changed, 164 insertions, 188 deletions
diff --git a/src/mongo/db/storage/mmap_v1/dur.h b/src/mongo/db/storage/mmap_v1/dur.h index 9b135ff78e9..c296ae4ad9b 100644 --- a/src/mongo/db/storage/mmap_v1/dur.h +++ b/src/mongo/db/storage/mmap_v1/dur.h @@ -1,38 +1,35 @@ -// @file dur.h durability support - /** -* Copyright (C) 2009 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/>. -* -* 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. -*/ + * 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 "mongo/db/storage/mmap_v1/durable_mapped_file.h" - namespace mongo { class OperationContext; @@ -40,188 +37,167 @@ namespace mongo { void mongoAbort(const char *msg); void abort(); // not defined -- use mongoAbort() instead - namespace dur { - // a smaller limit is likely better on 32 bit - const unsigned UncommittedBytesLimit = (sizeof(void*)==4) ? 50 * 1024 * 1024 : 512 * 1024 * 1024; +namespace dur { + + // a smaller limit is likely better on 32 bit + const unsigned UncommittedBytesLimit = (sizeof(void*) == 4) ? 50 * 1024 * 1024 : 512 * 1024 * 1024; + + /** + * Called during startup so durability module can initialize and start the durability thread. + * Does nothing if storageGlobalParams.dur is false + */ + void startup(); + + + class DurableInterface { + MONGO_DISALLOW_COPYING(DurableInterface); + public: + + DurableInterface(); + virtual ~DurableInterface(); - /** Call during startup so durability module can initialize - Throws if fatal error - Does nothing if storageGlobalParams.dur is false + /** + * 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. */ - void startup(); + 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 writing...() is checked in _DEBUG 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. + + /** + * Declare intent to write to x for up to len. + * + * @return pointer where to write. + */ + virtual void* writingPtr(void *x, unsigned len) = 0; + + /** + * Declare write intent after write has been done. + */ + virtual void declareWriteIntent(void *x, unsigned len) = 0; - class DurableInterface : boost::noncopyable { - public: - virtual ~DurableInterface(); + /** + * Allows you to declare many write intents at once more efficiently than repeated calls + * to declareWriteIntent. + */ + virtual void declareWriteIntents( + const std::vector<std::pair<void*, unsigned> >& intents) = 0; - /** 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 because of crashing. + /** 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 void createdFile(const std::string& filename, unsigned long long len) = 0; + virtual bool awaitCommit() = 0; - /** Declarations of write intent. + /** Commit immediately. - Use these methods to declare "i'm about to write to x and it should be logged for redo." + Generally, you do not want to do this often, as highly granular committing may affect + performance. - Failure to call writing...() is checked in _DEBUG 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. - */ + Does not return until the commit is complete. - /** declare intent to write to x for up to len - @return pointer where to write. this is modified when testIntent is true. - */ - virtual void* writingPtr(void *x, unsigned len) = 0; + You must be at least read locked when you call this. Ideally, you are not write locked + and then read operations can occur concurrently. - /** declare write intent; should already be in the write view to work correctly when testIntent is true. - if you aren't, use writingPtr() instead. + 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 void declareWriteIntent(void *x, unsigned len) = 0; - - /** - * Allows you to declare many write intents at once more efficiently than repeated calls - * to declareWriteIntent. - */ - virtual void declareWriteIntents( - const std::vector<std::pair<void*, unsigned> >& intents) = 0; - - /** declare intent to write - @param ofs offset within buf at which we will write - @param len the length at ofs we will write - @return new buffer pointer. this is modified when testIntent is true. + 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 void* writingAtOffset(void *buf, unsigned ofs, unsigned len) = 0; - - /** declare intent to write - @param ranges vector of pairs representing ranges. Each pair - comprises an offset from buf where a range begins, then the - range length. - @return new buffer pointer. this is modified when testIntent is true. - */ - virtual void* writingRangesAtOffsets(void *buf, const std::vector< std::pair< long long, unsigned > > &ranges ) = 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 commitIfNeeded() = 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 bool awaitCommit() = 0; + virtual void commitAndStopDurThread() = 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; - /** Commit immediately. + /** + * Declare intent to write to x for sizeof(*x) + */ + template <typename T> + T* writing(T *x) { + return static_cast<T*>(writingPtr(x, sizeof(T))); + } - Generally, you do not want to do this often, as highly granular committing may affect - performance. - Does not return until the commit is complete. + static DurableInterface& getDur() { return *_impl; } - You must be at least read locked when you call this. Ideally, you are not write locked - and then read operations can occur concurrently. + private: - Do not use this. Use commitIfNeeded() instead. + // Needs to be able to enable/disable Durability + friend void startup(); - @return true if --dur is on. - @return false if --dur is off. (in which case there is action) - */ - virtual bool commitNow(OperationContext* txn) = 0; + static void enableDurability(); // makes _impl a DurableImpl - /** Commit if enough bytes have been modified. Current threshold is 50MB + static DurableInterface* _impl; // NonDurableImpl at startup() + }; - 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; - /** - * 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() = 0; + class NonDurableImpl : public DurableInterface { + public: + void* writingPtr(void *x, unsigned len); + void declareWriteIntent(void *, unsigned); + void declareWriteIntents(const std::vector<std::pair<void*, unsigned> >& intents) { } + void createdFile(const std::string& filename, unsigned long long len) { } + bool awaitCommit() { return false; } + bool commitNow(OperationContext* txn); + bool commitIfNeeded(); + void syncDataAndTruncateJournal(OperationContext* txn) {} + bool isDurable() const { return false; } + void commitAndStopDurThread() { } + }; - /** Declare write intent for an int */ - inline int& writingInt(int& d) { return *static_cast<int*>(writingPtr( &d, sizeof(d))); } + class DurableImpl : public DurableInterface { + public: + void* writingPtr(void *x, unsigned len); + void declareWriteIntent(void *, unsigned); + void declareWriteIntents(const std::vector<std::pair<void*, unsigned> >& intents); + void createdFile(const std::string& filename, unsigned long long len); + bool awaitCommit(); + bool commitNow(OperationContext* txn); + bool commitIfNeeded(); + void syncDataAndTruncateJournal(OperationContext* txn); + bool isDurable() const { return true; } + void commitAndStopDurThread(); + }; + +} // namespace dur - /** "assume i've already indicated write intent, let me write" - redeclaration is fine too, but this is faster. - */ - template <typename T> - inline - T* alreadyDeclared(T *x) { -#if defined(_TESTINTENT) - return (T*) DurableMappedFile::switchToPrivateView(x); -#else - return x; -#endif - } - - /** declare intent to write to x for sizeof(*x) */ - template <typename T> - inline - T* writing(T *x) { - return (T*) writingPtr(x, sizeof(T)); - } - - /** - * 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; } - - private: - static DurableInterface* _impl; // NonDurableImpl at startup() - static void enableDurability(); // makes _impl a DurableImpl - - // these need to be able to enable/disable Durability - friend void startup(); - }; // class DurableInterface - - class NonDurableImpl : public DurableInterface { - void* writingPtr(void *x, unsigned len); - void* writingAtOffset(void *buf, unsigned ofs, unsigned len) { return buf; } - void* writingRangesAtOffsets(void *buf, const std::vector< std::pair< long long, unsigned > > &ranges) { return buf; } - void declareWriteIntent(void *, unsigned); - void declareWriteIntents(const std::vector<std::pair<void*, unsigned> >& intents) {} - void createdFile(const std::string& filename, unsigned long long len) { } - bool awaitCommit() { return false; } - bool commitNow(OperationContext* txn); - bool commitIfNeeded(); - void syncDataAndTruncateJournal(OperationContext* txn) {} - bool isDurable() const { return false; } - void commitAndStopDurThread() { } - }; - - class DurableImpl : public DurableInterface { - void* writingPtr(void *x, unsigned len); - void* writingAtOffset(void *buf, unsigned ofs, unsigned len); - void* writingRangesAtOffsets(void *buf, const std::vector< std::pair< long long, unsigned > > &ranges); - void declareWriteIntent(void *, unsigned); - void declareWriteIntents(const std::vector<std::pair<void*, unsigned> >& intents); - void createdFile(const std::string& filename, unsigned long long len); - bool awaitCommit(); - bool commitNow(OperationContext* txn); - bool commitIfNeeded(); - void syncDataAndTruncateJournal(OperationContext* txn); - bool isDurable() const { return true; } - void commitAndStopDurThread(); - }; - - } // namespace dur inline dur::DurableInterface& getDur() { return dur::DurableInterface::getDur(); } -} + +} // namespace mongo |