Skip to content

Commit d7b7e13

Browse files
move session state into inner struct (#189)
This wraps session state into an inner struct, reducing the required Arcs.
1 parent 2a542d8 commit d7b7e13

File tree

1 file changed

+57
-39
lines changed

1 file changed

+57
-39
lines changed

tower-sessions-core/src/session.rs

+57-39
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,33 @@ pub enum Error {
3737
Store(#[from] session_store::Error),
3838
}
3939

40-
/// A session which allows HTTP applications to associate key-value pairs with
41-
/// visitors.
42-
#[derive(Debug, Clone)]
43-
pub struct Session {
40+
#[derive(Debug)]
41+
struct Inner {
4442
// This will be `None` when:
4543
//
4644
// 1. We have not been provided a session cookie or have failed to parse it,
4745
// 2. The store has not found the session.
4846
//
4947
// Sync lock, see: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use
50-
session_id: Arc<parking_lot::Mutex<Option<Id>>>,
51-
52-
store: Arc<dyn SessionStore>,
48+
session_id: parking_lot::Mutex<Option<Id>>,
5349

5450
// A lazy representation of the session's value, hydrated on a just-in-time basis. A
5551
// `None` value indicates we have not tried to access it yet. After access, it will always
5652
// contain `Some(Record)`.
57-
record: Arc<Mutex<Option<Record>>>,
53+
record: Mutex<Option<Record>>,
5854

5955
// Sync lock, see: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use
60-
expiry: Arc<parking_lot::Mutex<Option<Expiry>>>,
56+
expiry: parking_lot::Mutex<Option<Expiry>>,
6157

62-
is_modified: Arc<AtomicBool>,
58+
is_modified: AtomicBool,
59+
}
60+
61+
/// A session which allows HTTP applications to associate key-value pairs with
62+
/// visitors.
63+
#[derive(Debug, Clone)]
64+
pub struct Session {
65+
store: Arc<dyn SessionStore>,
66+
inner: Arc<Inner>,
6367
}
6468

6569
impl Session {
@@ -83,12 +87,16 @@ impl Session {
8387
store: Arc<impl SessionStore>,
8488
expiry: Option<Expiry>,
8589
) -> Self {
90+
let inner = Inner {
91+
session_id: parking_lot::Mutex::new(session_id),
92+
record: Mutex::new(None), // `None` indicates we have not loaded from store.
93+
expiry: parking_lot::Mutex::new(expiry),
94+
is_modified: AtomicBool::new(false),
95+
};
96+
8697
Self {
87-
session_id: Arc::new(parking_lot::Mutex::new(session_id)),
8898
store,
89-
record: Arc::new(Mutex::new(None)), // `None` indicates we have not loaded from store.
90-
expiry: Arc::new(parking_lot::Mutex::new(expiry)),
91-
is_modified: Arc::new(AtomicBool::new(false)),
99+
inner: Arc::new(inner),
92100
}
93101
}
94102

@@ -98,13 +106,13 @@ impl Session {
98106

99107
#[tracing::instrument(skip(self), err)]
100108
async fn get_record(&self) -> Result<MappedMutexGuard<Record>> {
101-
let mut record_guard = self.record.lock().await;
109+
let mut record_guard = self.inner.record.lock().await;
102110

103111
// Lazily load the record since `None` here indicates we have no yet loaded it.
104112
if record_guard.is_none() {
105113
tracing::trace!("record not loaded from store; loading");
106114

107-
let session_id = *self.session_id.lock();
115+
let session_id = *self.inner.session_id.lock();
108116
*record_guard = Some(if let Some(session_id) = session_id {
109117
match self.store.load(&session_id).await? {
110118
Some(loaded_record) => {
@@ -119,7 +127,7 @@ impl Session {
119127
// be relatively uncommon and as such entering this branch could indicate
120128
// malicious behavior.
121129
tracing::warn!("possibly suspicious activity: record not found in store");
122-
*self.session_id.lock() = None;
130+
*self.inner.session_id.lock() = None;
123131
self.create_record()
124132
}
125133
}
@@ -212,7 +220,9 @@ impl Session {
212220
pub async fn insert_value(&self, key: &str, value: Value) -> Result<Option<Value>> {
213221
let mut record_guard = self.get_record().await?;
214222
Ok(if record_guard.data.get(key) != Some(&value) {
215-
self.is_modified.store(true, atomic::Ordering::Release);
223+
self.inner
224+
.is_modified
225+
.store(true, atomic::Ordering::Release);
216226
record_guard.data.insert(key.to_string(), value)
217227
} else {
218228
None
@@ -346,7 +356,9 @@ impl Session {
346356
/// we fail with [`Error::Store`].
347357
pub async fn remove_value(&self, key: &str) -> Result<Option<Value>> {
348358
let mut record_guard = self.get_record().await?;
349-
self.is_modified.store(true, atomic::Ordering::Release);
359+
self.inner
360+
.is_modified
361+
.store(true, atomic::Ordering::Release);
350362
Ok(record_guard.data.remove(key))
351363
}
352364

@@ -386,16 +398,18 @@ impl Session {
386398
/// # });
387399
/// ```
388400
pub async fn clear(&self) {
389-
let mut record_guard = self.record.lock().await;
401+
let mut record_guard = self.inner.record.lock().await;
390402
if let Some(record) = record_guard.as_mut() {
391403
record.data.clear();
392-
} else if let Some(session_id) = *self.session_id.lock() {
404+
} else if let Some(session_id) = *self.inner.session_id.lock() {
393405
let mut new_record = self.create_record();
394406
new_record.id = session_id;
395407
*record_guard = Some(new_record);
396408
}
397409

398-
self.is_modified.store(true, atomic::Ordering::Release);
410+
self.inner
411+
.is_modified
412+
.store(true, atomic::Ordering::Release);
399413
}
400414

401415
/// Returns `true` if there is no session ID and the session is empty.
@@ -450,13 +464,13 @@ impl Session {
450464
/// # });
451465
/// ```
452466
pub async fn is_empty(&self) -> bool {
453-
let record_guard = self.record.lock().await;
467+
let record_guard = self.inner.record.lock().await;
454468

455469
// N.B.: Session IDs are `None` if:
456470
//
457471
// 1. The cookie was not provided or otherwise could not be parsed,
458472
// 2. Or the session could not be loaded from the store.
459-
let session_id = self.session_id.lock();
473+
let session_id = self.inner.session_id.lock();
460474

461475
let Some(record) = record_guard.as_ref() else {
462476
return session_id.is_none();
@@ -484,7 +498,7 @@ impl Session {
484498
/// assert_eq!(id, session.id());
485499
/// ```
486500
pub fn id(&self) -> Option<Id> {
487-
*self.session_id.lock()
501+
*self.inner.session_id.lock()
488502
}
489503

490504
/// Get the session expiry.
@@ -502,7 +516,7 @@ impl Session {
502516
/// assert_eq!(session.expiry(), None);
503517
/// ```
504518
pub fn expiry(&self) -> Option<Expiry> {
505-
*self.expiry.lock()
519+
*self.inner.expiry.lock()
506520
}
507521

508522
/// Set `expiry` to the given value.
@@ -527,8 +541,10 @@ impl Session {
527541
/// assert_eq!(session.expiry(), Some(expiry));
528542
/// ```
529543
pub fn set_expiry(&self, expiry: Option<Expiry>) {
530-
*self.expiry.lock() = expiry;
531-
self.is_modified.store(true, atomic::Ordering::Release);
544+
*self.inner.expiry.lock() = expiry;
545+
self.inner
546+
.is_modified
547+
.store(true, atomic::Ordering::Release);
532548
}
533549

534550
/// Get session expiry as `OffsetDateTime`.
@@ -551,7 +567,7 @@ impl Session {
551567
/// assert!(session.expiry_date() < expected_expiry.saturating_add(Duration::seconds(1)));
552568
/// ```
553569
pub fn expiry_date(&self) -> OffsetDateTime {
554-
let expiry = self.expiry.lock();
570+
let expiry = self.inner.expiry.lock();
555571
match *expiry {
556572
Some(Expiry::OnInactivity(duration)) => {
557573
OffsetDateTime::now_utc().saturating_add(duration)
@@ -614,7 +630,7 @@ impl Session {
614630
/// # });
615631
/// ```
616632
pub fn is_modified(&self) -> bool {
617-
self.is_modified.load(atomic::Ordering::Acquire)
633+
self.inner.is_modified.load(atomic::Ordering::Acquire)
618634
}
619635

620636
/// Saves the session record to the store.
@@ -658,9 +674,9 @@ impl Session {
658674
// In either case, we must create a new session via the store interface.
659675
//
660676
// Potential ID collisions must be handled by session store implementers.
661-
if self.session_id.lock().is_none() {
677+
if self.inner.session_id.lock().is_none() {
662678
self.store.create(&mut record_guard).await?;
663-
*self.session_id.lock() = Some(record_guard.id);
679+
*self.inner.session_id.lock() = Some(record_guard.id);
664680
} else {
665681
self.store.save(&record_guard).await?;
666682
}
@@ -699,13 +715,13 @@ impl Session {
699715
/// - If loading from the store fails, we fail with [`Error::Store`].
700716
#[tracing::instrument(skip(self), err)]
701717
pub async fn load(&self) -> Result<()> {
702-
let session_id = *self.session_id.lock();
718+
let session_id = *self.inner.session_id.lock();
703719
let Some(ref id) = session_id else {
704720
tracing::warn!("called load with no session id");
705721
return Ok(());
706722
};
707723
let loaded_record = self.store.load(id).await.map_err(Error::Store)?;
708-
let mut record_guard = self.record.lock().await;
724+
let mut record_guard = self.inner.record.lock().await;
709725
*record_guard = loaded_record;
710726
Ok(())
711727
}
@@ -738,7 +754,7 @@ impl Session {
738754
/// - If deleting from the store fails, we fail with [`Error::Store`].
739755
#[tracing::instrument(skip(self), err)]
740756
pub async fn delete(&self) -> Result<()> {
741-
let session_id = *self.session_id.lock();
757+
let session_id = *self.inner.session_id.lock();
742758
let Some(ref session_id) = session_id else {
743759
tracing::warn!("called delete with no session id");
744760
return Ok(());
@@ -780,7 +796,7 @@ impl Session {
780796
pub async fn flush(&self) -> Result<()> {
781797
self.clear().await;
782798
self.delete().await?;
783-
*self.session_id.lock() = None;
799+
*self.inner.session_id.lock() = None;
784800
Ok(())
785801
}
786802

@@ -829,15 +845,17 @@ impl Session {
829845

830846
let old_session_id = record_guard.id;
831847
record_guard.id = Id::default();
832-
*self.session_id.lock() = None; // Setting `None` ensures `save` invokes the store's
833-
// `create` method.
848+
*self.inner.session_id.lock() = None; // Setting `None` ensures `save` invokes the store's
849+
// `create` method.
834850

835851
self.store
836852
.delete(&old_session_id)
837853
.await
838854
.map_err(Error::Store)?;
839855

840-
self.is_modified.store(true, atomic::Ordering::Release);
856+
self.inner
857+
.is_modified
858+
.store(true, atomic::Ordering::Release);
841859

842860
Ok(())
843861
}

0 commit comments

Comments
 (0)