summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/fsync.cpp
blob: 59c7a63410b6793c479068760a27911a103895a5 (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
// fsync.cpp

#include "mongo/db/d_concurrency.h"
#include "mongo/db/commands.h"
#include "mongo/db/dur.h"

namespace mongo {

    /* see unlockFsync() for unlocking:
       db.$cmd.sys.unlock.findOne()
    */
    class FSyncCommand : public Command {
        static const char* url() { return "http://www.mongodb.org/display/DOCS/fsync+Command"; }
    public:
        bool locked;
        SimpleMutex m; // protects locked var above
        FSyncCommand() : Command( "fsync" ), m("lockfsync") { locked=false; }
        virtual LockType locktype() const { return NONE; }
        virtual bool slaveOk() const { return true; }
        virtual bool adminOnly() const { return true; }
        virtual void help(stringstream& h) const { h << url(); }
        virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            bool sync = !cmdObj["async"].trueValue(); // async means do an fsync, but return immediately
            bool lock = cmdObj["lock"].trueValue();
            log() << "CMD fsync: sync:" << sync << " lock:" << lock << endl;
            if( lock ) {
                Lock::ThreadSpanningOp::setWLockedNongreedy();
                verify( !locked ); // impossible to get here if locked is true
                try { 
                    //uassert(12034, "fsync: can't lock while an unlock is pending", !unlockRequested);
                    uassert(12032, "fsync: sync option must be true when using lock", sync);
                    getDur().syncDataAndTruncateJournal();
                } catch(...) { 
                    Lock::ThreadSpanningOp::unsetW();
                    throw;
                }
                SimpleMutex::scoped_lock lk(m);
                Lock::ThreadSpanningOp::W_to_R();
                try {
                    MemoryMappedFile::flushAll(true);
                }
                catch(...) { 
                    Lock::ThreadSpanningOp::unsetR();
                    throw;
                }
                verify( !locked );
                locked = true;
                log() << "db is now locked for snapshotting, no writes allowed. db.fsyncUnlock() to unlock" << endl;
                log() << "    For more info see " << FSyncCommand::url() << endl;
                result.append("info", "now locked against writes, use db.fsyncUnlock() to unlock");
                result.append("seeAlso", url());
                Lock::ThreadSpanningOp::handoffR();
            }
            else {
                // the simple fsync command case
                if (sync) {
                    Lock::GlobalWrite w; // can this be GlobalRead? and if it can, it should be nongreedy.
                    getDur().commitNow();
                }
                // question : is it ok this is not in the dblock? i think so but this is a change from past behavior, 
                // please advise.
                result.append( "numFiles" , MemoryMappedFile::flushAll( sync ) );
            }
            return 1;
        }
    } fsyncCmd;

    bool lockedForWriting() { return fsyncCmd.locked; }

    // @return true if unlocked
    bool _unlockFsync() {
        SimpleMutex::scoped_lock lk(fsyncCmd.m);
        if( !fsyncCmd.locked ) { 
            return false;
        }
        fsyncCmd.locked = false;
        Lock::ThreadSpanningOp::unsetR();
        return true;
    }
}