Skip to content

Unwrap Remediation Quick Reference

Unwrap Remediation Quick Reference

Quick access guide for Week 1 unwrap elimination


Top 20 Files by Critical Unwrap Count

Fix these first - highest crash risk

#CriticalHighTotalFileEstimated Time
134059heliosdb-protocols/src/oracle/aq_engine.rs1h
224028heliosdb-compute/src/metadata_cache.rs45m
322034heliosdb-protocols/src/oracle/packages/dbms_aqadm.rs45m
421052heliosdb-protocols/src/oracle/packages/dbms_datapump.rs1h
519032heliosdb-protocols/src/oracle/packages/dbms_lob.rs45m
616020heliosdb-security/src/rls/oracle_policy.rs30m
714223heliosdb-protocols/src/oracle/packages/dbms_sql.rs45m
812174heliosdb-streaming/src/key_management.rs1h 30m
912024heliosdb-protocols/src/oracle/packages/dbms_output.rs30m
1012021heliosdb-protocols/src/oracle/packages/utl_file.rs30m
1111121heliosdb-protocols/src/oracle/packages/dbms_rls.rs30m
1211026heliosdb-protocols/src/oracle/packages/dbms_fga.rs45m
1311019heliosdb-protocols/src/oracle/packages/dbms_job.rs30m
1411015heliosdb-compute/src/cache_invalidation.rs30m
1510010heliosdb-protocols/src/oracle/packages/dbms_scheduler.rs20m
16808heliosdb-compute/src/query_coordinator.rs15m
17708heliosdb-compute/src/tracking.rs15m
18707heliosdb-protocols/src/oracle/packages/dbms_random.rs15m
19606heliosdb-protocols/src/oracle/packages/dbms_stats.rs15m
20505heliosdb-protocols/src/oracle/packages/dbms_session.rs10m

Top 20 Total: 263 critical unwraps (~79% of all critical unwraps) Estimated Time: ~12 hours


Common Pattern Fixes

1. Lock Unwraps (284 total - MOST COMMON)

Before (Dangerous):

let mut sessions = self.sessions.write().unwrap();
let data = self.cache.lock().unwrap();
let guard = self.state.read().unwrap();

After (Safe):

let mut sessions = self.sessions.write()
.map_err(|e| Error::LockPoisoned("sessions"))?;
let data = self.cache.lock()
.map_err(|e| Error::LockPoisoned("cache"))?;
let guard = self.state.read()
.map_err(|e| Error::LockPoisoned("state"))?;

Best (parking_lot - No unwrap needed):

// Add to Cargo.toml: parking_lot = "0.12"
use parking_lot::{RwLock, Mutex};
// Direct access, never fails
let mut sessions = self.sessions.write();
let data = self.cache.lock();
let guard = self.state.read();

Files affected: 25+ files across protocols, compute, streaming


2. I/O Operations (35 total)

Before (Data loss risk):

file.read_exact(&mut buffer).unwrap();
writer.write_all(&data).unwrap();
fs::create_dir_all(&path).unwrap();

After (Recoverable):

file.read_exact(&mut buffer)
.map_err(|e| StorageError::ReadFailed {
path: path.clone(),
source: e
})?;
writer.write_all(&data)
.map_err(|e| StorageError::WriteFailed {
path: path.clone(),
source: e
})?;
fs::create_dir_all(&path)
.map_err(|e| StorageError::CreateDirFailed {
path: path.clone(),
source: e
})?;

Files affected: heliosdb-storage (SSTable, WAL, compaction)


3. Array/Collection Access (12 total)

Before (Index panic):

let first = items.first().unwrap();
let last = results.last().unwrap();
let value = buckets[0].unwrap();

After (Safe with context):

let first = items.first()
.ok_or(Error::EmptyCollection("items"))?;
let last = results.last()
.ok_or(Error::NoResults)?;
let value = buckets.get(0)
.ok_or(Error::InvalidBucketIndex(0))?;

Files affected:

  • heliosdb-storage/src/sstable/reader.rs
  • heliosdb-compute/src/optimizer.rs
  • heliosdb-compute/src/online_aggregation.rs

4. Parse Operations (161 total)

Before (Panic on invalid input):

let num = s.parse::<u64>().unwrap();
let json = serde_json::from_str(&data).unwrap();
let addr = SocketAddr::from_str(&s).unwrap();

After (Descriptive errors):

let num = s.parse::<u64>()
.map_err(|e| ParseError::InvalidInteger {
input: s.to_string(),
source: e
})?;
let json = serde_json::from_str(&data)
.map_err(|e| ParseError::InvalidJson {
data: truncate(&data, 100),
source: e
})?;
let addr = SocketAddr::from_str(&s)
.map_err(|e| ParseError::InvalidSocketAddr {
input: s.to_string(),
source: e
})?;

Files affected: Protocol parsers, configuration, SQL engines


5. HashMap Access (30 total)

Before (Panic on missing key):

let value = map.get(&key).unwrap();
let entry = cache.remove(&id).unwrap();

After (Explicit key not found):

let value = map.get(&key)
.ok_or_else(|| Error::KeyNotFound {
key: key.clone()
})?;
let entry = cache.remove(&id)
.ok_or_else(|| Error::CacheEntryNotFound {
id: id.clone()
})?;

Files affected: Various caches, state managers


6. SystemTime Operations (Rare but critical)

Before (Can panic on time going backwards):

