Uploaded image for project: 'Rust Driver'
  1. Rust Driver
  2. RUST-714

Deadlock possible during retry

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Critical - P2 Critical - P2
    • 1.2.1, 2.0.0-alpha.1
    • Affects Version/s: 1.2.0, 2.0.0-alpha
    • Component/s: None
    • None

      The driver deadlocks when performing a retry when all connections are checked out from the pool. This is due to the fact that the connection used in the first attempt is not dropped before attempting the retry.

      repro:

      Unable to find source-code formatter for language: rust. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      #[cfg_attr(feature = "tokio-runtime", tokio::test(flavor = "multi_thread"))]
      #[cfg_attr(feature = "async-std-runtime", async_std::test)]
      async fn deadlock_test() {
          let _guard: RwLockWriteGuard<()> = LOCK.run_exclusively().await;
      
          let mut client_options = CLIENT_OPTIONS.clone();
          client_options.hosts.drain(1..);
          client_options.direct_connection = Some(true);
          client_options.repl_set_name = None;
          client_options.retry_reads = Some(true);
          client_options.max_pool_size = Some(1);
      
          let client = TestClient::with_options(Some(client_options.clone()), true).await;
          if !client.supports_fail_command().await {
              println!("skipping {} due to failCommand not being supported", "ok");
              return;
          }
      
          let collection = client.database("ok").collection("ok");
          collection.insert_one(doc! { "x": 1 }, None).await.unwrap();
      
          let options = FailCommandOptions::builder()
              .error_code(91)
              .build();
          let failpoint = FailPoint::fail_command(&["find"], FailPointMode::Times(1), Some(options));
          let _fp_guard = client.enable_failpoint(failpoint, None).await.unwrap();
      
          let mut tasks: Vec<AsyncJoinHandle<_>> = Vec::new();
          for _ in 0..2 {
              let coll = collection.clone();
              let task = RUNTIME
                  .spawn(async move { coll.find_one(doc! {}, None).await })
                  .unwrap();
              tasks.push(task);
          }
      
          futures::future::join_all(tasks)
              .await
              .into_iter()
              .collect::<Result<Vec<_>>>()
              .expect("all should succeeed");
      }
      

            Assignee:
            patrick.freed@mongodb.com Patrick Freed
            Reporter:
            patrick.freed@mongodb.com Patrick Freed
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: