jstests/concurrency/fsm_libs/fsm.js
// args.iterations = number of iterations to run the FSM for
args.iterations = number of iterations to run the FSM for
args . iterations = number of iterations to run the FSM for
function runFSM(args) {
        if (TestData.runInsideTransaction) {
            let overridePath = "jstests/libs/override_methods/";
            load(overridePath + "check_for_operation_not_supported_in_transaction.js");
            load("jstests/concurrency/fsm_workload_helpers/auto_retry_transaction.js");
            load("jstests/libs/transactions_util.js");
        }
        var currentState = args.startState;
        var connCache;
        if (args.passConnectionCache) {
            const makeNewConnWithExistingSession = function(connStr) {
                const conn = connect(connStr).getMongo();
                conn._defaultSession = new _DelegatingDriverSession(conn, args.db.getSession());
                return conn;
            };
            const getReplSetName = (conn) => {
                let res;
                assert.soonNoExcept(
                    () => {
                        res = conn.getDB('admin').runCommand({isMaster: 1});
                        return true;
                    },
                    "Failed to establish a connection to the replica set",
                    undefined,  
                    2 * 1000);  
                assert.commandWorked(res);
                assert.eq('string',
                          typeof res.setName,
                          () => `not connected to a replica set: ${tojson(res)}`);
                return res.setName;
            };
            const makeReplSetConnWithExistingSession = (connStrList, replSetName) => {
                const conn = makeNewConnWithExistingSession(`mongodb://${
                    connStrList.join(',')}/?appName=tid:${args.tid}&replicaSet=${replSetName}`);
                return conn;
            };
            connCache =
                {mongos: [], config: [], shards: {}, rsConns: {config: undefined, shards: {}}};
            connCache.mongos = args.cluster.mongos.map(makeNewConnWithExistingSession);
            connCache.config = args.cluster.config.map(makeNewConnWithExistingSession);
            connCache.rsConns.config = makeReplSetConnWithExistingSession(
                args.cluster.config, getReplSetName(connCache.config[0]));
            connCache.rsConns.config._isConfigServer = true;
            var shardNames = Object.keys(args.cluster.shards);
            shardNames.forEach(name => {
                connCache.shards[name] =
                    args.cluster.shards[name].map(makeNewConnWithExistingSession);
                connCache.rsConns.shards[name] = makeReplSetConnWithExistingSession(
                    args.cluster.shards[name], getReplSetName(connCache.shards[name][0]));
            });
        }
        for (var i = 0; i < args.iterations; ++i) {
            var fn = args.states[currentState];
            assert.eq('function', typeof fn, 'states.' + currentState + ' is not a function');
            if (TestData.runInsideTransaction) {
                try {
                    let data;
                    withTxnAndAutoRetry(args.db.getSession(), () => {
                        data = TransactionsUtil.deepCopyObject({}, args.data);
                        data[kIsRunningInsideTransaction] = true;
                        fn.call(data, args.db, args.collName, connCache);
                    }, {retryOnKilledSession: args.data.retryOnKilledSession});
                    delete data[kIsRunningInsideTransaction];
                    args.data = data;
                } catch (e) {
                    if (!e.isNotSupported) {
                        throw e;
                    }
                    fn.call(args.data, args.db, args.collName, connCache);
                }
            } else {
                fn.call(args.data, args.db, args.collName, connCache);
            }
            var nextState = getWeightedRandomChoice(args.transitions[currentState], Random.rand());
            currentState = nextState;
        }
        if (args.passConnectionCache) {
            connCache = null;
            gc();
        }
    }
