Skip to content

Commit

Permalink
Reuse Rng during temp name creation
Browse files Browse the repository at this point in the history
The fastrand Rng should be created manually to avoid TLS deallocation
issues. The fastrand::alphanumeric function uses a TLS storage
internally.

With current Rust and fastrand implementation, this is no problem.

Yet, we can speed up the process a bit by not accessing the storage
for every single random char.
  • Loading branch information
stoeckmann committed Mar 12, 2024
1 parent 8ee0018 commit 7ed0d45
Showing 1 changed file with 20 additions and 16 deletions.
36 changes: 20 additions & 16 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,7 @@ use std::{io, iter::repeat_with};

use crate::error::IoResultExt;

fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
let capacity = prefix
.len()
.saturating_add(suffix.len())
.saturating_add(rand_len);
let mut buf = OsString::with_capacity(capacity);
buf.push(prefix);
let mut char_buf = [0u8; 4];
for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
buf.push(c.encode_utf8(&mut char_buf));
}
buf.push(suffix);
buf
}
use fastrand::Rng;

pub fn create_helper<R>(
base: &Path,
Expand All @@ -27,12 +14,29 @@ pub fn create_helper<R>(
permissions: Option<&std::fs::Permissions>,
mut f: impl FnMut(PathBuf, Option<&std::fs::Permissions>) -> io::Result<R>,
) -> io::Result<R> {
let capacity = prefix
.len()
.saturating_add(random_len)
.saturating_add(suffix.len());
let mut buf = OsString::with_capacity(capacity);

if random_len == 0 {
let path = base.join(tmpname(prefix, suffix, random_len));
buf.push(prefix);
buf.push(suffix);
let path = base.join(buf);
f(path, permissions)
} else {
let mut char_buf = [0u8; 4];
let mut rng = Rng::new();

for _ in 0..crate::NUM_RETRIES {
let path = base.join(tmpname(prefix, suffix, random_len));
buf.push(prefix);
for c in repeat_with(|| rng.alphanumeric()).take(random_len) {
buf.push(c.encode_utf8(&mut char_buf));
}
buf.push(suffix);
let path = base.join(&buf);
buf.clear();
return match f(path, permissions) {
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
// AddrInUse can happen if we're creating a UNIX domain socket and
Expand Down

0 comments on commit 7ed0d45

Please sign in to comment.