Skip to content

Commit 1ee896f

Browse files
committed
PatternFormatter lock the local time cacher only once
1 parent 6ba46c3 commit 1ee896f

File tree

6 files changed

+194
-185
lines changed

6 files changed

+194
-185
lines changed

spdlog/benches/spdlog-rs/pattern.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ include!(concat!(
2222
));
2323
use test_utils::*;
2424

25-
struct BenchSink<F> {
25+
struct BenchSink<'a, F> {
2626
formatter: F,
2727
buffer: RefCell<StringBuf>,
28-
ctx: RefCell<FormatterContext>,
28+
ctx: RefCell<FormatterContext<'a>>,
2929
}
3030

31-
impl<F: Formatter> BenchSink<F> {
31+
impl<F: Formatter> BenchSink<'_, F> {
3232
fn new(formatter: F) -> Self {
3333
Self {
3434
formatter,
@@ -40,9 +40,9 @@ impl<F: Formatter> BenchSink<F> {
4040

4141
// I think we're just testing benchmarks here, and they should not be executed
4242
// in parallel, so the data race from `buffer` shouldn't be an problem?
43-
unsafe impl<F> Sync for BenchSink<F> {}
43+
unsafe impl<F> Sync for BenchSink<'_, F> {}
4444

45-
impl<F: Formatter> Sink for BenchSink<F> {
45+
impl<F: Formatter> Sink for BenchSink<'_, F> {
4646
fn log(&self, record: &Record) -> spdlog::Result<()> {
4747
self.formatter.format(
4848
record,

spdlog/src/formatter/full_formatter.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::fmt::{self, Write};
55
use cfg_if::cfg_if;
66

77
use crate::{
8-
formatter::{Formatter, FormatterContext, LOCAL_TIME_CACHER},
8+
formatter::{fmt_with_time, Formatter, FormatterContext, TimeDate},
99
Error, Record, StringBuf, __EOL,
1010
};
1111

@@ -62,15 +62,14 @@ impl FullFormatter {
6262
}
6363
}
6464

65-
{
66-
let mut local_time_cacher = LOCAL_TIME_CACHER.lock();
67-
let mut time = local_time_cacher.get(record.time());
65+
fmt_with_time(ctx, record, |mut time: TimeDate| {
6866
dest.write_str("[")?;
6967
dest.write_str(time.full_second_str())?;
7068
dest.write_str(".")?;
7169
write!(dest, "{:03}", time.millisecond())?;
7270
dest.write_str("] [")?;
73-
}
71+
Ok(())
72+
})?;
7473

7574
if let Some(logger_name) = record.logger_name() {
7675
dest.write_str(logger_name)?;

spdlog/src/formatter/local_time_cacher.rs

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
use std::time::SystemTime;
1+
use std::{fmt, time::SystemTime};
22

33
use chrono::prelude::*;
44
use once_cell::sync::Lazy;
55

6-
use crate::sync::*;
6+
use crate::{formatter::FormatterContext, sync::*, Record};
77

8-
pub(crate) static LOCAL_TIME_CACHER: Lazy<SpinMutex<LocalTimeCacher>> =
8+
static LOCAL_TIME_CACHER: Lazy<SpinMutex<LocalTimeCacher>> =
99
Lazy::new(|| SpinMutex::new(LocalTimeCacher::new()));
1010

11+
pub(crate) fn fmt_with_time<R, F>(ctx: &mut FormatterContext, record: &Record, mut callback: F) -> R
12+
where
13+
F: FnMut(TimeDate) -> R,
14+
{
15+
if let Some(time_date) = ctx.locked_time_date.as_mut() {
16+
callback(time_date.get())
17+
} else {
18+
callback(LOCAL_TIME_CACHER.lock().get(record.time()))
19+
}
20+
}
21+
1122
#[derive(Clone)]
1223
pub(crate) struct LocalTimeCacher {
1324
stored_key: CacheKey,
@@ -91,11 +102,11 @@ impl LocalTimeCacher {
91102
self.stored_key = cache_key;
92103
}
93104

94-
TimeDate::new(
95-
self.cache_values.as_mut().unwrap(),
96-
reduced_nanosecond,
105+
TimeDate {
106+
cached: self.cache_values.as_mut().unwrap(),
107+
nanosecond: reduced_nanosecond,
97108
millisecond,
98-
)
109+
}
99110
}
100111
}
101112

@@ -128,15 +139,6 @@ macro_rules! impl_cache_fields_str_getter {
128139
}
129140

130141
impl<'a> TimeDate<'a> {
131-
#[must_use]
132-
fn new(cached: &'a mut CacheValues, nanosecond: u32, millisecond: u32) -> Self {
133-
Self {
134-
cached,
135-
nanosecond,
136-
millisecond,
137-
}
138-
}
139-
140142
#[must_use]
141143
pub(crate) fn full_second_str(&mut self) -> &str {
142144
if self.cached.full_second_str.is_none() {
@@ -361,6 +363,52 @@ impl CacheValues {
361363
}
362364
}
363365

366+
struct TimeDateLocked<'a> {
367+
cached: SpinMutexGuard<'a, LocalTimeCacher>,
368+
nanosecond: u32,
369+
millisecond: u32,
370+
}
371+
372+
pub(crate) struct TimeDateLazyLocked<'a> {
373+
time: SystemTime,
374+
locked: Option<TimeDateLocked<'a>>,
375+
}
376+
377+
impl<'a> TimeDateLazyLocked<'a> {
378+
#[must_use]
379+
pub(crate) fn new(time: SystemTime) -> Self {
380+
Self { time, locked: None }
381+
}
382+
383+
#[must_use]
384+
pub(crate) fn get(&mut self) -> TimeDate<'_> {
385+
let locked = self.locked.get_or_insert_with(|| {
386+
let mut cached = LOCAL_TIME_CACHER.lock();
387+
let time_date = cached.get(self.time);
388+
let (nanosecond, millisecond) = (time_date.nanosecond, time_date.millisecond);
389+
TimeDateLocked {
390+
cached,
391+
nanosecond,
392+
millisecond,
393+
}
394+
});
395+
396+
TimeDate {
397+
cached: locked.cached.cache_values.as_mut().unwrap(),
398+
nanosecond: locked.nanosecond,
399+
millisecond: locked.millisecond,
400+
}
401+
}
402+
}
403+
404+
impl fmt::Debug for TimeDateLazyLocked<'_> {
405+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406+
f.debug_struct("TimeDateLazyLocked")
407+
.field("time", &self.time)
408+
.finish()
409+
}
410+
}
411+
364412
#[cfg(test)]
365413
mod tests {
366414
use super::*;

spdlog/src/formatter/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,20 @@ clone_trait_object!(Formatter);
9595

9696
/// Provides context for formatters.
9797
#[derive(Debug, Default)]
98-
pub struct FormatterContext {
98+
pub struct FormatterContext<'a> {
9999
style_range: Option<Range<usize>>,
100+
// Set to `Some` if the cached date time is locked in the upper caller.
101+
locked_time_date: Option<TimeDateLazyLocked<'a>>,
100102
}
101103

102-
impl FormatterContext {
104+
impl FormatterContext<'_> {
103105
/// Constructs a `FormatterContext`.
104106
#[must_use]
105107
pub fn new() -> Self {
106-
Self { style_range: None }
108+
Self {
109+
style_range: None,
110+
locked_time_date: None,
111+
}
107112
}
108113

109114
/// Sets style range (in bytes) of the formatted text.

spdlog/src/formatter/pattern_formatter/mod.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use dyn_clone::*;
1212
pub use runtime::*;
1313

1414
use crate::{
15-
formatter::{Formatter, FormatterContext},
15+
formatter::{Formatter, FormatterContext, TimeDate, TimeDateLazyLocked},
1616
Error, Record, StringBuf,
1717
};
1818

@@ -381,8 +381,12 @@ where
381381
}
382382
};
383383

384-
let mut pat_ctx = PatternContext::new(fmt_ctx);
385-
self.pattern.format(record, dest, &mut pat_ctx)?;
384+
fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
385+
{
386+
let mut pat_ctx = PatternContext { fmt_ctx };
387+
self.pattern.format(record, dest, &mut pat_ctx)?;
388+
}
389+
fmt_ctx.locked_time_date = None;
386390
Ok(())
387391
}
388392
}
@@ -391,15 +395,14 @@ where
391395
///
392396
/// There is nothing to set up here at the moment, reserved for future use.
393397
#[derive(Debug)]
394-
pub struct PatternContext<'a> {
395-
fmt_ctx: &'a mut FormatterContext,
398+
pub struct PatternContext<'a, 'b> {
399+
fmt_ctx: &'a mut FormatterContext<'b>,
396400
}
397401

398-
impl<'a> PatternContext<'a> {
399-
/// Creates a new `PatternContext` object.
402+
impl PatternContext<'_, '_> {
400403
#[must_use]
401-
fn new(fmt_ctx: &'a mut FormatterContext) -> Self {
402-
Self { fmt_ctx }
404+
fn time_date(&mut self) -> TimeDate {
405+
self.fmt_ctx.locked_time_date.as_mut().unwrap().get()
403406
}
404407
}
405408

@@ -1221,10 +1224,12 @@ pub mod tests {
12211224
let record = get_mock_record();
12221225
let mut output = StringBuf::new();
12231226
let mut fmt_ctx = FormatterContext::new();
1224-
let mut pat_ctx = PatternContext::new(&mut fmt_ctx);
1225-
1226-
let format_result = pattern.format(&record, &mut output, &mut pat_ctx);
1227-
assert!(format_result.is_ok());
1227+
fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
1228+
let mut pat_ctx = PatternContext {
1229+
fmt_ctx: &mut fmt_ctx,
1230+
};
1231+
pattern.format(&record, &mut output, &mut pat_ctx).unwrap();
1232+
fmt_ctx.locked_time_date = None;
12281233

12291234
assert_eq!(output.as_str(), formatted.as_ref());
12301235
assert_eq!(fmt_ctx.style_range(), style_range);

0 commit comments

Comments
 (0)