function runFSM ( args ) { if ( TestData . runInsideTransaction ) { let overridePath = "jstests/libs/override_methods/" ; load ( overridePath + "check_for_operation_not_supported_in_transaction.js" ) ; load ( "jstests/concurrency/fsm_workload_helpers/auto_retry_transaction.js" ) ; load ( "jstests/libs/transactions_util.js" ) ; } var currentState = args . startState ; var connCache ; if ( args . passConnectionCache ) { const makeNewConnWithExistingSession = function ( connStr ) { const conn = connect ( connStr ) . getMongo ( ) ; conn . _defaultSession = new _DelegatingDriverSession ( conn , args . db . getSession ( ) ) ; return conn ; } ; const getReplSetName = ( conn ) => { let res ; assert . soonNoExcept ( ( ) => { res = conn . getDB ( 'admin' ) . runCommand ( { isMaster : 1 } ) ; return true ; } , "Failed to establish a connection to the replica set" , undefined , 2 * 1000 ) ; assert . commandWorked ( res ) ; assert . eq ( 'string' , typeof res . setName , ( ) => ` ${ tojson ( res ) } ` ) ; return res . setName ; } ; const makeReplSetConnWithExistingSession = ( connStrList , replSetName ) => { const conn = makeNewConnWithExistingSession ( ` ${ connStrList . join ( ',' ) } ${ args . tid } ${ replSetName } ` ) ; return conn ; } ; connCache = { mongos : [ ] , config : [ ] , shards : { } , rsConns : { config : undefined , shards : { } } } ; connCache . mongos = args . cluster . mongos . map ( makeNewConnWithExistingSession ) ; connCache . config = args . cluster . config . map ( makeNewConnWithExistingSession ) ; connCache . rsConns . config = makeReplSetConnWithExistingSession ( args . cluster . config , getReplSetName ( connCache . config [ 0 ] ) ) ; connCache . rsConns . config . _isConfigServer = true ; var shardNames = Object . keys ( args . cluster . shards ) ; shardNames . forEach ( name => { connCache . shards [ name ] = args . cluster . shards [ name ] . map ( makeNewConnWithExistingSession ) ; connCache . rsConns . shards [ name ] = makeReplSetConnWithExistingSession ( args . cluster . shards [ name ] , getReplSetName ( connCache . shards [ name ] [ 0 ] ) ) ; } ) ; } for ( var i = 0 ; i < args . iterations ; ++ i ) { var fn = args . states [ currentState ] ; assert . eq ( 'function' , typeof fn , 'states.' + currentState + ' is not a function' ) ; if ( TestData . runInsideTransaction ) { try { let data ; withTxnAndAutoRetry ( args . db . getSession ( ) , ( ) => { data = TransactionsUtil . deepCopyObject ( { } , args . data ) ; data [ kIsRunningInsideTransaction ] = true ; fn . call ( data , args . db , args . collName , connCache ) ; } , { retryOnKilledSession : args . data . retryOnKilledSession } ) ; delete data [ kIsRunningInsideTransaction ] ; args . data = data ; } catch ( e ) { if ( ! e . isNotSupported ) { throw e ; } fn . call ( args . data , args . db , args . collName , connCache ) ; } } else { fn . call ( args . data , args . db , args . collName , connCache ) ; } var nextState = getWeightedRandomChoice ( args . transitions [ currentState ] , Random . rand ( ) ) ; currentState = nextState ; } if ( args . passConnectionCache ) { connCache = null ; gc ( ) ; } }
args.iterations = number of iterations to run the FSM for
args . iterations = number of iterations to run the FSM for
// We build a cache of connections that can be used in workload states. This cache // allows state functions to access arbitrary cluster nodes for verification checks. // See fsm_libs/cluster.js for the format of args.cluster. // In order to ensure that all operations performed by a worker thread happen on the // same session, we override the "_defaultSession" property of the connections in the // cache to be the same as the session underlying 'args.db'. // We may fail to connect if the continuous stepdown thread had just terminated // or killed a primary. We therefore use the connect() function defined in // network_error_and_transaction_override.js to add automatic retries to // connections. The override is loaded in worker_thread.js. // default timeout is 10 mins // retry on a 2 second interval // We set _isConfigServer=true on the Mongo connection object so // set_read_preference_secondary.js knows to avoid overriding the read preference as the // concurrency suite may be running with a 1-node CSRS. // We make a deep copy of 'args.data' before running the state function in a // transaction so that if the transaction aborts, then we haven't speculatively // modified the thread-local state. // Retry state functions that threw OperationNotSupportedInTransaction or // InvalidOptions errors outside of a transaction. Rethrow any other error. // e.isNotSupported added by check_for_operation_not_supported_in_transaction.js // Null out the workload connection cache and perform garbage collection to clean up, // i.e., close, the open connections.