Skip to content

Commit add5f38

Browse files
russellromneyclaude
andcommitted
Clear all clippy warnings (style/lint cleanup)
clippy reported ~109 warnings (it had never been enforced on the ffi crate). Drive the lib, ffi-default, and ffi-loadable-extension builds all to zero, with no behavior change: - Machine-applicable fixes via clippy --fix: io::Error::other, div_ceil, slice .first(), derivable impls, sort_by_key, c"..." literals, etc. - suspicious_open_options: added explicit .truncate(false) — preserves the current default behavior, just makes it intentional (never truncate(true)). - too_many_arguments: allowed crate-wide; the tiered pipeline threads many params through flush/compact/prefetch by design. - missing_safety_doc: added # Safety sections to the unsafe extern "C" FFI entry points. - Deprecated SyncMode::S3Primary / set_local_checkpoint_only: scoped #[allow(deprecated)] with comments (kept for back-compat; no behavior change). Verified: lib 568 passed, loadable-ext 27/27, clippy clean in all three modes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 916b4e9 commit add5f38

37 files changed

Lines changed: 192 additions & 221 deletions

src/compress.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ pub fn compress(
2020

2121
if let Some(encoder_dict) = encoder_dict {
2222
let mut encoder = zstd::stream::Encoder::with_prepared_dictionary(Vec::new(), encoder_dict)
23-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
23+
.map_err(io::Error::other)?;
2424
encoder.write_all(data)?;
2525
encoder
2626
.finish()
27-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
27+
.map_err(io::Error::other)
2828
} else {
29-
encode_all(data, level).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
29+
encode_all(data, level).map_err(io::Error::other)
3030
}
3131
}
3232

