This is an automated email from the ASF dual-hosted git repository.

piotr pushed a commit to branch improve_pat
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit 755434da8f69054179d53409dd3e40ee1425d607
Author: spetz <[email protected]>
AuthorDate: Sat Mar 29 12:22:02 2025 +0100

    fix(server): use dashmap for personal access tokens, log commit hash on 
startup
---
 Cargo.lock                                         | 120 ++++++++++++---------
 bench/Cargo.toml                                   |   4 +-
 bench/report/Cargo.toml                            |   2 +-
 cli/Cargo.toml                                     |   2 +-
 examples/Cargo.toml                                |   2 +-
 sdk/Cargo.toml                                     |   2 +-
 server/Cargo.toml                                  |   6 +-
 .../create_personal_access_token_handler.rs        |   3 +-
 server/src/binary/mapper.rs                        |   2 +-
 server/src/build.rs                                |   2 +
 .../commands/clean_personal_access_tokens.rs       |   7 +-
 server/src/http/mapper.rs                          |   4 +-
 server/src/http/personal_access_tokens.rs          |   4 +-
 server/src/main.rs                                 |   4 +
 .../personal_access_token.rs                       |  22 ++--
 server/src/streaming/systems/info.rs               |   5 +-
 .../streaming/systems/personal_access_tokens.rs    |  41 +++----
 server/src/streaming/systems/storage.rs            |   2 +-
 server/src/streaming/systems/users.rs              |   5 +-
 server/src/streaming/users/user.rs                 |  10 +-
 tools/Cargo.toml                                   |   2 +-
 21 files changed, 140 insertions(+), 111 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 6cef1ac5..a065d3c4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -467,11 +467,11 @@ dependencies = [
 
 [[package]]
 name = "axum"
-version = "0.8.1"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
+checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288"
 dependencies = [
- "axum-core 0.5.0",
+ "axum-core 0.5.2",
  "bytes",
  "form_urlencoded",
  "futures-util",
@@ -521,12 +521,12 @@ dependencies = [
 
 [[package]]
 name = "axum-core"
-version = "0.5.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
+checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
 dependencies = [
  "bytes",
- "futures-util",
+ "futures-core",
  "http 1.3.1",
  "http-body 1.0.1",
  "http-body-util",
@@ -619,7 +619,7 @@ dependencies = [
  "integration",
  "nonzero_lit",
  "serde",
- "sysinfo",
+ "sysinfo 0.34.1",
  "tokio",
  "toml",
  "tracing",
@@ -754,9 +754,9 @@ dependencies = [
 
 [[package]]
 name = "borsh"
-version = "1.5.6"
+version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b2b74d67a0fc0af8e9823b79fd1c43a0900e5a8f0e0f4cc9210796bf3a820126"
+checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
 dependencies = [
  "borsh-derive",
  "cfg_aliases",
@@ -764,9 +764,9 @@ dependencies = [
 
 [[package]]
 name = "borsh-derive"
-version = "1.5.6"
+version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2d37ed1b2c9b78421218a0b4f6d8349132d6ec2cfeba1cfb0118b0a8e268df9e"
+checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3"
 dependencies = [
  "once_cell",
  "proc-macro-crate",
@@ -981,9 +981,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.32"
+version = "4.5.34"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
+checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -991,9 +991,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.32"
+version = "4.5.34"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
+checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
 dependencies = [
  "anstream",
  "anstyle",
@@ -1333,9 +1333,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -1343,9 +1343,9 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
 dependencies = [
  "fnv",
  "ident_case",
@@ -1357,9 +1357,9 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.20.10"
+version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
 dependencies = [
  "darling_core",
  "quote",
@@ -1699,9 +1699,9 @@ dependencies = [
 
 [[package]]
 name = "event-listener-strategy"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
+checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
 dependencies = [
  "event-listener",
  "pin-project-lite",
@@ -1803,9 +1803,9 @@ dependencies = [
 
 [[package]]
 name = "fragile"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
+checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
 
 [[package]]
 name = "fs-err"
@@ -2392,9 +2392,9 @@ dependencies = [
 
 [[package]]
 name = "icu_locid_transform_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
 
 [[package]]
 name = "icu_normalizer"
@@ -2416,9 +2416,9 @@ dependencies = [
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
 
 [[package]]
 name = "icu_properties"
@@ -2437,9 +2437,9 @@ dependencies = [
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
 
 [[package]]
 name = "icu_provider"
@@ -2557,7 +2557,7 @@ dependencies = [
  "human-repr",
  "serde",
  "serde_json",
- "sysinfo",
+ "sysinfo 0.34.1",
  "tracing",
  "uuid",
 ]
@@ -3278,6 +3278,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
+dependencies = [
+ "bitflags 2.9.0",
+]
+
 [[package]]
 name = "object"
 version = "0.36.7"
@@ -3289,9 +3298,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.21.1"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "opaque-debug"
@@ -3589,9 +3598,9 @@ checksum = 
"e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
+checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
 dependencies = [
  "memchr",
  "thiserror 2.0.12",
@@ -3600,9 +3609,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e"
+checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
 dependencies = [
  "pest",
  "pest_generator",
@@ -3610,9 +3619,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b"
+checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
 dependencies = [
  "pest",
  "pest_meta",
@@ -3623,9 +3632,9 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.7.15"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea"
+checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
 dependencies = [
  "once_cell",
  "pest",
@@ -3935,9 +3944,9 @@ dependencies = [
 
 [[package]]
 name = "quinn-udp"
-version = "0.5.10"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944"
+checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
 dependencies = [
  "cfg_aliases",
  "libc",
@@ -4474,9 +4483,9 @@ checksum = 
"f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
 
 [[package]]
 name = "rustls-webpki"
-version = "0.103.0"
+version = "0.103.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f"
+checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
 dependencies = [
  "aws-lc-rs",
  "ring",
@@ -4735,7 +4744,7 @@ dependencies = [
  "anyhow",
  "async_zip",
  "atone",
- "axum 0.8.1",
+ "axum 0.8.3",
  "axum-server",
  "bcrypt",
  "bincode",
@@ -4778,7 +4787,7 @@ dependencies = [
  "serde_with",
  "static-toml",
  "strum",
- "sysinfo",
+ "sysinfo 0.34.1",
  "tempfile",
  "thiserror 2.0.12",
  "tokio",
@@ -5027,6 +5036,19 @@ dependencies = [
  "windows 0.57.0",
 ]
 
+[[package]]
+name = "sysinfo"
+version = "0.34.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "927fa32067cbb22b8a91987d84c0ff94c7441ccf3f767165a58d77a656d6267c"
+dependencies = [
+ "libc",
+ "memchr",
+ "ntapi",
+ "objc2-core-foundation",
+ "windows 0.57.0",
+]
+
 [[package]]
 name = "system-configuration"
 version = "0.6.1"
@@ -5717,7 +5739,7 @@ dependencies = [
  "regex",
  "rustc_version",
  "rustversion",
- "sysinfo",
+ "sysinfo 0.33.1",
  "time",
  "vergen-lib",
 ]
diff --git a/bench/Cargo.toml b/bench/Cargo.toml
index 48062227..1f87ad91 100644
--- a/bench/Cargo.toml
+++ b/bench/Cargo.toml
@@ -29,7 +29,7 @@ atomic-time = "0.1.5"
 bytes = "1.10.1"
 charming = "0.4.0"
 chrono = "0.4.40"
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 figlet-rs = "0.1.5"
 hostname = "0.4.0"
 human-repr = "1.1.0"
@@ -38,7 +38,7 @@ iggy-bench-report = { path = "report" }
 integration = { path = "../integration" }
 nonzero_lit = "0.1.2"
 serde = { version = "1.0.219", features = ["derive"] }
-sysinfo = "0.33.1"
+sysinfo = "0.34.1"
 tokio = { version = "1.44.1", features = ["full"] }
 toml = "0.8.20"
 tracing = { version = "0.1.41" }
diff --git a/bench/report/Cargo.toml b/bench/report/Cargo.toml
index 2fcbb313..d6a62160 100644
--- a/bench/report/Cargo.toml
+++ b/bench/report/Cargo.toml
@@ -31,6 +31,6 @@ derive_more = { version = "2.0.1", features = ["full"] }
 human-repr = "1.1.0"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
-sysinfo = "0.33.1"
+sysinfo = "0.34.1"
 tracing = "0.1"
 uuid = { version = "1.16.0", features = ["serde"] }
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 08519a29..d184ee93 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -34,7 +34,7 @@ login-session = ["dep:keyring"]
 [dependencies]
 ahash = { version = "0.8.11", features = ["serde"] }
 anyhow = "1.0.97"
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 clap_complete = "4.5.47"
 figlet-rs = "0.1.5"
 iggy = { path = "../sdk", features = ["iggy-cli"], version = "0.6.210" }
diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 3c31a28f..efe3d0e8 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -93,7 +93,7 @@ path = "src/stream-builder/stream-producer-config/main.rs"
 ahash = { version = "0.8.11", features = ["serde"] }
 anyhow = "1.0.97"
 bytes = "1.10.1"
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 futures-util = "0.3.31"
 iggy = { path = "../sdk" }
 rand = "0.9.0"
diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml
index 5b378fb4..f9e79a12 100644
--- a/sdk/Cargo.toml
+++ b/sdk/Cargo.toml
@@ -44,7 +44,7 @@ byte-unit = { version = "5.1.6", default-features = false, 
features = [
 ] }
 bytes = "1.10.1"
 chrono = { version = "0.4.40" }
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 comfy-table = { version = "7.1.4", optional = true }
 crc32fast = "1.4.2"
 dashmap = "6.1.0"
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 8e067b6a..95902f46 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -40,14 +40,14 @@ async_zip = { version = "0.0.17", features = [
     "zstd",
 ] }
 atone = "0.3.7"
-axum = "0.8.1"
+axum = "0.8.3"
 axum-server = { version = "0.7.2", features = ["tls-rustls"] }
 bcrypt = "0.17.0"
 bincode = { version = "2.0.1", features = ["serde"] }
 blake3 = "1.7.0"
 bytes = "1.10.1"
 chrono = "0.4.40"
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 console-subscriber = { version = "0.4.1", optional = true }
 dashmap = "6.1.0"
 derive_more = "2.0.1"
@@ -101,7 +101,7 @@ serde_json = "1.0.140"
 serde_with = { version = "3.12.0", features = ["base64", "macros"] }
 static-toml = "1.3.0"
 strum = { version = "0.27.1", features = ["derive"] }
-sysinfo = "0.33.1"
+sysinfo = "0.34.1"
 tempfile = "3.19"
 thiserror = "2.0.12"
 tokio = { version = "1.44.1", features = ["full"] }
diff --git 
a/server/src/binary/handlers/personal_access_tokens/create_personal_access_token_handler.rs
 
b/server/src/binary/handlers/personal_access_tokens/create_personal_access_token_handler.rs
index aba35290..97b4acdc 100644
--- 
a/server/src/binary/handlers/personal_access_tokens/create_personal_access_token_handler.rs
+++ 
b/server/src/binary/handlers/personal_access_tokens/create_personal_access_token_handler.rs
@@ -38,7 +38,7 @@ pub async fn handle(
 ) -> Result<(), IggyError> {
     debug!("session: {session}, command: {command}");
 
-    let mut system = system.write().await;
+    let system = system.read().await;
     let token = system
             .create_personal_access_token(session, &command.name, 
command.expiry)
             .await
@@ -51,7 +51,6 @@ pub async fn handle(
     let bytes = mapper::map_raw_pat(&token);
     let token_hash = PersonalAccessToken::hash_token(&token);
 
-    let system = system.downgrade();
     system
         .state
         .apply(
diff --git a/server/src/binary/mapper.rs b/server/src/binary/mapper.rs
index d9fd65ce..1c6e1d4e 100644
--- a/server/src/binary/mapper.rs
+++ b/server/src/binary/mapper.rs
@@ -146,7 +146,7 @@ pub fn map_raw_pat(token: &str) -> Bytes {
     bytes.freeze()
 }
 
-pub fn map_personal_access_tokens(personal_access_tokens: 
&[&PersonalAccessToken]) -> Bytes {
+pub fn map_personal_access_tokens(personal_access_tokens: 
&[PersonalAccessToken]) -> Bytes {
     let mut bytes = BytesMut::new();
     for personal_access_token in personal_access_tokens {
         extend_pat(personal_access_token, &mut bytes);
diff --git a/server/src/build.rs b/server/src/build.rs
index 919a63ec..fd1129a1 100644
--- a/server/src/build.rs
+++ b/server/src/build.rs
@@ -42,6 +42,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
         );
     } else {
         println!("cargo:info=Skipping build script because CI environment 
variable IGGY_CI_BUILD is not set to 'true'");
+        let git2 = Git2Builder::default().sha(false).build()?;
+        Emitter::default().add_instructions(&git2)?.emit()?;
     }
 
     Ok(())
diff --git a/server/src/channels/commands/clean_personal_access_tokens.rs 
b/server/src/channels/commands/clean_personal_access_tokens.rs
index 787d639b..f3a07709 100644
--- a/server/src/channels/commands/clean_personal_access_tokens.rs
+++ b/server/src/channels/commands/clean_personal_access_tokens.rs
@@ -78,14 +78,13 @@ impl PersonalAccessTokenCleaner {
 impl ServerCommand<CleanPersonalAccessTokensCommand> for 
CleanPersonalAccessTokensExecutor {
     #[instrument(skip_all, name = "trace_clean_personal_access_tokens")]
     async fn execute(&mut self, system: &SharedSystem, _command: 
CleanPersonalAccessTokensCommand) {
-        // TODO: System write lock, investigate if it's necessary.
-        let mut system = system.write().await;
+        let system = system.read().await;
         let now = IggyTimestamp::now();
         let mut deleted_tokens_count = 0;
-        for (_, user) in system.users.iter_mut() {
+        for (_, user) in system.users.iter() {
             let expired_tokens = user
                 .personal_access_tokens
-                .values()
+                .iter()
                 .filter(|token| token.is_expired(now))
                 .map(|token| token.token.clone())
                 .collect::<Vec<_>>();
diff --git a/server/src/http/mapper.rs b/server/src/http/mapper.rs
index 621948bf..b4e61cc3 100644
--- a/server/src/http/mapper.rs
+++ b/server/src/http/mapper.rs
@@ -146,12 +146,12 @@ pub fn map_users(users: &[&User]) -> Vec<UserInfo> {
 }
 
 pub fn map_personal_access_tokens(
-    personal_access_tokens: &[&PersonalAccessToken],
+    personal_access_tokens: &[PersonalAccessToken],
 ) -> Vec<PersonalAccessTokenInfo> {
     let mut personal_access_tokens_data = 
Vec::with_capacity(personal_access_tokens.len());
     for personal_access_token in personal_access_tokens {
         let personal_access_token = PersonalAccessTokenInfo {
-            name: personal_access_token.name.clone(),
+            name: personal_access_token.name.as_str().to_owned(),
             expiry_at: personal_access_token.expiry_at,
         };
         personal_access_tokens_data.push(personal_access_token);
diff --git a/server/src/http/personal_access_tokens.rs 
b/server/src/http/personal_access_tokens.rs
index 5c447df5..20626108 100644
--- a/server/src/http/personal_access_tokens.rs
+++ b/server/src/http/personal_access_tokens.rs
@@ -82,8 +82,7 @@ async fn create_personal_access_token(
     Json(command): Json<CreatePersonalAccessToken>,
 ) -> Result<Json<RawPersonalAccessToken>, CustomError> {
     command.validate()?;
-
-    let mut system = state.system.write().await;
+    let system = state.system.read().await;
     let token = system
             .create_personal_access_token(
                 &Session::stateless(identity.user_id, identity.ip_address),
@@ -98,7 +97,6 @@ async fn create_personal_access_token(
                 )
             })?;
 
-    let system = system.downgrade();
     let token_hash = PersonalAccessToken::hash_token(&token);
     system
         .state
diff --git a/server/src/main.rs b/server/src/main.rs
index 70f9dc5f..9a957c0e 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -61,6 +61,10 @@ async fn main() -> Result<(), ServerError> {
         );
     }
 
+    if let Some(sha) = option_env!("VERGEN_GIT_SHA") {
+        println!("Commit SHA: {sha}");
+    }
+
     let args = Args::parse();
     let config_provider = config_provider::resolve(&args.config_provider)?;
     let config = ServerConfig::load(&config_provider).await?;
diff --git 
a/server/src/streaming/personal_access_tokens/personal_access_token.rs 
b/server/src/streaming/personal_access_tokens/personal_access_token.rs
index c042701b..cb188aa7 100644
--- a/server/src/streaming/personal_access_tokens/personal_access_token.rs
+++ b/server/src/streaming/personal_access_tokens/personal_access_token.rs
@@ -15,21 +15,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 use crate::streaming::utils::hash;
 use iggy::models::user_info::UserId;
 use iggy::utils::expiry::IggyExpiry;
 use iggy::utils::text::as_base64;
 use iggy::utils::timestamp::IggyTimestamp;
 use ring::rand::SecureRandom;
+use std::sync::Arc;
 
 const SIZE: usize = 50;
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct PersonalAccessToken {
     pub user_id: UserId,
-    pub name: String,
-    pub token: String,
+    pub name: Arc<String>,
+    pub token: Arc<String>,
     pub expiry_at: Option<IggyTimestamp>,
 }
 
@@ -49,8 +49,8 @@ impl PersonalAccessToken {
         (
             Self {
                 user_id,
-                name: name.to_string(),
-                token: token_hash,
+                name: Arc::new(name.to_string()),
+                token: Arc::new(token_hash),
                 expiry_at: Self::calculate_expiry_at(now, expiry),
             },
             token,
@@ -65,8 +65,8 @@ impl PersonalAccessToken {
     ) -> Self {
         Self {
             user_id,
-            name: name.into(),
-            token: token_hash.into(),
+            name: Arc::new(name.into()),
+            token: Arc::new(token_hash.into()),
             expiry_at,
         }
     }
@@ -106,12 +106,12 @@ mod tests {
         let name = "test_token";
         let (personal_access_token, raw_token) =
             PersonalAccessToken::new(user_id, name, now, 
IggyExpiry::NeverExpire);
-        assert_eq!(personal_access_token.name, name);
+        assert_eq!(personal_access_token.name.as_str(), name);
         assert!(!personal_access_token.token.is_empty());
         assert!(!raw_token.is_empty());
-        assert_ne!(personal_access_token.token, raw_token);
+        assert_ne!(personal_access_token.token.as_str(), raw_token);
         assert_eq!(
-            personal_access_token.token,
+            personal_access_token.token.as_str(),
             PersonalAccessToken::hash_token(&raw_token)
         );
     }
diff --git a/server/src/streaming/systems/info.rs 
b/server/src/streaming/systems/info.rs
index d2158b03..0cba996d 100644
--- a/server/src/streaming/systems/info.rs
+++ b/server/src/streaming/systems/info.rs
@@ -65,7 +65,10 @@ impl System {
             system_info = load_system_info.unwrap();
         }
 
-        info!("Loaded {system_info}");
+        info!("Loaded {system_info}.");
+        if let Some(sha) = option_env!("VERGEN_GIT_SHA") {
+            info!("Commit SHA: {sha}");
+        }
         let loaded_version = 
SemanticVersion::from_str(&system_info.version.version)?;
         if current_version.is_equal_to(&loaded_version) {
             info!("System version {current_version} is up to date.");
diff --git a/server/src/streaming/systems/personal_access_tokens.rs 
b/server/src/streaming/systems/personal_access_tokens.rs
index 7741734f..bc1dabfc 100644
--- a/server/src/streaming/systems/personal_access_tokens.rs
+++ b/server/src/streaming/systems/personal_access_tokens.rs
@@ -31,7 +31,7 @@ impl System {
     pub async fn get_personal_access_tokens(
         &self,
         session: &Session,
-    ) -> Result<Vec<&PersonalAccessToken>, IggyError> {
+    ) -> Result<Vec<PersonalAccessToken>, IggyError> {
         self.ensure_authenticated(session)?;
         let user_id = session.get_user_id();
         let user = self
@@ -40,7 +40,12 @@ impl System {
                 format!("{COMPONENT} (error: {error}) - failed to get user 
with id: {user_id}")
             })?;
         info!("Loading personal access tokens for user with ID: 
{user_id}...",);
-        let personal_access_tokens: Vec<_> = 
user.personal_access_tokens.values().collect();
+        let personal_access_tokens: Vec<_> = user
+            .personal_access_tokens
+            .iter()
+            .map(|pat| pat.clone())
+            .collect();
+
         info!(
             "Loaded {} personal access tokens for user with ID: {user_id}.",
             personal_access_tokens.len(),
@@ -49,7 +54,7 @@ impl System {
     }
 
     pub async fn create_personal_access_token(
-        &mut self,
+        &self,
         session: &Session,
         name: &str,
         expiry: IggyExpiry,
@@ -73,14 +78,14 @@ impl System {
             }
         }
 
-        let user = self.get_user_mut(&identifier).with_error_context(|error| {
+        let user = self.get_user(&identifier).with_error_context(|error| {
             format!("{COMPONENT} (error: {error}) - failed to get mutable 
reference to the user with id: {user_id}")
         })?;
 
         if user
             .personal_access_tokens
-            .values()
-            .any(|pat| pat.name == name)
+            .iter()
+            .any(|pat| pat.name.as_str() == name)
         {
             error!("Personal access token: {name} for user with ID: {user_id} 
already exists.");
             return Err(IggyError::PersonalAccessTokenAlreadyExists(
@@ -113,20 +118,16 @@ impl System {
                 )
             })?;
 
-        let token;
-
+        let token = if let Some(pat) = user
+            .personal_access_tokens
+            .iter()
+            .find(|pat| pat.name.as_str() == name)
         {
-            let pat = user
-                .personal_access_tokens
-                .iter()
-                .find(|(_, pat)| pat.name == name);
-            if pat.is_none() {
-                error!("Personal access token: {name} for user with ID: 
{user_id} does not exist.",);
-                return Err(IggyError::ResourceNotFound(name.to_owned()));
-            }
-
-            token = pat.unwrap().1.token.clone();
-        }
+            pat.token.clone()
+        } else {
+            error!("Personal access token: {name} for user with ID: {user_id} 
does not exist.",);
+            return Err(IggyError::ResourceNotFound(name.to_owned()));
+        };
 
         info!("Deleting personal access token: {name} for user with ID: 
{user_id}...");
         user.personal_access_tokens.remove(&token);
@@ -160,7 +161,7 @@ impl System {
                 personal_access_token.name, personal_access_token.user_id
             );
             return Err(IggyError::PersonalAccessTokenExpired(
-                personal_access_token.name.clone(),
+                personal_access_token.name.as_str().to_owned(),
                 personal_access_token.user_id,
             ));
         }
diff --git a/server/src/streaming/systems/storage.rs 
b/server/src/streaming/systems/storage.rs
index 187919ca..49649b5f 100644
--- a/server/src/streaming/systems/storage.rs
+++ b/server/src/streaming/systems/storage.rs
@@ -91,7 +91,7 @@ impl SystemInfoStorage for FileSystemInfoStorage {
                     self.path
                 )
             })?;
-        info!("Saved system info, {}", system_info);
+        info!("Saved system info, {system_info}");
         Ok(())
     }
 }
diff --git a/server/src/streaming/systems/users.rs 
b/server/src/streaming/systems/users.rs
index 0d11ba34..68ea3a74 100644
--- a/server/src/streaming/systems/users.rs
+++ b/server/src/streaming/systems/users.rs
@@ -36,6 +36,7 @@ use iggy::users::create_user::CreateUser;
 use iggy::users::defaults::*;
 use std::env;
 use std::sync::atomic::{AtomicU32, Ordering};
+use std::sync::Arc;
 use tracing::{error, info, warn};
 
 static USER_ID: AtomicU32 = AtomicU32::new(1);
@@ -85,7 +86,7 @@ impl System {
                 .into_values()
                 .map(|token| {
                     (
-                        token.token_hash.clone(),
+                        Arc::new(token.token_hash.clone()),
                         PersonalAccessToken::raw(
                             user_state.id,
                             &token.name,
@@ -104,7 +105,7 @@ impl System {
         self.permissioner
             .init(&self.users.values().collect::<Vec<&User>>());
         self.metrics.increment_users(users_count as u32);
-        info!("Initialized {} user(s).", users_count);
+        info!("Initialized {users_count} user(s).");
         Ok(())
     }
 
diff --git a/server/src/streaming/users/user.rs 
b/server/src/streaming/users/user.rs
index 1ddfcc23..fe585345 100644
--- a/server/src/streaming/users/user.rs
+++ b/server/src/streaming/users/user.rs
@@ -15,14 +15,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 use 
crate::streaming::personal_access_tokens::personal_access_token::PersonalAccessToken;
 use crate::streaming::utils::crypto;
-use ahash::AHashMap;
+use dashmap::DashMap;
 use iggy::models::user_status::UserStatus;
 use iggy::models::{permissions::Permissions, user_info::UserId};
 use iggy::users::defaults::*;
 use iggy::utils::timestamp::IggyTimestamp;
+use std::sync::Arc;
 
 #[derive(Debug)]
 pub struct User {
@@ -32,7 +32,7 @@ pub struct User {
     pub password: String,
     pub created_at: IggyTimestamp,
     pub permissions: Option<Permissions>,
-    pub personal_access_tokens: AHashMap<String, PersonalAccessToken>,
+    pub personal_access_tokens: DashMap<Arc<String>, PersonalAccessToken>,
 }
 
 impl Default for User {
@@ -44,7 +44,7 @@ impl Default for User {
             password: "secret".to_string(),
             created_at: IggyTimestamp::now(),
             permissions: None,
-            personal_access_tokens: AHashMap::new(),
+            personal_access_tokens: DashMap::new(),
         }
     }
 }
@@ -87,7 +87,7 @@ impl User {
             created_at: IggyTimestamp::now(),
             status,
             permissions,
-            personal_access_tokens: AHashMap::new(),
+            personal_access_tokens: DashMap::new(),
         }
     }
 
diff --git a/tools/Cargo.toml b/tools/Cargo.toml
index b6096bc5..ce861169 100644
--- a/tools/Cargo.toml
+++ b/tools/Cargo.toml
@@ -27,7 +27,7 @@ path = "src/data-seeder/main.rs"
 
 [dependencies]
 anyhow = "1.0.97"
-clap = { version = "4.5.32", features = ["derive"] }
+clap = { version = "4.5.34", features = ["derive"] }
 iggy = { path = "../sdk" }
 rand = "0.9.0"
 tokio = { version = "1.44.1", features = ["full"] }

Reply via email to