Skip to content

Commit

Permalink
[TieredStorage] Make TieredStorage::write_accounts() thread-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
yhchiang-sol committed Feb 8, 2024
1 parent 28a320d commit 72fa85d
Showing 1 changed file with 36 additions and 23 deletions.
59 changes: 36 additions & 23 deletions accounts-db/src/tiered_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ use {
borrow::Borrow,
fs::{self, OpenOptions},
path::{Path, PathBuf},
sync::OnceLock,
sync::{
atomic::{AtomicBool, Ordering},
OnceLock,
},
},
};

Expand All @@ -49,6 +52,7 @@ pub struct TieredStorageFormat {
#[derive(Debug)]
pub struct TieredStorage {
reader: OnceLock<TieredStorageReader>,
read_only: AtomicBool,
path: PathBuf,
}

Expand All @@ -72,6 +76,7 @@ impl TieredStorage {
pub fn new_writable(path: impl Into<PathBuf>) -> Self {
Self {
reader: OnceLock::<TieredStorageReader>::new(),
read_only: false.into(),
path: path.into(),
}
}
Expand All @@ -82,6 +87,7 @@ impl TieredStorage {
let path = path.into();
Ok(Self {
reader: TieredStorageReader::new_from_path(&path).map(OnceLock::from)?,
read_only: true.into(),
path,
})
}
Expand Down Expand Up @@ -109,29 +115,36 @@ impl TieredStorage {
skip: usize,
format: &TieredStorageFormat,
) -> TieredStorageResult<Vec<StoredAccountInfo>> {
if self.is_read_only() {
return Err(TieredStorageError::AttemptToUpdateReadOnly(
self.path.to_path_buf(),
));
}

if format == &HOT_FORMAT {
let result = {
let writer = HotStorageWriter::new(&self.path)?;
writer.write_accounts(accounts, skip)
};

// panic here if self.reader.get() is not None as self.reader can only be
// None since we have passed `is_read_only()` check previously, indicating
// self.reader is not yet set.
self.reader
.set(TieredStorageReader::new_from_path(&self.path)?)
.unwrap();
let was_readonly =
self.read_only
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed);

// If it was not previously readonly, and the current thread has
// successfully updated the read_only flag, then the current
// thread will proceed and writes the input accounts.
if was_readonly == Ok(false) {
if format == &HOT_FORMAT {
let result = {
let writer = HotStorageWriter::new(&self.path)?;
writer.write_accounts(accounts, skip)
};

// panic here if self.reader.get() is not None as self.reader can only be
// None since we have passed `is_read_only()` check previously, indicating
// self.reader is not yet set.
self.reader
.set(TieredStorageReader::new_from_path(&self.path)?)
.unwrap();

return result;
}

return result;
Err(TieredStorageError::UnknownFormat(self.path.to_path_buf()))
} else {
Err(TieredStorageError::AttemptToUpdateReadOnly(
self.path.to_path_buf(),
))
}

Err(TieredStorageError::UnknownFormat(self.path.to_path_buf()))
}

/// Returns the underlying reader of the TieredStorage. None will be
Expand All @@ -142,7 +155,7 @@ impl TieredStorage {

/// Returns true if the TieredStorage instance is read-only.
pub fn is_read_only(&self) -> bool {
self.reader.get().is_some()
self.read_only.load(Ordering::Relaxed)
}

/// Returns the size of the underlying accounts file.
Expand Down

0 comments on commit 72fa85d

Please sign in to comment.