diff --git a/CHANGELOG.md b/CHANGELOG.md index 1542956e..dc1f9f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If - Branding: Stalwart logo flashes before the per-tenant logo is loaded on the login page. - Calendar: iMIP and alarm notification messages embed the default logo using bare `LF` line endings, producing a single 4247 octet line that strict SMTP relays reject with `line too long`. - DMARC: Failure reports state `Identity-Alignment: none` when a mechanism authenticated successfully but against an identity that is not aligned with the `From` domain. +- Redis: Task and queue locks are never released after a worker dies, because failed lock attempts refresh the lock expiry. - Recovery mode: Download WebUI if missing. - Logging: The systemd journal tracer omits the parent span's fields. - MTA: diff --git a/Cargo.lock b/Cargo.lock index d084df1b..37ab9733 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" dependencies = [ "cipher 0.5.2", "cpubits", @@ -248,9 +248,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8" dependencies = [ "compression-codecs", "compression-core", @@ -264,7 +264,7 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.1", + "event-listener 5.4.2", "event-listener-strategy", "pin-project-lite", ] @@ -356,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" dependencies = [ "base64 0.22.1", - "http 1.4.2", + "http 1.5.0", "log", "rustls", "serde", @@ -430,7 +430,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "itoa", @@ -454,7 +454,7 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "mime", @@ -580,6 +580,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9" + [[package]] name = "base64ct" version = "1.8.3" @@ -771,7 +777,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", "zeroize", ] @@ -790,7 +796,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" dependencies = [ - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", ] [[package]] @@ -830,7 +836,7 @@ dependencies = [ "futures-util", "hex", "home", - "http 1.4.2", + "http 1.5.0", "http-body-util", "hyper", "hyper-named-pipe", @@ -996,9 +1002,9 @@ dependencies = [ [[package]] name = "calcard" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88c4c9063026b3a2361859739f0a4dde1f62ea7bf860f70b76a30924fff0a88" +checksum = "f88e3f86628443fd0d5137a81b34c9d9e8373d902eb3dde30bf83b7b2aca2f8b" dependencies = [ "ahash", "chrono", @@ -1213,9 +1219,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ "glob", "libc", @@ -1336,6 +1342,7 @@ dependencies = [ "sha2 0.11.0", "sieve-rs", "smtp-proto", + "socket2 0.6.5", "store", "tinyvec", "tokio", @@ -1636,7 +1643,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", "rand_core 0.10.1", ] @@ -2104,13 +2111,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -2124,17 +2131,17 @@ dependencies = [ [[package]] name = "dns-update" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c07b2767be6aead1916e05cc9a655c7d34737eb071cda3f05f67031b29891c8" +checksum = "80a322effc9082d62e1e0a46ac98ef9e1d3b168997174fc6ad9a49c39e1daefe" dependencies = [ "aws-lc-rs", - "base64 0.22.1", + "base64 0.23.0", "chrono", "hex", "hickory-net", "hickory-proto", - "quick-xml 0.40.1", + "quick-xml 0.41.0", "reqwest 0.13.4", "rustls", "serde", @@ -2296,7 +2303,7 @@ dependencies = [ name = "email" version = "0.16.16" dependencies = [ - "aes 0.9.1", + "aes 0.9.2", "aes-gcm", "aes-gcm-siv", "cbc 0.2.1", @@ -2384,11 +2391,10 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -2399,7 +2405,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener 5.4.2", "pin-project-lite", ] @@ -2584,7 +2590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3757d8523a60f4d3516a018e767cd3bea0829a43045d290ace16dcc92ac4f4cd" dependencies = [ "bytes", - "http 1.4.2", + "http 1.5.0", "httparse", "memchr", "mime", @@ -2942,7 +2948,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.2", + "http 1.5.0", "indexmap 2.14.0", "slab", "tokio", @@ -3053,7 +3059,7 @@ dependencies = [ "futures-util", "h2", "hickory-proto", - "http 1.4.2", + "http 1.5.0", "idna", "ipnet", "jni", @@ -3239,9 +3245,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -3254,7 +3260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", - "http 1.4.2", + "http 1.5.0", ] [[package]] @@ -3265,7 +3271,7 @@ checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", - "http 1.4.2", + "http 1.5.0", "http-body", "pin-project-lite", ] @@ -3336,9 +3342,9 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" dependencies = [ "ctutils", "typenum", @@ -3356,7 +3362,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.2", + "http 1.5.0", "http-body", "httparse", "httpdate", @@ -3387,7 +3393,7 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.2", + "http 1.5.0", "hyper", "hyper-util", "rustls", @@ -3421,7 +3427,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.2", + "http 1.5.0", "http-body", "hyper", "ipnet", @@ -3727,7 +3733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ "block-padding 0.4.2", - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", ] [[package]] @@ -3754,9 +3760,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" dependencies = [ "serde", ] @@ -4240,9 +4246,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa" dependencies = [ "libc", ] @@ -4645,7 +4651,7 @@ checksum = "add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d" dependencies = [ "crypto-common 0.2.2", "ctutils", - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", "module-lattice", "shake", "signature 3.0.0", @@ -4658,7 +4664,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66" dependencies = [ - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", "kem", "module-lattice", "rand_core 0.10.1", @@ -4673,7 +4679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" dependencies = [ "ctutils", - "hybrid-array 0.4.13", + "hybrid-array 0.4.14", "num-traits", "zeroize", ] @@ -5167,7 +5173,7 @@ source = "git+https://github.com/stalwartlabs/opentelemetry-rust#274b4d324794280 dependencies = [ "async-trait", "bytes", - "http 1.4.2", + "http 1.5.0", "opentelemetry", "reqwest 0.13.4", ] @@ -5177,7 +5183,7 @@ name = "opentelemetry-otlp" version = "0.31.0" source = "git+https://github.com/stalwartlabs/opentelemetry-rust#274b4d324794280ce6f4def095a3428197a9e6e3" dependencies = [ - "http 1.4.2", + "http 1.5.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -5770,9 +5776,9 @@ dependencies = [ [[package]] name = "proc-macro-error-attr3" -version = "3.0.3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5bfc63c4dc85083c9daaf7112d0261701d4058677c3bff7f2afc44e30ef3e1" +checksum = "b0084e6206a967a2dad822180626b2f6b07a3b379325e8f1ec0438e33a469ba7" dependencies = [ "proc-macro2", "quote", @@ -5780,9 +5786,9 @@ dependencies = [ [[package]] name = "proc-macro-error3" -version = "3.0.3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0d42490f6b7b143eef32b9e3522e42bf25dadc02c69ed72236f80adb949b5c" +checksum = "0cf066225f2373bc711684792b69bdeac0356019b007e721090c24d92d5d5a50" dependencies = [ "proc-macro-error-attr3", "proc-macro2", @@ -5877,9 +5883,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.222" +version = "2.1.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fa2bb454bd1a4e046f36c4e8b60f034143ce14d09cfbf4608a65619e9f8611" +checksum = "c0dedad316e05de220cbf3fd8bfb69f3df8755dde2d7d479211827b595168a93" dependencies = [ "psl-types", ] @@ -5951,16 +5957,6 @@ dependencies = [ "serde", ] -[[package]] -name = "quick-xml" -version = "0.40.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "quick-xml" version = "0.41.0" @@ -5968,6 +5964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", + "serde", ] [[package]] @@ -6354,9 +6351,9 @@ dependencies = [ [[package]] name = "redis" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b9503711b03773e43b31668c7b5bd279ee7cd9b7d18cff7c23a42cc1d08e5a" +checksum = "3257df217f7eab0044627a268c9cc6cdb60c0c421c88f83ac41c4e31520b6b84" dependencies = [ "arcstr", "async-lock", @@ -6364,6 +6361,7 @@ dependencies = [ "cfg-if", "combine", "crc16", + "futures-channel", "futures-util", "itoa", "log", @@ -6489,7 +6487,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "hyper", @@ -6532,7 +6530,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "hyper", @@ -6760,7 +6758,7 @@ dependencies = [ "futures-util", "hex", "hmac 0.12.1", - "http 1.4.2", + "http 1.5.0", "log", "maybe-async", "md5", @@ -6828,9 +6826,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "aws-lc-rs", "log", @@ -6980,9 +6978,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" dependencies = [ "dyn-clone", "either", @@ -6994,14 +6992,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -7182,13 +7180,13 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -7252,7 +7250,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.2", "serde_core", "serde_json", "serde_with_macros", @@ -8127,7 +8125,7 @@ dependencies = [ "etcetera", "ferroid", "futures", - "http 1.4.2", + "http 1.5.0", "itertools 0.14.0", "log", "memchr", @@ -8270,9 +8268,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "js-sys", @@ -8376,13 +8374,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -8474,7 +8472,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "http 1.4.2", + "http 1.5.0", "httparse", "rand 0.8.7", "rustls-pki-types", @@ -8507,9 +8505,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ "winnow", ] @@ -8525,7 +8523,7 @@ dependencies = [ "base64 0.22.1", "bytes", "h2", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "hyper", @@ -8612,7 +8610,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.4.2", + "http 1.5.0", "http-body", "http-body-util", "pin-project-lite", @@ -8751,7 +8749,7 @@ checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.4.2", + "http 1.5.0", "httparse", "log", "rand 0.9.5", @@ -8966,7 +8964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64 0.22.1", - "http 1.4.2", + "http 1.5.0", "httparse", "log", ] @@ -9876,7 +9874,7 @@ dependencies = [ "hashbrown 0.16.1", "keyed-set", "rand 0.8.7", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "token-cell", "zenoh-result", @@ -10117,7 +10115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9588f87db82b414a3e73d13312026be826332f53d270966e3e19f77f7fa1f06d" dependencies = [ "arc-swap", - "event-listener 5.4.1", + "event-listener 5.4.2", "futures", "tokio", "zenoh-buffers", @@ -10189,7 +10187,7 @@ dependencies = [ "libc", "libloading", "pnet_datalink", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "serde_json", "shellexpand", @@ -10322,7 +10320,7 @@ version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ - "aes 0.9.1", + "aes 0.9.2", "bzip2", "constant_time_eq 0.4.2", "crc32fast", diff --git a/crates/store/src/backend/composite/sharded_lookup.rs b/crates/store/src/backend/composite/sharded_lookup.rs index bfc7ff1e..4196ff18 100644 --- a/crates/store/src/backend/composite/sharded_lookup.rs +++ b/crates/store/src/backend/composite/sharded_lookup.rs @@ -85,6 +85,19 @@ impl ShardedInMemory { .await } + #[allow(unused_variables)] + pub async fn try_lock(&self, key: &[u8], expires: u64) -> trc::Result { + Box::pin(async move { + match self.get_store(key) { + #[cfg(feature = "redis")] + InMemoryStore::Redis(store) => store.try_lock(key, expires).await, + InMemoryStore::Static(_) => Err(trc::StoreEvent::NotSupported.into_err()), + _ => Err(trc::StoreEvent::NotSupported.into_err()), + } + }) + .await + } + pub async fn key_delete(&self, key: impl Into>) -> trc::Result<()> { let key_ = key.into(); let key = key_.as_bytes(); diff --git a/crates/store/src/backend/redis/lookup.rs b/crates/store/src/backend/redis/lookup.rs index 079c3b9e..9f681d95 100644 --- a/crates/store/src/backend/redis/lookup.rs +++ b/crates/store/src/backend/redis/lookup.rs @@ -5,7 +5,7 @@ */ use super::{RedisPool, RedisStore, into_error}; -use crate::Deserialize; +use crate::{Deserialize, write::now}; use redis::AsyncCommands; impl RedisStore { @@ -73,6 +73,23 @@ impl RedisStore { } } + pub async fn try_lock(&self, key: &[u8], expires: u64) -> trc::Result { + match &self.pool { + RedisPool::Single(pool) => { + self.try_lock_(pool.get().await.map_err(into_error)?.as_mut(), key, expires) + .await + } + RedisPool::Cluster(pool) => { + self.try_lock_(pool.get().await.map_err(into_error)?.as_mut(), key, expires) + .await + } + RedisPool::Sentinel(pool) => { + self.try_lock_(pool.get().await.map_err(into_error)?.as_mut(), key, expires) + .await + } + } + } + pub async fn key_delete(&self, key: &[u8]) -> trc::Result<()> { match &self.pool { RedisPool::Single(pool) => { @@ -227,6 +244,24 @@ impl RedisStore { } } + async fn try_lock_( + &self, + conn: &mut impl AsyncCommands, + key: &[u8], + expires: u64, + ) -> trc::Result { + redis::cmd("SET") + .arg(key) + .arg(now() + expires) + .arg("NX") + .arg("EX") + .arg(expires as i64) + .query_async::>(conn) + .await + .map(|reply| reply.is_some()) + .map_err(into_error) + } + async fn key_delete_(&self, conn: &mut impl AsyncCommands, key: &[u8]) -> trc::Result<()> { conn.del(key).await.map_err(into_error) } diff --git a/crates/store/src/dispatch/lookup.rs b/crates/store/src/dispatch/lookup.rs index ba228432..1c800d3c 100644 --- a/crates/store/src/dispatch/lookup.rs +++ b/crates/store/src/dispatch/lookup.rs @@ -383,18 +383,20 @@ impl InMemoryStore { } } #[cfg(feature = "redis")] - InMemoryStore::Redis(store) => store - .key_incr(&KeyValue::<()>::build_key(prefix, key), 1, duration.into()) - .await - .map(|count| count == 1), + InMemoryStore::Redis(store) => { + store + .try_lock(&KeyValue::<()>::build_key(prefix, key), duration) + .await + } // SPDX-SnippetBegin // SPDX-FileCopyrightText: 2020 Stalwart Labs LLC // SPDX-License-Identifier: LicenseRef-SEL #[cfg(feature = "enterprise")] - InMemoryStore::Sharded(store) => store - .counter_incr(KeyValue::with_prefix(prefix, key, 1).expires(duration)) - .await - .map(|count| count == 1), + InMemoryStore::Sharded(store) => { + store + .try_lock(&KeyValue::<()>::build_key(prefix, key), duration) + .await + } // SPDX-SnippetEnd InMemoryStore::Static(_) | InMemoryStore::Http(_) => { Err(trc::StoreEvent::NotSupported.into_err()) diff --git a/tests/src/store/lookup.rs b/tests/src/store/lookup.rs index c0d0ec31..eb3c478c 100644 --- a/tests/src/store/lookup.rs +++ b/tests/src/store/lookup.rs @@ -144,6 +144,20 @@ pub async fn lookup_tests() { tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; } store.purge_in_memory_store().await.unwrap(); + + // Failed lock attempts must not extend the lock expiry + assert!(store.try_lock(0, "lock".as_bytes(), 2).await.unwrap()); + let mut acquired = false; + for _ in 0..12 { + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + if store.try_lock(0, "lock".as_bytes(), 2).await.unwrap() { + acquired = true; + break; + } + } + assert!(acquired, "Abandoned lock was never released"); + store.remove_lock(0, "lock".as_bytes()).await.unwrap(); + store.purge_in_memory_store().await.unwrap(); if let InMemoryStore::Store(store) = &store { store_assert_is_empty(store, store.clone().into(), false).await; }