This repository was archived by the owner on Jan 22, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add file-based blob store #2554
Closed
Closed
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
da7a5ac
initial work on simplified blob store. erasure unimplemented; entry a…
mark-solana d6ef456
Add basic storage and retrieval of erasure codes
mark-solana 153ef75
split slot paths (/root/0x7788 => /root/0x77/88)
mark-solana 448efc1
Add and store more per-slot metadata
mark-solana 5151b53
Add per-slot entry retrieval
mark-solana 5860094
moved blob_store tests to integration test folder as that's what they…
mark-solana 2599ec7
created benchmark for blob_store matching db_ledger
mark-solana bbb8198
Batch index and blob writing
mark-solana 819c3e4
Separated out per-slot I/O in prep for async
mark-solana f3f46ab
Move to more free functions; remove excess unwrap
mark-solana ce65462
added append vec; small refactoring
mark-solana 35c3acc
more generic store; support for unique and multiple per-slot values
mark-solana 5c8220a
Make backing store generic over what it stores. BlobStore now mostly …
mark-solana 3a83665
simplify keys and remove generics
mark-solana 1d5af3f
added cross-slot retrieval and tracking of occupied slots
mark-solana 6c3e6f0
fix non-looping loop lint; simplify/correct record iteration logic
mark-solana 6c45524
fix rebase errors
mark-solana 032fb3f
Rebase and fix clippy lints + Rust edition
mark-solana File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
#![feature(test)] | ||
use rand; | ||
|
||
extern crate test; | ||
|
||
use solana::blob_store::{get_tmp_store_path, BlobStore}; | ||
use solana::entry::{make_large_test_entries, make_tiny_test_entries, EntrySlice}; | ||
use solana::packet::Blob; | ||
|
||
use rand::seq::SliceRandom; | ||
use rand::{thread_rng, Rng}; | ||
use test::Bencher; | ||
|
||
// Given some blobs and a ledger at ledger_path, benchmark writing the blobs to the ledger | ||
fn bench_write_blobs(bench: &mut Bencher, blobs: &mut [Blob], ledger_path: &str) { | ||
let mut store = BlobStore::open(&ledger_path).unwrap(); | ||
|
||
bench.iter(move || { | ||
store.put_blobs(&blobs[..]).expect("Failed to insert blobs"); | ||
}); | ||
|
||
BlobStore::destroy(&ledger_path).expect("Expected successful database destruction"); | ||
} | ||
|
||
// Insert some blobs into the ledger in preparation for read benchmarks | ||
fn setup_read_bench(store: &mut BlobStore, num_small_blobs: u64, num_large_blobs: u64, slot: u64) { | ||
// Make some big and small entries | ||
let mut entries = make_large_test_entries(num_large_blobs as usize); | ||
entries.extend(make_tiny_test_entries(num_small_blobs as usize)); | ||
|
||
// Convert the entries to blobs, write the blobs to the ledger | ||
let mut blobs = entries.to_blobs(); | ||
for (index, b) in blobs.iter_mut().enumerate() { | ||
b.set_index(index as u64); | ||
b.set_slot(slot); | ||
} | ||
|
||
store | ||
.put_blobs(&blobs) | ||
.expect("Expectd successful insertion of blobs into ledger"); | ||
} | ||
|
||
// Write small blobs to the ledger | ||
#[bench] | ||
#[ignore] | ||
fn bench_write_small(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_write_small").unwrap(); | ||
let num_entries = 32 * 1024; | ||
let entries = make_tiny_test_entries(num_entries); | ||
let mut blobs = entries.to_blobs(); | ||
for (index, b) in blobs.iter_mut().enumerate() { | ||
b.set_index(index as u64); | ||
} | ||
bench_write_blobs(bench, &mut blobs, &ledger_path.to_string_lossy()); | ||
} | ||
|
||
// Write big blobs to the ledger | ||
#[bench] | ||
#[ignore] | ||
fn bench_write_big(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_write_big").unwrap(); | ||
let num_entries = 1 * 1024; | ||
let entries = make_large_test_entries(num_entries); | ||
let mut blobs = entries.to_blobs(); | ||
for (index, b) in blobs.iter_mut().enumerate() { | ||
b.set_index(index as u64); | ||
} | ||
|
||
bench_write_blobs(bench, &mut blobs, &ledger_path.to_string_lossy()); | ||
} | ||
|
||
#[bench] | ||
#[ignore] | ||
fn bench_read_sequential(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_read_sequential").unwrap(); | ||
let mut store = BlobStore::open(&ledger_path).unwrap(); | ||
|
||
// Insert some big and small blobs into the ledger | ||
let num_small_blobs = 32 * 1024; | ||
let num_large_blobs = 32 * 1024; | ||
let total_blobs = num_small_blobs + num_large_blobs; | ||
let slot = 0; | ||
setup_read_bench(&mut store, num_small_blobs, num_large_blobs, slot); | ||
|
||
let num_reads = total_blobs / 15; | ||
let mut rng = rand::thread_rng(); | ||
bench.iter(move || { | ||
// Generate random starting point in the range [0, total_blobs - 1], read num_reads blobs sequentially | ||
let start_index = rng.gen_range(0, num_small_blobs + num_large_blobs); | ||
for i in start_index..start_index + num_reads { | ||
let _ = store.get_blob_data(slot, i as u64 % total_blobs); | ||
} | ||
}); | ||
|
||
BlobStore::destroy(&ledger_path).expect("Expected successful database destruction"); | ||
} | ||
|
||
#[bench] | ||
#[ignore] | ||
fn bench_read_random(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_read_random").unwrap(); | ||
let mut store = BlobStore::open(&ledger_path).unwrap(); | ||
|
||
// Insert some big and small blobs into the ledger | ||
let num_small_blobs = 32 * 1024; | ||
let num_large_blobs = 32 * 1024; | ||
let total_blobs = num_small_blobs + num_large_blobs; | ||
let slot = 0; | ||
setup_read_bench(&mut store, num_small_blobs, num_large_blobs, slot); | ||
|
||
let num_reads = total_blobs / 15; | ||
|
||
// Generate a num_reads sized random sample of indexes in range [0, total_blobs - 1], | ||
// simulating random reads | ||
let mut rng = rand::thread_rng(); | ||
let indexes: Vec<usize> = (0..num_reads) | ||
.map(|_| rng.gen_range(0, total_blobs) as usize) | ||
.collect(); | ||
bench.iter(move || { | ||
for i in indexes.iter() { | ||
let _ = store.get_blob_data(slot, *i as u64); | ||
} | ||
}); | ||
|
||
BlobStore::destroy(&ledger_path).expect("Expected successful database destruction"); | ||
} | ||
|
||
#[bench] | ||
#[ignore] | ||
fn bench_insert_data_blob_small(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_insert_data_blob_small").unwrap(); | ||
let mut store = BlobStore::open(&ledger_path).unwrap(); | ||
let num_entries = 32 * 1024; | ||
let entries = make_tiny_test_entries(num_entries); | ||
let mut blobs = entries.to_blobs(); | ||
|
||
blobs.shuffle(&mut thread_rng()); | ||
|
||
bench.iter(move || { | ||
for blob in blobs.iter_mut() { | ||
let index = blob.index(); | ||
blob.set_index(index + num_entries as u64); | ||
} | ||
store.put_blobs(&blobs).unwrap(); | ||
}); | ||
|
||
BlobStore::destroy(&ledger_path).expect("Expect successful destruction"); | ||
} | ||
|
||
#[bench] | ||
#[ignore] | ||
fn bench_insert_data_blob_big(bench: &mut Bencher) { | ||
let ledger_path = get_tmp_store_path("bench_insert_data_blob_big").unwrap(); | ||
let mut store = BlobStore::open(&ledger_path).unwrap(); | ||
let num_entries = 32 * 1024; | ||
let entries = make_large_test_entries(num_entries); | ||
let mut blobs = entries.to_blobs(); | ||
blobs.shuffle(&mut thread_rng()); | ||
|
||
bench.iter(move || { | ||
let mut i = 0; | ||
for blob in blobs.iter_mut() { | ||
blob.set_index(i + num_entries as u64); | ||
i += 1; | ||
} | ||
|
||
store.put_blobs(&blobs).expect("failed to insert blobs"); | ||
}); | ||
|
||
BlobStore::destroy(&ledger_path).expect("Expect successful destruction"); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you intending to verify that caching helps, once implemented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I've also experimented with parallelizing writing (partitioned based on slots) but I couldn't get it to work safely without needing to copy so much memory that it was much slower overall.
The little caching I've done so far made benchmark ns/iter ~70-80% of
db_ledger
benchmarks when before it was about ~110-120% .I tried several different ways of exploiting concurrency including using
tokio
and futures, creating a separate writer thread that communicated overstd::sync::mpsc
andcrossbeam-channel::
channels, etc.But I could not do it both 1) safely 2) without so much copying that it made everything much slower.