@@ -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,37 @@ impl RocksDbStoreExecutor {
166166 Ok ( entries. into_iter ( ) . collect :: < Result < _ , _ > > ( ) ?)
167167 }
168168
169+ fn get_find_prefix_read_opts ( & self , prefix : Vec < 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. set_iterate_lower_bound ( prefix) ;
181+ read_opts
182+ }
183+
169184 fn find_keys_by_prefix_internal (
170185 & self ,
171186 key_prefix : Vec < u8 > ,
172187 ) -> Result < Vec < Vec < u8 > > , RocksDbStoreInternalError > {
173188 check_key_size ( & key_prefix) ?;
189+
174190 let mut prefix = self . start_key . clone ( ) ;
175191 prefix. extend ( key_prefix) ;
176192 let len = prefix. len ( ) ;
177- let mut iter = self . db . raw_iterator ( ) ;
193+
194+ let read_opts = self . get_find_prefix_read_opts ( prefix) ;
195+ let mut iter = self . db . raw_iterator_opt ( read_opts) ;
178196 let mut keys = Vec :: new ( ) ;
179- 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- }
197+ while let Some ( key) = iter. key ( ) {
185198 keys. push ( key[ len..] . to_vec ( ) ) ;
186199 iter. next ( ) ;
187- next_key = iter. key ( ) ;
188200 }
189201 Ok ( keys)
190202 }
@@ -198,20 +210,16 @@ impl RocksDbStoreExecutor {
198210 let mut prefix = self . start_key . clone ( ) ;
199211 prefix. extend ( key_prefix) ;
200212 let len = prefix. len ( ) ;
201- let mut iter = self . db . raw_iterator ( ) ;
213+
214+ let read_opts = self . get_find_prefix_read_opts ( prefix) ;
215+ let mut iter = self . db . raw_iterator_opt ( read_opts) ;
202216 let mut key_values = Vec :: new ( ) ;
203- 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- }
217+ while let Some ( key) = iter. key ( ) {
209218 if let Some ( value) = iter. value ( ) {
210219 let key_value = ( key[ len..] . to_vec ( ) , value. to_vec ( ) ) ;
211220 key_values. push ( key_value) ;
212221 }
213222 iter. next ( ) ;
214- next_key = iter. key ( ) ;
215223 }
216224 Ok ( key_values)
217225 }
@@ -373,8 +381,32 @@ impl RocksDbStoreInternal {
373381 total_ram / 4 ,
374382 HYPER_CLOCK_CACHE_BLOCK_SIZE ,
375383 ) ) ;
384+
385+ // Configure bloom filters for prefix iteration optimization
386+ block_options. set_bloom_filter ( 10.0 , false ) ;
387+ block_options. set_whole_key_filtering ( false ) ;
388+
389+ // 32KB blocks instead of default 4KB - reduces iterator seeks
390+ block_options. set_block_size ( 32 * 1024 ) ;
391+ // Use latest format for better compression and performance
392+ block_options. set_format_version ( 5 ) ;
393+
376394 options. set_block_based_table_factory ( & block_options) ;
377395
396+ // Configure prefix extraction for bloom filter optimization
397+ // Use 8 bytes: ROOT_KEY_DOMAIN (1 byte) + BCS variant (1-2 bytes) + identifier start (4-5 bytes)
398+ let prefix_extractor = SliceTransform :: create_fixed_prefix ( 8 ) ;
399+ options. set_prefix_extractor ( prefix_extractor) ;
400+
401+ // 12.5% of memtable size for bloom filter
402+ options. set_memtable_prefix_bloom_ratio ( 0.125 ) ;
403+ // Skip bloom filter for memtable when key exists
404+ options. set_optimize_filters_for_hits ( true ) ;
405+ // Use memory-mapped files for faster reads
406+ options. set_allow_mmap_reads ( true ) ;
407+ // Don't use random access pattern since we do prefix scans
408+ options. set_advise_random_on_open ( false ) ;
409+
378410 let db = DB :: open ( & options, path_buf) ?;
379411 let executor = RocksDbStoreExecutor {
380412 db : Arc :: new ( db) ,
0 commit comments