Skip to content

Commit 96091ec

Browse files
committed
f: review comments
1 parent a545f9b commit 96091ec

File tree

3 files changed

+44
-27
lines changed

3 files changed

+44
-27
lines changed

fuzz/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ lightning-persister = { path = "../lightning-persister", features = ["tokio"]}
2626
bech32 = "0.11.0"
2727
bitcoin = { version = "0.32.2", features = ["secp-lowmemory"] }
2828
tokio = { version = "~1.35", default-features = false, features = ["rt-multi-thread"] }
29-
uuid = { version = "1.3", features = ["v4"] }
3029

3130
afl = { version = "0.12", optional = true }
3231
honggfuzz = { version = "0.5", optional = true, default-features = false }

fuzz/src/fs_store.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
use core::hash::{BuildHasher, Hasher};
12
use lightning::util::persist::{KVStore, KVStoreSync};
23
use lightning_persister::fs_store::FilesystemStore;
34
use std::fs;
45
use tokio::runtime::Runtime;
5-
use uuid::Uuid;
66

77
use crate::utils::test_logger;
88

@@ -20,7 +20,8 @@ impl TempFilesystemStore {
2020
std::env::temp_dir()
2121
};
2222

23-
let random_folder_name = format!("fs_store_fuzz_{}", Uuid::new_v4());
23+
let random_number = std::collections::hash_map::RandomState::new().build_hasher().finish();
24+
let random_folder_name = format!("fs_store_fuzz_{:016x}", random_number);
2425
temp_path.push(random_folder_name);
2526

2627
let inner = FilesystemStore::new(temp_path.clone());
@@ -46,10 +47,11 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
4647
($len: expr) => {{
4748
let slice_len = $len as usize;
4849
if data.len() < read_pos + slice_len {
49-
return;
50+
None
51+
} else {
52+
read_pos += slice_len;
53+
Some(&data[read_pos - slice_len..read_pos])
5054
}
51-
read_pos += slice_len;
52-
&data[read_pos - slice_len..read_pos]
5355
}};
5456
}
5557

@@ -72,7 +74,10 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
7274

7375
let mut handles = Vec::new();
7476
loop {
75-
let v = get_slice!(1)[0];
77+
let v = match get_slice!(1) {
78+
Some(b) => b[0],
79+
None => break,
80+
};
7681
match v % 13 {
7782
// Sync write
7883
0 => {
@@ -104,7 +109,7 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
104109
3 => {
105110
_ = KVStoreSync::read(fs_store, primary_namespace, secondary_namespace, key);
106111
},
107-
// Async write
112+
// Async write. Bias writes a bit.
108113
4..=9 => {
109114
let data_value = get_next_data_value();
110115

@@ -127,8 +132,9 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
127132
},
128133
// Async remove
129134
10 | 11 => {
135+
let lazy = v == 10;
130136
let fut =
131-
KVStore::remove(fs_store, primary_namespace, secondary_namespace, key, v == 10);
137+
KVStore::remove(fs_store, primary_namespace, secondary_namespace, key, lazy);
132138

133139
// Already set the current_data, even though writing hasn't finished yet. This supports the call-time
134140
// ordering semantics.
@@ -143,9 +149,7 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
143149
let _ = handle.await.unwrap();
144150
}
145151
},
146-
_ => {
147-
return;
148-
},
152+
_ => unreachable!(),
149153
}
150154

151155
// If no more writes are pending, we can reliably see if the data is consistent.
@@ -160,6 +164,12 @@ async fn do_test_internal<Out: test_logger::Output>(data: &[u8], _out: Out) {
160164
assert_eq!(0, fs_store.state_size());
161165
}
162166
}
167+
168+
// Always make sure that all async tasks are completed before returning. Otherwise the temporary storage dir could
169+
// be removed, and then again recreated by unfinished tasks.
170+
for handle in handles.drain(..) {
171+
let _ = handle.await.unwrap();
172+
}
163173
}
164174

165175
/// Method that needs to be added manually, {name}_test

lightning-persister/src/fs_store.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl FilesystemStoreInner {
198198
let mut buf = Vec::new();
199199

200200
self.execute_locked_read(dest_file_path.clone(), || {
201-
let mut f = fs::File::open(dest_file_path.clone())?;
201+
let mut f = fs::File::open(dest_file_path)?;
202202
f.read_to_end(&mut buf)?;
203203
Ok(())
204204
})?;
@@ -209,19 +209,21 @@ impl FilesystemStoreInner {
209209
fn execute_locked_write<F: FnOnce() -> Result<(), lightning::io::Error>>(
210210
&self, inner_lock_ref: Arc<RwLock<u64>>, dest_file_path: PathBuf, version: u64, callback: F,
211211
) -> Result<(), lightning::io::Error> {
212-
let mut last_written_version = inner_lock_ref.write().unwrap();
212+
let res = {
213+
let mut last_written_version = inner_lock_ref.write().unwrap();
213214

214-
// Check if we already have a newer version written/removed. This is used in async contexts to realize eventual
215-
// consistency.
216-
let is_stale_version = version <= *last_written_version;
215+
// Check if we already have a newer version written/removed. This is used in async contexts to realize eventual
216+
// consistency.
217+
let is_stale_version = version <= *last_written_version;
217218

218-
// If the version is not stale, we execute the callback. Otherwise we can and must skip writing.
219-
let res = if is_stale_version {
220-
Ok(())
221-
} else {
222-
callback().map(|_| {
223-
*last_written_version = version;
224-
})
219+
// If the version is not stale, we execute the callback. Otherwise we can and must skip writing.
220+
if is_stale_version {
221+
Ok(())
222+
} else {
223+
callback().map(|_| {
224+
*last_written_version = version;
225+
})
226+
}
225227
};
226228

227229
self.clean_locks(&inner_lock_ref, dest_file_path);
@@ -233,8 +235,10 @@ impl FilesystemStoreInner {
233235
&self, dest_file_path: PathBuf, callback: F,
234236
) -> Result<(), lightning::io::Error> {
235237
let inner_lock_ref = self.get_inner_lock_ref(dest_file_path.clone());
236-
let _guard = inner_lock_ref.read().unwrap();
237-
let res = callback();
238+
let res = {
239+
let _guard = inner_lock_ref.read().unwrap();
240+
callback()
241+
};
238242
self.clean_locks(&inner_lock_ref, dest_file_path);
239243
res
240244
}
@@ -245,7 +249,11 @@ impl FilesystemStoreInner {
245249
// inner_lock_ref. The outer lock is obtained first, to avoid a new arc being cloned after we've already
246250
// counted.
247251
let mut outer_lock = self.locks.lock().unwrap();
248-
if Arc::strong_count(&inner_lock_ref) == 2 {
252+
253+
let strong_count = Arc::strong_count(&inner_lock_ref);
254+
debug_assert!(strong_count >= 2, "Unexpected FilesystemStore strong count");
255+
256+
if strong_count == 2 {
249257
outer_lock.remove(&dest_file_path);
250258
}
251259
}

0 commit comments

Comments
 (0)