// SERVER-21305: reported lock times are way too high. // // This test uses the fsync command to induce locking. // @tags: [requires_fsync] (function() { 'use strict'; function testBlockTime(blockTimeMillis) { // Lock the database, and in parallel start an operation that needs the lock, so it blocks. assert.commandWorked(db.fsyncLock()); var startStats = db.serverStatus().locks.Global; var startTime = new Date(); var minBlockedMillis = blockTimeMillis; let awaitSleepCmd = startParallelShell(() => { assert.commandWorked( db.adminCommand({sleep: 1, millis: 100, lock: "w", $comment: "Lock sleep"})); }, conn.port); // Wait until we see somebody waiting to acquire the lock, defend against unset stats. assert.soon((function() { var stats = db.serverStatus().locks.Global; if (!stats.acquireWaitCount || !stats.acquireWaitCount.W) return false; if (!stats.timeAcquiringMicros || !stats.timeAcquiringMicros.W) return false; if (!startStats.acquireWaitCount || !startStats.acquireWaitCount.W) return true; return stats.acquireWaitCount.W > startStats.acquireWaitCount.W; })); // Sleep for minBlockedMillis, so the acquirer would have to wait at least that long. sleep(minBlockedMillis); db.fsyncUnlock(); awaitSleepCmd(); // The fsync command from the shell cannot have possibly been blocked longer than this. var maxBlockedMillis = new Date() - startTime; var endStats = db.serverStatus().locks.Global; // The server was just started, so initial stats may be missing. if (!startStats.acquireWaitCount || !startStats.acquireWaitCount.W) { startStats.acquireWaitCount = {W: 0}; } if (!startStats.timeAcquiringMicros || !startStats.timeAcquiringMicros.W) { startStats.timeAcquiringMicros = {W: 0}; } var acquireWaitCount = endStats.acquireWaitCount.W - startStats.acquireWaitCount.W; var blockedMillis = Math.floor((endStats.timeAcquiringMicros.W - startStats.timeAcquiringMicros.W) / 1000); // Require that no other commands run (and maybe acquire locks) in parallel. assert.eq(acquireWaitCount, 1, "other commands ran in parallel, can't check timing"); assert.gte(blockedMillis, minBlockedMillis, "reported time acquiring lock is too low"); assert.lte(blockedMillis, maxBlockedMillis, "reported time acquiring lock is too high"); return ({ blockedMillis: blockedMillis, minBlockedMillis: minBlockedMillis, maxBlockedMillis: maxBlockedMillis }); } var conn = MongoRunner.runMongod(); var db = conn.getDB('test'); printjson([1, 10, 100, 500, 1000, 1500].map(testBlockTime)); MongoRunner.stopMongod(conn); })();