@@ -14,7 +14,7 @@ use std::{
1414} ;
1515
1616use linera_base:: ensure;
17- use rocksdb:: { BlockBasedOptions , Cache , DBCompactionStyle } ;
17+ use rocksdb:: { BlockBasedOptions , Cache , DBCompactionStyle , SliceTransform } ;
1818use serde:: { Deserialize , Serialize } ;
1919use sysinfo:: { CpuRefreshKind , MemoryRefreshKind , RefreshKind , System } ;
2020use tempfile:: TempDir ;
@@ -166,25 +166,38 @@ impl RocksDbStoreExecutor {
166166 Ok ( entries. into_iter ( ) . collect :: < Result < _ , _ > > ( ) ?)
167167 }
168168
169+ fn get_find_prefix_read_opts ( & self , prefix : & [ u8 ] ) -> rocksdb:: ReadOptions {
170+ // Configure ReadOptions optimized for SSDs and iterator performance
171+ let mut read_opts = rocksdb:: ReadOptions :: default ( ) ;
172+ // Enable async I/O for better concurrency
173+ read_opts. set_async_io ( true ) ;
174+
175+ // Set precise upper bound to minimize key traversal
176+ let upper_bound = get_upper_bound_option ( prefix) ;
177+ if let Some ( upper_bound) = upper_bound {
178+ read_opts. set_iterate_upper_bound ( upper_bound) ;
179+ }
180+ read_opts
181+ }
182+
169183 fn find_keys_by_prefix_internal (
170184 & self ,
171185 key_prefix : Vec < u8 > ,
172186 ) -> Result < Vec < Vec < u8 > > , RocksDbStoreInternalError > {
173187 check_key_size ( & key_prefix) ?;
188+
174189 let mut prefix = self . start_key . clone ( ) ;
175190 prefix. extend ( key_prefix) ;
176191 let len = prefix. len ( ) ;
177- let mut iter = self . db . raw_iterator ( ) ;
178- let mut keys = Vec :: new ( ) ;
192+
193+ let read_opts = self . get_find_prefix_read_opts ( & prefix) ;
194+ let mut iter = self . db . raw_iterator_opt ( read_opts) ;
179195 iter. seek ( & prefix) ;
180- let mut next_key = iter. key ( ) ;
181- while let Some ( key) = next_key {
182- if !key. starts_with ( & prefix) {
183- break ;
184- }
196+
197+ let mut keys = Vec :: new ( ) ;
198+ while let Some ( key) = iter. key ( ) {
185199 keys. push ( key[ len..] . to_vec ( ) ) ;
186200 iter. next ( ) ;
187- next_key = iter. key ( ) ;
188201 }
189202 Ok ( keys)
190203 }
@@ -198,20 +211,18 @@ impl RocksDbStoreExecutor {
198211 let mut prefix = self . start_key . clone ( ) ;
199212 prefix. extend ( key_prefix) ;
200213 let len = prefix. len ( ) ;
201- let mut iter = self . db . raw_iterator ( ) ;
202- let mut key_values = Vec :: new ( ) ;
214+
215+ let read_opts = self . get_find_prefix_read_opts ( & prefix) ;
216+ let mut iter = self . db . raw_iterator_opt ( read_opts) ;
203217 iter. seek ( & prefix) ;
204- let mut next_key = iter. key ( ) ;
205- while let Some ( key) = next_key {
206- if !key. starts_with ( & prefix) {
207- break ;
208- }
218+
219+ let mut key_values = Vec :: new ( ) ;
220+ while let Some ( key) = iter. key ( ) {
209221 if let Some ( value) = iter. value ( ) {
210222 let key_value = ( key[ len..] . to_vec ( ) , value. to_vec ( ) ) ;
211223 key_values. push ( key_value) ;
212224 }
213225 iter. next ( ) ;
214- next_key = iter. key ( ) ;
215226 }
216227 Ok ( key_values)
217228 }
@@ -373,8 +384,32 @@ impl RocksDbStoreInternal {
373384 total_ram / 4 ,
374385 HYPER_CLOCK_CACHE_BLOCK_SIZE ,
375386 ) ) ;
387+
388+ // Configure bloom filters for prefix iteration optimization
389+ block_options. set_bloom_filter ( 10.0 , false ) ;
390+ block_options. set_whole_key_filtering ( false ) ;
391+
392+ // 32KB blocks instead of default 4KB - reduces iterator seeks
393+ block_options. set_block_size ( 32 * 1024 ) ;
394+ // Use latest format for better compression and performance
395+ block_options. set_format_version ( 5 ) ;
396+
376397 options. set_block_based_table_factory ( & block_options) ;
377398
399+ // Configure prefix extraction for bloom filter optimization
400+ // Use 8 bytes: ROOT_KEY_DOMAIN (1 byte) + BCS variant (1-2 bytes) + identifier start (4-5 bytes)
401+ let prefix_extractor = SliceTransform :: create_fixed_prefix ( 8 ) ;
402+ options. set_prefix_extractor ( prefix_extractor) ;
403+
404+ // 12.5% of memtable size for bloom filter
405+ options. set_memtable_prefix_bloom_ratio ( 0.125 ) ;
406+ // Skip bloom filter for memtable when key exists
407+ options. set_optimize_filters_for_hits ( true ) ;
408+ // Use memory-mapped files for faster reads
409+ options. set_allow_mmap_reads ( true ) ;
410+ // Don't use random access pattern since we do prefix scans
411+ options. set_advise_random_on_open ( false ) ;
412+
378413 let db = DB :: open ( & options, path_buf) ?;
379414 let executor = RocksDbStoreExecutor {
380415 db : Arc :: new ( db) ,
0 commit comments