Browse Source

Delay db insert to avoid deadlock (#55)

When using `get_map_or` it is not allowed to change the database state
inside the callback or it may endup in a database deadlock.

This PR fixes that situation for `lmove`
César D. Rodas 2 years ago
parent
commit
70ca07f177
3 changed files with 22 additions and 8 deletions
  1. 10 2
      .github/workflows/ci.yml
  2. 1 1
      Makefile
  3. 11 5
      src/cmd/list.rs

+ 10 - 2
.github/workflows/ci.yml

@@ -15,8 +15,16 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - uses: actions/checkout@v3
-    - name: test
+    - name: prepare
       run: |
         rustup component add clippy
         sudo apt-get install tcl8.6 tclx
-        make ci
+    - name: Fmt
+      run: make fmt
+    - name: Clippy
+      run: make clippy
+    - name: Unit test
+      run: make unit-test
+    - name: Test
+      run: make test
+

+ 1 - 1
Makefile

@@ -1,5 +1,5 @@
 fmt:
-	cargo fmt
+	cargo fmt --check
 clippy:
 	cargo clippy --release
 build:

+ 11 - 5
src/cmd/list.rs

@@ -427,6 +427,8 @@ pub async fn lmove(conn: &Connection, args: &[Bytes]) -> Result<Value, Error> {
     /// Lock keys to alter exclusively
     db.lock_keys(&args[1..=2]);
 
+    let mut to_create = None;
+
     let result = db.get_map_or(
         &args[1],
         |v| match v {
@@ -466,7 +468,7 @@ pub async fn lmove(conn: &Connection, args: &[Bytes]) -> Result<Value, Error> {
                         let ret = element.clone_value();
                         let mut h = VecDeque::new();
                         h.push_front(element);
-                        conn.db().set(&args[2], h.into(), None);
+                        to_create = Some(h);
                         Ok(ret)
                     } else {
                         Ok(Value::Null)
@@ -478,6 +480,10 @@ pub async fn lmove(conn: &Connection, args: &[Bytes]) -> Result<Value, Error> {
         || Ok(Value::Null),
     );
 
+    if let Some(to_create) = to_create {
+        conn.db().set(&args[2], to_create.into(), None);
+    }
+
     /// release the lock on keys
     db.unlock_keys(&args[1..=2]);
 
@@ -1370,17 +1376,17 @@ mod test {
 
         assert_eq!(
             Ok(Value::Blob("1".into())),
-            run_command(&c, &["lmove", "foo", "bar", "left", "left"]).await
+            run_command(&c, &["lmove", "foo", "foo-668", "left", "left"]).await
         );
 
         assert_eq!(
             Ok(Value::Array(vec![Value::Blob("1".into()),])),
-            run_command(&c, &["lrange", "bar", "0", "-1"]).await
+            run_command(&c, &["lrange", "foo-668", "0", "-1"]).await
         );
 
         assert_eq!(
             Ok(Value::Blob("5".into())),
-            run_command(&c, &["lmove", "foo", "bar", "right", "left"]).await
+            run_command(&c, &["lmove", "foo", "foo-668", "right", "left"]).await
         );
 
         assert_eq!(
@@ -1388,7 +1394,7 @@ mod test {
                 Value::Blob("5".into()),
                 Value::Blob("1".into()),
             ])),
-            run_command(&c, &["lrange", "bar", "0", "-1"]).await
+            run_command(&c, &["lrange", "foo-668", "0", "-1"]).await
         );
     }