1

I'm trying to build a nagios check to check for how long a mongoDB has been locked using fsyncLock() for backup purposes (if the iSCSI snapshotting script blows up and the mongo is not being unlocked for example)

I was thinking about using a simple

    $currentLock->run_command({currentOp => 1})
    $isLocked = $currentLock->{fsyncLock}

But it seems like run_command() doesn't support currentOp yet. (As seen in there: https://github.com/MLstate/opalang/blob/master/lib/stdlib/apis/mongo/commands.opa)

Woudl anybody have an advice on how to check if a mongo is locked with a perl script? If not, I guess I'll go for some bash. I was thinking about using a db.eval('db.currentOp()') but I'm getting a bit lost.

Thanks!

Alb Dum
  • 1,121
  • 3
  • 11
  • 26

2 Answers2

2

You are right that run_command does not support doing a currentOp directly. However, if we look at the implementation of db.currentOp in the mongo shell, we can see how it works under the hood:

> db.currentOp
function (arg) {
    var q = {};
    if (arg) {
        if (typeof arg == "object") {
            Object.extend(q, arg);
        } else if (arg) {
            q.$all = true;
        }
    }
    return this.$cmd.sys.inprog.findOne(q);
}

So we can query the special collection $cmd.sys.inprog on the Perl side to get the same inprog array that would be returned in the shell.

use strict;
use warnings;

use MongoDB;

my $db = MongoDB::MongoClient->new->get_database( 'test' );
my $current_op = $db->get_collection( '$cmd.sys.inprog' )->find_one;

When the server is not locked, it will return a structure in $current_op that looks something like this:

{
      'inprog' => [
                  {
                    'connectionId' => 53,
                    'insert' => {},
                    'active' => bless( do{\(my $o = 0)}, 'boolean' ),
                    'lockStats' => {
                                   'timeAcquiringMicros' => {
                                                            'w' => 1,
                                                            'r' => 0
                                                          },
                                   'timeLockedMicros' => {
                                                         'w' => 9,
                                                         'r' => 0
                                                       }
                                 },
                    'numYields' => 0,
                    'locks' => {
                               '^' => 'w',
                               '^test' => 'W'
                             },
                    'waitingForLock' => $VAR1->{'inprog'}[0]{'active'},
                    'ns' => 'test.fnoof',
                    'client' => '127.0.0.1:50186',
                    'threadId' => '0x105a81000',
                    'desc' => 'conn53',
                    'opid' => 7152352,
                    'op' => 'insert'
                  }
                ]
    };

During an fsyncLock(), you'll get an empty inprog array but you will have a helpful info field and the expected fsyncLock boolean:

    {
      'info' => 'use db.fsyncUnlock() to terminate the fsync write/snapshot lock',
      'fsyncLock' => bless( do{\(my $o = 1)}, 'boolean' ),   # <--- that's true
      'inprog' => []
    };

So, putting it all together, we get:

use strict;
use warnings;

use MongoDB;

my $db = MongoDB::MongoClient->new->get_database( 'fnarf' );
my $current_op = $db->get_collection( '$cmd.sys.inprog' )->find_one;

if ( $current_op->{fsyncLock} ) {
    print "fsync lock is currently ON\n";
} else {
    print "fsync lock is currently OFF\n";
}
friedo
  • 65,762
  • 16
  • 114
  • 184
2

I actually decided to switch for a solution in bash (easier for what I want to do with the data later):

currentOp=`mongo --port $port --host $host --eval "printjson(db.currentOp())"`

Then some sort of grep -Po '"fsyncLock" : \d'

Thanks for the Perl insight though, it worked perfectly

Alb Dum
  • 1,121
  • 3
  • 11
  • 26