let ts = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();

After (Handles time anomalies):

let ts = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| {
warn!("System time before UNIX_EPOCH, using 0");
Duration::from_secs(0)
})
.as_secs();

Files affected:

  • heliosdb-streaming/src/key_management.rs (3 instances)

Day-by-Day Plan

Day 2: Lock Unwraps (6 hours)

Goal: Eliminate 204 lock unwraps in heliosdb-protocols

Files (in order):

  1. oracle/aq_engine.rs (34 critical)
  2. oracle/packages/dbms_datapump.rs (21 critical)
  3. oracle/packages/dbms_aqadm.rs (22 critical)
  4. oracle/packages/dbms_lob.rs (19 critical)
  5. oracle/packages/dbms_sql.rs (14 critical)
  6. oracle/packages/dbms_output.rs (12 critical)
  7. oracle/packages/utl_file.rs (12 critical)
  8. oracle/packages/dbms_rls.rs (11 critical)
  9. oracle/packages/dbms_fga.rs (11 critical)
  10. oracle/packages/dbms_job.rs (11 critical)

Remaining Oracle packages: dbms_scheduler, dbms_random, dbms_stats, etc.


Day 3: Compute + Streaming Locks (4 hours)

Goal: Eliminate 64 lock unwraps

heliosdb-compute:

  1. metadata_cache.rs (24 critical) ⭐ Hot path
  2. cache_invalidation.rs (11 critical)
  3. query_coordinator.rs (8 critical)
  4. tracking.rs (7 critical)

heliosdb-streaming:

  1. key_management.rs (12 critical) ⭐ Includes SystemTime

Day 4: I/O Operations (4 hours)

Goal: Eliminate 35 I/O unwraps in heliosdb-storage

Focus areas:

  • SSTable reader (hot read path)
  • WAL operations (crash safety)
  • Compaction (background operations)

Day 5: Parse Operations (5 hours)

Goal: Eliminate 161 parse unwraps

By crate:

  • heliosdb-protocols: 79 unwraps
  • heliosdb-security: 40 unwraps (JWT parsing)
  • heliosdb-streaming: 23 unwraps
  • heliosdb-storage: 16 unwraps

Day 6: Array + HashMap (3 hours)

Goal: Eliminate 42 unwraps

  • Array access: 12 unwraps
  • HashMap access: 30 unwraps

Day 7: Validation + Testing (6 hours)

Goal: Verify all changes

  1. Top medium-priority files (3 hours)
  2. Full test suite (1 hour)
  3. Performance benchmarks (1 hour)
  4. Manual testing (1 hour)

Testing After Each Fix

Terminal window
# Run tests for specific crate
cd heliosdb-protocols
cargo test --lib
# Run integration tests
cargo test --test '*'
# Check for remaining unwraps
rg '\.unwrap\(\)' src/ --type rust | grep -v '/tests/'
# Performance check
cargo bench

Error Type Examples

Add to each crate’s error.rs:

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Lock poisoned: {resource}")]
LockPoisoned { resource: &'static str },
#[error("I/O error on {path}: {source}")]
IoError {
path: PathBuf,
#[source] source: std::io::Error
},
#[error("Parse error for {field}: expected {expected_type}, got '{value}'")]
ParseError {
field: &'static str,
expected_type: &'static str,
value: String,
#[source] source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Array access error: {context}")]
ArrayAccessError { context: String },
#[error("Key not found: {key}")]
KeyNotFound { key: String },
}

Verification Commands

Check remaining unwraps:

Terminal window
# Production code only
find heliosdb-*/src -name "*.rs" | \
grep -v "/tests/" | \
xargs rg '\.unwrap\(\)' | wc -l
# By crate
for crate in heliosdb-*; do
count=$(find $crate/src -name "*.rs" 2>/dev/null | \
grep -v "/tests/" | \
xargs rg '\.unwrap\(\)' 2>/dev/null | wc -l)
if [ $count -gt 0 ]; then
echo "$crate: $count"
fi
done | sort -t: -k2 -rn

Check for new unwraps:

Terminal window
# Git diff since last commit
git diff HEAD~1 | rg '^\+.*\.unwrap\(\)'

Progress Dashboard

Track progress in this format:

WEEK 1 UNWRAP ELIMINATION PROGRESS
Day 2: Lock Unwraps
[████████████████████--------] 204/204 (100%)
Files: 25/25 ✓
Tests: ✓ Passing
Benchmarks: ✓ No regression
Day 3: Compute + Streaming
[████████████████████--------] 52/64 (81%)
Files: 4/5 ✓
Tests: ✓ Passing
Current: streaming/key_management.rs
Day 4: I/O Operations
[░░░░░░░░░░░░░░░░░░░░--------] 0/35 (0%)
Status: Not started
...

Common Mistakes to Avoid

❌ Don’t just replace with expect():

// Still panics!
let data = self.state.read().expect("Failed to acquire lock");

❌ Don’t use generic error messages:

// Not helpful for debugging
.map_err(|e| Error::Generic(e.to_string()))?

❌ Don’t ignore lock poisoning:

// Hides the real problem
let data = self.state.read().unwrap_or_else(|e| e.into_inner());

Do provide context:

let data = self.state.read()
.map_err(|e| Error::LockPoisoned {
resource: "query_state",
operation: "read_lock",
context: "processing SELECT query"
})?;

Resources


Quick Reference - Updated 2025-11-09