@@ -40,12 +40,12 @@ pub fn decompress(
4040

4141
if let Some(decoder_dict) = decoder_dict {
4242
let mut decoder = zstd::stream::Decoder::with_prepared_dictionary(data, decoder_dict)
43-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
43+
.map_err(io::Error::other)?;
4444
let mut output = Vec::new();
4545
decoder.read_to_end(&mut output)?;
4646
Ok(output)
4747
} else {
48-
decode_all(data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
48+
decode_all(data).map_err(io::Error::other)
4949
}
5050
}
5151

@@ -70,11 +70,11 @@ pub fn decompress_capped(
7070
let mut output = Vec::new();
7171
let n = if let Some(decoder_dict) = decoder_dict {
7272
let decoder = zstd::stream::Decoder::with_prepared_dictionary(data, decoder_dict)
73-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
73+
.map_err(io::Error::other)?;
7474
decoder.take(cap as u64).read_to_end(&mut output)?
7575
} else {
7676
let decoder = zstd::stream::Decoder::new(data)
77-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
77+
.map_err(io::Error::other)?;
7878
decoder.take(cap as u64).read_to_end(&mut output)?
7979
};
8080
if n > max_len {

src/dict.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ pub fn train_dictionary(samples: &[Vec<u8>], dict_size: usize) -> io::Result<Vec
4646
let sample_refs: Vec<&[u8]> = samples.iter().map(|s| s.as_slice()).collect();
4747

4848
from_samples(&sample_refs, dict_size).map_err(|e| {
49-
io::Error::new(
50-
io::ErrorKind::Other,
49+
io::Error::other(
5150
format!("Dictionary training failed: {}", e),
5251
)
5352
})
@@ -101,11 +100,11 @@ pub fn compress_with_dict(data: &[u8], dict: &[u8], level: i32) -> io::Result<Ve
101100

102101
let encoder_dict = EncoderDictionary::copy(dict, level);
103102
let mut encoder = zstd::stream::Encoder::with_prepared_dictionary(Vec::new(), &encoder_dict)
104-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
103+
.map_err(io::Error::other)?;
105104
encoder.write_all(data)?;
106105
encoder
107106
.finish()
108-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
107+
.map_err(io::Error::other)
109108
}
110109

111110
/// Decompress data using a dictionary.
@@ -116,7 +115,7 @@ pub fn decompress_with_dict(data: &[u8], dict: &[u8]) -> io::Result<Vec<u8>> {
116115

117116
let decoder_dict = DecoderDictionary::copy(dict);
118117
let mut decoder = zstd::stream::Decoder::with_prepared_dictionary(data, &decoder_dict)
119-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
118+
.map_err(io::Error::other)?;
120119
let mut output = Vec::new();
121120
decoder.read_to_end(&mut output)?;
122121
Ok(output)

src/install_hook.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ unsafe fn install(db: *mut ffi::sqlite3) {
120120

121121
let queue_ptr = Arc::into_raw(queue) as *mut std::ffi::c_void;
122122

123-
let name = b"turbolite_config_set\0".as_ptr() as *const c_char;
123+
let name = c"turbolite_config_set".as_ptr() as *const c_char;
124124
let rc = ffi::sqlite3_create_function_v2(
125125
db,
126126
name,
@@ -220,7 +220,7 @@ unsafe extern "C" fn destroy(ptr: *mut std::ffi::c_void) {
220220
/// connection was opened with `vfs=<some name passed to turbolite::tiered::register>`.
221221
unsafe fn connection_uses_turbolite_vfs(db: *mut ffi::sqlite3) -> bool {
222222
let mut vfs_ptr: *mut ffi::sqlite3_vfs = std::ptr::null_mut();
223-
let main = b"main\0".as_ptr() as *const c_char;
223+
let main = c"main".as_ptr() as *const c_char;
224224
let rc = ffi::sqlite3_file_control(
225225
db,
226226
main,

src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
//! turbolite::tiered::register("mydb", vfs)?;
2323
//! ```
2424
25+
// The tiered storage pipeline threads many parameters (offsets, codecs,
26+
// counters, manifests) through its flush/compact/prefetch paths. Grouping them
27+
// into structs is a worthwhile refactor but a separate one; until then these
28+
// signatures are intentional, not an oversight.
29+
#![allow(clippy::too_many_arguments)]
30+
2531
/// Debug logging macro. Emits a `tracing::debug!` event under the
2632
/// `turbolite` target. Users filter via `RUST_LOG=turbolite=debug` like any
2733
/// other tracing-instrumented library. Silent by default — no subscriber
@@ -144,7 +150,7 @@ pub fn connect(path: &str, config: TurboliteConfig) -> Result<rusqlite::Connecti
144150
/// # SQL function return codes
145151
///
146152
/// - `0` — update queued successfully; the handle applies it on the next
147-
/// slow-path read.
153+
/// slow-path read.
148154
/// - SQL error — validation failed (unknown key or bad value). The
149155
/// captured queue makes "no active handle" unreachable through this
150156
/// function: the closure holds an `Arc` to its queue for the function's
@@ -314,7 +320,7 @@ const WAL_LOCK_OFFSET: u64 = 120;
314320

315321
/// Lock tracing events are emitted under the `turbolite::locks` tracing
316322
/// target. Filter with `RUST_LOG=turbolite::locks=trace`.
317-
323+
///
318324
/// The five SQLite database lock levels, ordered from weakest to strongest.
319325
/// Turbolite's own type (the VFS backend is sqlite-plugin; we no longer pull
320326
/// these from sqlite-vfs). See <https://www.sqlite.org/lockingv3.html>.
@@ -405,6 +411,7 @@ impl FileWalIndex {
405411
.read(true)
406412
.write(true)
407413
.create(true)
414+
.truncate(false)
408415
.open(&self.path)?;
409416
self.file = Some(file);
410417
}
@@ -417,6 +424,7 @@ impl FileWalIndex {
417424
.read(true)
418425
.write(true)
419426
.create(true)
427+
.truncate(false)
420428
.open(&self.path)?;
421429
self.lock_file = Some(std::sync::Arc::new(file));
422430
}

src/local/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ impl MainHandle {
450450
let lock_path = lock_path_for(&path);
451451
let lock_file = std::fs::OpenOptions::new()
452452
.create(true)
453+
.truncate(false)
453454
.read(true)
454455
.write(true)
455456
.open(&lock_path)?;
@@ -588,8 +589,7 @@ fn decode_file(bytes: &[u8], codec: &PageCodec) -> Result<(Vec<u8>, u32), io::Er
588589
}
589590
// Exact-tail invariant: the directory occupies the remainder of the file.
590591
if dir_off
591-
.checked_add(page_count * DIR_ENTRY_LEN)
592-
.map_or(true, |end| end != bytes.len())
592+
.checked_add(page_count * DIR_ENTRY_LEN) != Some(bytes.len())
593593
{
594594
return Err(io::Error::new(
595595
io::ErrorKind::InvalidData,

src/tiered/bench.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,7 @@ impl TurboliteSharedState {
449449
let mut groups_submitted = 0u32;
450450

451451
let Some(ref pool) = self.prefetch_pool else {
452-
return format!(
453-
"{{\"trees_warmed\":[],\"groups_submitted\":0,\"note\":\"no prefetch pool (local mode)\"}}",
454-
);
452+
return "{\"trees_warmed\":[],\"groups_submitted\":0,\"note\":\"no prefetch pool (local mode)\"}".to_string();
455453
};
456454

457455
for access in accesses {

src/tiered/cache_tracking.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl PageBitmap {
105105
/// but safe to call while readers use `is_present()` on existing pages
106106
/// (they only access indices < current len).
107107
pub(crate) fn resize(&mut self, page_count: u64) {
108-
let needed_bytes = (page_count as usize + 7) / 8;
108+
let needed_bytes = (page_count as usize).div_ceil(8);
109109
if self.bits.len() < needed_bytes {
110110
self.bits.resize_with(needed_bytes, || AtomicU8::new(0));
111111
}
@@ -309,7 +309,7 @@ impl SubChunkTracker {
309309
/// Correct for B-tree-aware groups where pages are non-positional.
310310
pub(crate) fn sub_chunk_id_for(&self, gid: u64, index_in_group: u32) -> SubChunkId {
311311
let spf = self.sub_pages_per_frame;
312-
let frame_idx = if spf > 0 { index_in_group / spf } else { 0 };
312+
let frame_idx = index_in_group.checked_div(spf).unwrap_or(0);
313313
SubChunkId {
314314
group_id: gid as u32,
315315
frame_index: frame_idx as u16,
@@ -647,8 +647,7 @@ impl SubChunkTracker {
647647
})
648648
.collect();
649649
let data = serde_json::to_vec(&entries).map_err(|e| {
650-
io::Error::new(
651-
io::ErrorKind::Other,
650+
io::Error::other(
652651
format!("serialize sub-chunk tracker: {}", e),
653652
)
654653
})?;

src/tiered/compact.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,11 @@ pub(crate) fn compact_override_group(
425425
encryption_key,
426426
)?;
427427
let ps = page_size as usize;
428-
for i in 0..group_size {
428+
for (i, slot) in page_buffers.iter_mut().enumerate().take(group_size) {
429429
let start = i * ps;
430430
let end = start + ps;
431431
if end <= bulk_data.len() {
432-
page_buffers[i] = Some(bulk_data[start..end].to_vec());
432+
*slot = Some(bulk_data[start..end].to_vec());
433433
}
434434
}
435435
} else {
@@ -468,11 +468,11 @@ pub(crate) fn compact_override_group(
468468
let frame_start = frame_idx * sub_ppf as usize;
469469
let frame_end = std::cmp::min(frame_start + sub_ppf as usize, group_size);
470470
let ps = page_size as usize;
471-
for pos in frame_start..frame_end {
472-
let offset_in_frame = (pos - frame_start) * ps;
471+
for (i, slot) in page_buffers[frame_start..frame_end].iter_mut().enumerate() {
472+
let offset_in_frame = i * ps;
473473
let end = offset_in_frame + ps;
474474
if end <= decompressed.len() {
475-
page_buffers[pos] = Some(decompressed[offset_in_frame..end].to_vec());
475+
*slot = Some(decompressed[offset_in_frame..end].to_vec());
476476
}
477477
}
478478
}

src/tiered/config.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ use super::*;
44

55
/// Where to load the manifest on connection open.
66
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7+
#[derive(Default)]
78
pub enum ManifestSource {
89
/// Use local manifest if present, fall back to remote. Correct for single-writer.
910
/// Checkpoints keep the local cache fresh; no remote fetch on warm reconnect.
11+
#[default]
1012
Auto,
1113
/// Always fetch from the remote backend on open. For HA followers and
1214
/// multi-reader setups where another process may have checkpointed.
@@ -15,31 +17,23 @@ pub enum ManifestSource {
1517
S3,
1618
}
1719

18-
impl Default for ManifestSource {
19-
fn default() -> Self {
20-
ManifestSource::Auto
21-
}
22-
}
2320

2421
// ===== Checkpoint mode =====
2522

2623
/// How checkpoints interact with the configured storage backend.
2724
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
25+
#[derive(Default)]
2826
pub enum CheckpointMode {
2927
/// A SQLite checkpoint uploads dirty page groups to the backend before
3028
/// returning. This is the default durability mode.
29+
#[default]
3130
Durable,
3231
/// A SQLite checkpoint commits into the local cache/staging log and returns
3332
/// without backend I/O. Call `flush_to_storage()` to publish the exact
3433
/// checkpointed image to the backend later.
3534
LocalThenFlush,
3635
}
3736

38-
impl Default for CheckpointMode {
39-
fn default() -> Self {
40-
CheckpointMode::Durable
41-
}
42-
}
4337

4438
// ===== Legacy sync mode =====
4539

@@ -53,36 +47,31 @@ impl Default for CheckpointMode {
5347
note = "use TurboliteConfig.cache.checkpoint_mode instead"
5448
)]
5549
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
50+
#[derive(Default)]
51+
// S3Primary is the deprecated default; the derived Default references it on
52+
// purpose for back-compat with existing serialized configs.
53+
#[allow(deprecated)]
5654
pub enum SyncMode {
55+
#[default]
5756
S3Primary,
5857
LocalThenFlush,
5958
}
6059

61-
#[allow(deprecated)]
62-
impl Default for SyncMode {
63-
fn default() -> Self {
64-
SyncMode::S3Primary
65-
}
66-
}
67-
6860
// ===== Grouping strategy =====
6961

7062
/// Grouping strategy marker. Only BTreeAware is supported.
7163
/// Kept as an enum for serde backward compatibility with existing manifests.
7264
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
65+
#[derive(Default)]
7366
pub enum GroupingStrategy {
7467
/// Legacy positional mapping. No longer used for new databases.
7568
/// Existing Positional manifests are read-only compatible.
7669
Positional,
7770
/// B-tree-aware: explicit page-to-group mapping from btree walking.
71+
#[default]
7872
BTreeAware,
7973
}
8074

81-
impl Default for GroupingStrategy {
82-
fn default() -> Self {
83-
GroupingStrategy::BTreeAware
84-
}
85-
}
8675

8776
// ===== Group state for prefetch coordination =====
8877

@@ -315,7 +304,6 @@ impl PrefetchConfig {
315304
_ => ManifestSource::Auto,
316305
})
317306
.unwrap_or(d.manifest_source),
318-
..d
319307
}
320308
}
321309
}

0 commit comments

Comments
 (0)