1use std::collections::HashSet;
16use std::fmt::Debug;
17use std::sync::{Arc, LazyLock};
18use std::time::Duration;
19
20use enum_as_inner::EnumAsInner;
21use foyer::{
22 BlockEngineConfig, CacheBuilder, DeviceBuilder, FifoPicker, FsDeviceBuilder, HybridCacheBuilder,
23};
24use futures::FutureExt;
25use futures::future::BoxFuture;
26use mixtrics::registry::prometheus::PrometheusMetricsRegistry;
27use risingwave_common::catalog::TableId;
28use risingwave_common::config::Role;
29use risingwave_common::config::storage::FileCacheRuntimeConfig;
30use risingwave_common::license::Feature;
31use risingwave_common::monitor::GLOBAL_METRICS_REGISTRY;
32use risingwave_common_service::RpcNotificationClient;
33use risingwave_hummock_sdk::{HummockEpoch, HummockSstableObjectId, SyncResult};
34use risingwave_object_store::object::build_remote_object_store;
35use thiserror_ext::AsReport;
36
37use crate::StateStore;
38use crate::compaction_catalog_manager::{CompactionCatalogManager, RemoteTableAccessor};
39use crate::error::StorageResult;
40use crate::hummock::all::AllRecentFilter;
41use crate::hummock::hummock_meta_client::MonitoredHummockMetaClient;
42use crate::hummock::none::NoneRecentFilter;
43use crate::hummock::sharded::ShardedRecentFilter;
44use crate::hummock::simple::SimpleRecentFilter;
45use crate::hummock::{
46 Block, BlockCacheEventListener, HummockError, HummockStorage, Sstable, SstableBlockIndex,
47 SstableStore, SstableStoreConfig,
48};
49use crate::memory::MemoryStateStore;
50use crate::memory::sled::SledStateStore;
51use crate::monitor::{
52 CompactorMetrics, HummockStateStoreMetrics, MonitoredStateStore, MonitoredStorageMetrics,
53 ObjectStoreMetrics,
54};
55use crate::opts::StorageOpts;
56
57fn build_file_cache_spawner(
58 name: &str,
59 config: &FileCacheRuntimeConfig,
60) -> StorageResult<foyer::Spawner> {
61 let config = match config {
62 FileCacheRuntimeConfig::Disabled => return Ok(foyer::Spawner::current()),
63 FileCacheRuntimeConfig::Unified(config) => config.clone(),
64 FileCacheRuntimeConfig::Separated { .. } => {
65 return Err(HummockError::other(format!(
66 "{name} runtime_config.Separated is unsupported with Foyer 0.22; use runtime_config.Unified instead"
67 ))
68 .into());
69 }
70 };
71
72 let mut builder = tokio::runtime::Builder::new_multi_thread();
73 #[cfg(madsim)]
74 let _ = &config;
75 #[cfg(not(madsim))]
76 if config.worker_threads != 0 {
77 builder.worker_threads(config.worker_threads);
78 }
79 #[cfg(not(madsim))]
80 if config.max_blocking_threads != 0 {
81 builder.max_blocking_threads(config.max_blocking_threads);
82 }
83 builder.thread_name(format!("{name}-unified"));
84 let runtime = builder.enable_all().build().map_err(|error| {
85 HummockError::other(format!(
86 "failed to build {name} dedicated runtime: {}",
87 error.as_report()
88 ))
89 })?;
90 Ok(runtime.into())
91}
92
93#[cfg(test)]
94mod tests {
95 use risingwave_common::config::storage::FileCacheTokioRuntimeConfig;
96
97 use super::*;
98
99 #[test]
100 fn test_build_file_cache_spawner_rejects_separated_runtime() {
101 let runtime_options = FileCacheTokioRuntimeConfig {
102 worker_threads: 1,
103 max_blocking_threads: 1,
104 };
105 let error = build_file_cache_spawner(
106 "foyer.test",
107 &FileCacheRuntimeConfig::Separated {
108 read_runtime_options: runtime_options.clone(),
109 write_runtime_options: runtime_options,
110 },
111 )
112 .unwrap_err()
113 .to_string();
114
115 assert!(error.contains("foyer.test runtime_config.Separated"));
116 assert!(error.contains("use runtime_config.Unified instead"));
117 }
118
119 #[cfg(not(madsim))]
120 #[tokio::test]
121 async fn test_build_file_cache_spawner_runtime_modes() {
122 let current_runtime_id = tokio::runtime::Handle::current().id();
123
124 let disabled =
125 build_file_cache_spawner("foyer.test", &FileCacheRuntimeConfig::Disabled).unwrap();
126 let disabled_runtime_id = disabled
127 .spawn(async { tokio::runtime::Handle::current().id() })
128 .await
129 .unwrap();
130 assert_eq!(disabled_runtime_id, current_runtime_id);
131
132 let unified = build_file_cache_spawner(
133 "foyer.test",
134 &FileCacheRuntimeConfig::Unified(FileCacheTokioRuntimeConfig {
135 worker_threads: 1,
136 max_blocking_threads: 1,
137 }),
138 )
139 .unwrap();
140 let (unified_runtime_id, thread_name) = unified
141 .spawn(async {
142 (
143 tokio::runtime::Handle::current().id(),
144 std::thread::current().name().map(str::to_owned),
145 )
146 })
147 .await
148 .unwrap();
149
150 assert_ne!(unified_runtime_id, current_runtime_id);
151 assert_eq!(thread_name.as_deref(), Some("foyer.test-unified"));
152 }
153}
154
155static FOYER_METRICS_REGISTRY: LazyLock<Box<PrometheusMetricsRegistry>> = LazyLock::new(|| {
156 Box::new(PrometheusMetricsRegistry::new(
157 GLOBAL_METRICS_REGISTRY.clone(),
158 ))
159});
160
161mod opaque_type {
162 use super::*;
163
164 pub type HummockStorageType = impl StateStore + AsHummock;
165 pub type MemoryStateStoreType = impl StateStore + AsHummock;
166 pub type SledStateStoreType = impl StateStore + AsHummock;
167
168 #[define_opaque(MemoryStateStoreType)]
169 pub fn in_memory(state_store: MemoryStateStore) -> MemoryStateStoreType {
170 may_dynamic_dispatch(state_store)
171 }
172
173 #[define_opaque(HummockStorageType)]
174 pub fn hummock(state_store: HummockStorage) -> HummockStorageType {
175 may_dynamic_dispatch(may_verify(state_store))
176 }
177
178 #[define_opaque(SledStateStoreType)]
179 pub fn sled(state_store: SledStateStore) -> SledStateStoreType {
180 may_dynamic_dispatch(state_store)
181 }
182}
183pub use opaque_type::{HummockStorageType, MemoryStateStoreType, SledStateStoreType};
184use opaque_type::{hummock, in_memory, sled};
185
186#[cfg(feature = "hm-trace")]
187type Monitored<S> = MonitoredStateStore<crate::monitor::traced_store::TracedStateStore<S>>;
188
189#[cfg(not(feature = "hm-trace"))]
190type Monitored<S> = MonitoredStateStore<S>;
191
192fn monitored<S: StateStore>(
193 state_store: S,
194 storage_metrics: Arc<MonitoredStorageMetrics>,
195) -> Monitored<S> {
196 let inner = {
197 #[cfg(feature = "hm-trace")]
198 {
199 crate::monitor::traced_store::TracedStateStore::new_global(state_store)
200 }
201 #[cfg(not(feature = "hm-trace"))]
202 {
203 state_store
204 }
205 };
206 inner.monitored(storage_metrics)
207}
208
209fn inner<S>(state_store: &Monitored<S>) -> &S {
210 let inner = state_store.inner();
211 {
212 #[cfg(feature = "hm-trace")]
213 {
214 inner.inner()
215 }
216 #[cfg(not(feature = "hm-trace"))]
217 {
218 inner
219 }
220 }
221}
222
223#[derive(Clone, EnumAsInner)]
225#[expect(clippy::enum_variant_names)]
226pub enum StateStoreImpl {
227 HummockStateStore(Monitored<HummockStorageType>),
236 MemoryStateStore(Monitored<MemoryStateStoreType>),
241 SledStateStore(Monitored<SledStateStoreType>),
242}
243
244fn may_dynamic_dispatch(state_store: impl StateStore + AsHummock) -> impl StateStore + AsHummock {
245 #[cfg(not(debug_assertions))]
246 {
247 state_store
248 }
249 #[cfg(debug_assertions)]
250 {
251 use crate::store_impl::dyn_state_store::StateStorePointer;
252 StateStorePointer(Arc::new(state_store) as _)
253 }
254}
255
256fn may_verify(state_store: impl StateStore + AsHummock) -> impl StateStore + AsHummock {
257 #[cfg(not(debug_assertions))]
258 {
259 state_store
260 }
261 #[cfg(debug_assertions)]
262 {
263 use std::marker::PhantomData;
264
265 use risingwave_common::util::env_var::env_var_is_true;
266 use tracing::info;
267
268 use crate::store_impl::verify::VerifyStateStore;
269
270 let expected = if env_var_is_true("ENABLE_STATE_STORE_VERIFY") {
271 info!("enable verify state store");
272 Some(SledStateStore::new_temp())
273 } else {
274 info!("verify state store is not enabled");
275 None
276 };
277 VerifyStateStore {
278 actual: state_store,
279 expected,
280 _phantom: PhantomData::<()>,
281 }
282 }
283}
284
285impl StateStoreImpl {
286 fn in_memory(
287 state_store: MemoryStateStore,
288 storage_metrics: Arc<MonitoredStorageMetrics>,
289 ) -> Self {
290 Self::MemoryStateStore(monitored(in_memory(state_store), storage_metrics))
292 }
293
294 pub fn hummock(
295 state_store: HummockStorage,
296 storage_metrics: Arc<MonitoredStorageMetrics>,
297 ) -> Self {
298 Self::HummockStateStore(monitored(hummock(state_store), storage_metrics))
300 }
301
302 pub fn sled(
303 state_store: SledStateStore,
304 storage_metrics: Arc<MonitoredStorageMetrics>,
305 ) -> Self {
306 Self::SledStateStore(monitored(sled(state_store), storage_metrics))
307 }
308
309 pub fn shared_in_memory_store(storage_metrics: Arc<MonitoredStorageMetrics>) -> Self {
310 Self::in_memory(MemoryStateStore::shared(), storage_metrics)
311 }
312
313 pub fn for_test() -> Self {
314 Self::in_memory(
315 MemoryStateStore::new(),
316 Arc::new(MonitoredStorageMetrics::unused()),
317 )
318 }
319
320 pub fn as_hummock(&self) -> Option<&HummockStorage> {
321 match self {
322 StateStoreImpl::HummockStateStore(hummock) => {
323 Some(inner(hummock).as_hummock().expect("should be hummock"))
324 }
325 _ => None,
326 }
327 }
328}
329
330impl Debug for StateStoreImpl {
331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 match self {
333 StateStoreImpl::HummockStateStore(_) => write!(f, "HummockStateStore"),
334 StateStoreImpl::MemoryStateStore(_) => write!(f, "MemoryStateStore"),
335 StateStoreImpl::SledStateStore(_) => write!(f, "SledStateStore"),
336 }
337 }
338}
339
340#[macro_export]
341macro_rules! dispatch_state_store {
342 ($impl:expr, $store:ident, $body:tt) => {{
343 use $crate::store_impl::StateStoreImpl;
344
345 match $impl {
346 StateStoreImpl::MemoryStateStore($store) => {
347 #[cfg(debug_assertions)]
350 {
351 $body
352 }
353 #[cfg(not(debug_assertions))]
354 {
355 let _store = $store;
356 unimplemented!("memory state store should never be used in release mode");
357 }
358 }
359
360 StateStoreImpl::SledStateStore($store) => {
361 #[cfg(debug_assertions)]
364 {
365 $body
366 }
367 #[cfg(not(debug_assertions))]
368 {
369 let _store = $store;
370 unimplemented!("sled state store should never be used in release mode");
371 }
372 }
373
374 StateStoreImpl::HummockStateStore($store) => $body,
375 }
376 }};
377}
378
379#[cfg(any(debug_assertions, test, feature = "test"))]
380pub mod verify {
381 use std::fmt::Debug;
382 use std::future::Future;
383 use std::marker::PhantomData;
384 use std::ops::Deref;
385 use std::sync::Arc;
386
387 use bytes::Bytes;
388 use risingwave_common::array::VectorRef;
389 use risingwave_common::bitmap::Bitmap;
390 use risingwave_common::hash::VirtualNode;
391 use risingwave_hummock_sdk::HummockReadEpoch;
392 use risingwave_hummock_sdk::key::{FullKey, TableKey, TableKeyRange};
393 use tracing::log::warn;
394
395 use crate::error::StorageResult;
396 use crate::hummock::HummockStorage;
397 use crate::store::*;
398 use crate::store_impl::AsHummock;
399
400 #[expect(dead_code)]
401 fn assert_result_eq<Item: PartialEq + Debug, E>(
402 first: &std::result::Result<Item, E>,
403 second: &std::result::Result<Item, E>,
404 ) {
405 match (first, second) {
406 (Ok(first), Ok(second)) => {
407 if first != second {
408 warn!("result different: {:?} {:?}", first, second);
409 }
410 assert_eq!(first, second);
411 }
412 (Err(_), Err(_)) => {}
413 _ => {
414 warn!("one success and one failed");
415 panic!("result not equal");
416 }
417 }
418 }
419
420 #[derive(Clone)]
421 pub struct VerifyStateStore<A, E, T = ()> {
422 pub actual: A,
423 pub expected: Option<E>,
424 pub _phantom: PhantomData<T>,
425 }
426
427 impl<A: AsHummock, E: AsHummock> AsHummock for VerifyStateStore<A, E> {
428 fn as_hummock(&self) -> Option<&HummockStorage> {
429 self.actual.as_hummock()
430 }
431 }
432
433 impl<A: StateStoreGet, E: StateStoreGet> StateStoreGet for VerifyStateStore<A, E> {
434 async fn on_key_value<'a, O: Send + 'a>(
435 &'a self,
436 key: TableKey<Bytes>,
437 read_options: ReadOptions,
438 on_key_value_fn: impl KeyValueFn<'a, O>,
439 ) -> StorageResult<Option<O>> {
440 let actual: Option<(FullKey<Bytes>, Bytes)> = self
441 .actual
442 .on_key_value(key.clone(), read_options.clone(), |key, value| {
443 Ok((key.copy_into(), Bytes::copy_from_slice(value)))
444 })
445 .await?;
446 if let Some(expected) = &self.expected {
447 let expected: Option<(FullKey<Bytes>, Bytes)> = expected
448 .on_key_value(key, read_options, |key, value| {
449 Ok((key.copy_into(), Bytes::copy_from_slice(value)))
450 })
451 .await?;
452 assert_eq!(
453 actual
454 .as_ref()
455 .map(|item| (item.0.epoch_with_gap.pure_epoch(), item)),
456 expected
457 .as_ref()
458 .map(|item| (item.0.epoch_with_gap.pure_epoch(), item))
459 );
460 }
461
462 actual
463 .map(|(key, value)| on_key_value_fn(key.to_ref(), value.as_ref()))
464 .transpose()
465 }
466 }
467
468 impl<A: StateStoreReadVector, E: StateStoreReadVector> StateStoreReadVector
469 for VerifyStateStore<A, E>
470 {
471 fn nearest<'a, O: Send + 'a>(
472 &'a self,
473 vec: VectorRef<'a>,
474 options: VectorNearestOptions,
475 on_nearest_item_fn: impl OnNearestItemFn<'a, O>,
476 ) -> impl StorageFuture<'a, Vec<O>> {
477 self.actual.nearest(vec, options, on_nearest_item_fn)
478 }
479 }
480
481 impl<A: StateStoreRead, E: StateStoreRead> StateStoreRead for VerifyStateStore<A, E> {
482 type Iter = impl StateStoreReadIter;
483 type RevIter = impl StateStoreReadIter;
484
485 #[expect(clippy::manual_async_fn)]
488 fn iter(
489 &self,
490 key_range: TableKeyRange,
491
492 read_options: ReadOptions,
493 ) -> impl Future<Output = StorageResult<Self::Iter>> + '_ {
494 async move {
495 let actual = self
496 .actual
497 .iter(key_range.clone(), read_options.clone())
498 .await?;
499 let expected = if let Some(expected) = &self.expected {
500 Some(expected.iter(key_range, read_options).await?)
501 } else {
502 None
503 };
504
505 Ok(verify_iter::<StateStoreKeyedRow>(actual, expected))
506 }
507 }
508
509 #[expect(clippy::manual_async_fn)]
510 fn rev_iter(
511 &self,
512 key_range: TableKeyRange,
513
514 read_options: ReadOptions,
515 ) -> impl Future<Output = StorageResult<Self::RevIter>> + '_ {
516 async move {
517 let actual = self
518 .actual
519 .rev_iter(key_range.clone(), read_options.clone())
520 .await?;
521 let expected = if let Some(expected) = &self.expected {
522 Some(expected.rev_iter(key_range, read_options).await?)
523 } else {
524 None
525 };
526
527 Ok(verify_iter::<StateStoreKeyedRow>(actual, expected))
528 }
529 }
530 }
531
532 impl<A: StateStoreReadLog, E: StateStoreReadLog> StateStoreReadLog for VerifyStateStore<A, E> {
533 type ChangeLogIter = impl StateStoreReadChangeLogIter;
534
535 async fn next_epoch(&self, epoch: u64, options: NextEpochOptions) -> StorageResult<u64> {
536 let actual = self.actual.next_epoch(epoch, options.clone()).await?;
537 if let Some(expected) = &self.expected {
538 assert_eq!(actual, expected.next_epoch(epoch, options).await?);
539 }
540 Ok(actual)
541 }
542
543 async fn iter_log(
544 &self,
545 epoch_range: (u64, u64),
546 key_range: TableKeyRange,
547 options: ReadLogOptions,
548 ) -> StorageResult<Self::ChangeLogIter> {
549 let actual = self
550 .actual
551 .iter_log(epoch_range, key_range.clone(), options.clone())
552 .await?;
553 let expected = if let Some(expected) = &self.expected {
554 Some(expected.iter_log(epoch_range, key_range, options).await?)
555 } else {
556 None
557 };
558
559 Ok(verify_iter::<StateStoreReadLogItem>(actual, expected))
560 }
561 }
562
563 impl<A: StateStoreIter<T>, E: StateStoreIter<T>, T: IterItem> StateStoreIter<T>
564 for VerifyStateStore<A, E, T>
565 where
566 for<'a> T::ItemRef<'a>: PartialEq + Debug,
567 {
568 async fn try_next(&mut self) -> StorageResult<Option<T::ItemRef<'_>>> {
569 let actual = self.actual.try_next().await?;
570 if let Some(expected) = self.expected.as_mut() {
571 let expected = expected.try_next().await?;
572 assert_eq!(actual, expected);
573 }
574 Ok(actual)
575 }
576 }
577
578 fn verify_iter<T: IterItem>(
579 actual: impl StateStoreIter<T>,
580 expected: Option<impl StateStoreIter<T>>,
581 ) -> impl StateStoreIter<T>
582 where
583 for<'a> T::ItemRef<'a>: PartialEq + Debug,
584 {
585 VerifyStateStore {
586 actual,
587 expected,
588 _phantom: PhantomData::<T>,
589 }
590 }
591
592 impl<A: LocalStateStore, E: LocalStateStore> LocalStateStore for VerifyStateStore<A, E> {
593 type FlushedSnapshotReader =
594 VerifyStateStore<A::FlushedSnapshotReader, E::FlushedSnapshotReader>;
595
596 type Iter<'a> = impl StateStoreIter + 'a;
597 type RevIter<'a> = impl StateStoreIter + 'a;
598
599 #[expect(clippy::manual_async_fn)]
600 fn iter(
601 &self,
602 key_range: TableKeyRange,
603 read_options: ReadOptions,
604 ) -> impl Future<Output = StorageResult<Self::Iter<'_>>> + Send + '_ {
605 async move {
606 let actual = self
607 .actual
608 .iter(key_range.clone(), read_options.clone())
609 .await?;
610 let expected = if let Some(expected) = &self.expected {
611 Some(expected.iter(key_range, read_options).await?)
612 } else {
613 None
614 };
615
616 Ok(verify_iter::<StateStoreKeyedRow>(actual, expected))
617 }
618 }
619
620 #[expect(clippy::manual_async_fn)]
621 fn rev_iter(
622 &self,
623 key_range: TableKeyRange,
624 read_options: ReadOptions,
625 ) -> impl Future<Output = StorageResult<Self::RevIter<'_>>> + Send + '_ {
626 async move {
627 let actual = self
628 .actual
629 .rev_iter(key_range.clone(), read_options.clone())
630 .await?;
631 let expected = if let Some(expected) = &self.expected {
632 Some(expected.rev_iter(key_range, read_options).await?)
633 } else {
634 None
635 };
636
637 Ok(verify_iter::<StateStoreKeyedRow>(actual, expected))
638 }
639 }
640
641 fn insert(
642 &mut self,
643 key: TableKey<Bytes>,
644 new_val: Bytes,
645 old_val: Option<Bytes>,
646 ) -> StorageResult<()> {
647 if let Some(expected) = &mut self.expected {
648 expected.insert(key.clone(), new_val.clone(), old_val.clone())?;
649 }
650 self.actual.insert(key, new_val, old_val)?;
651
652 Ok(())
653 }
654
655 fn delete(&mut self, key: TableKey<Bytes>, old_val: Bytes) -> StorageResult<()> {
656 if let Some(expected) = &mut self.expected {
657 expected.delete(key.clone(), old_val.clone())?;
658 }
659 self.actual.delete(key, old_val)?;
660 Ok(())
661 }
662
663 async fn update_vnode_bitmap(&mut self, vnodes: Arc<Bitmap>) -> StorageResult<Arc<Bitmap>> {
664 let ret = self.actual.update_vnode_bitmap(vnodes.clone()).await?;
665 if let Some(expected) = &mut self.expected {
666 assert_eq!(ret, expected.update_vnode_bitmap(vnodes).await?);
667 }
668 Ok(ret)
669 }
670
671 fn get_table_watermark(&self, vnode: VirtualNode) -> Option<Bytes> {
672 let ret = self.actual.get_table_watermark(vnode);
673 if let Some(expected) = &self.expected {
674 assert_eq!(ret, expected.get_table_watermark(vnode));
675 }
676 ret
677 }
678
679 fn new_flushed_snapshot_reader(&self) -> Self::FlushedSnapshotReader {
680 VerifyStateStore {
681 actual: self.actual.new_flushed_snapshot_reader(),
682 expected: self.expected.as_ref().map(E::new_flushed_snapshot_reader),
683 _phantom: Default::default(),
684 }
685 }
686 }
687
688 impl<A: StateStoreWriteEpochControl, E: StateStoreWriteEpochControl> StateStoreWriteEpochControl
689 for VerifyStateStore<A, E>
690 {
691 async fn flush(&mut self) -> StorageResult<usize> {
692 if let Some(expected) = &mut self.expected {
693 expected.flush().await?;
694 }
695 self.actual.flush().await
696 }
697
698 async fn try_flush(&mut self) -> StorageResult<()> {
699 if let Some(expected) = &mut self.expected {
700 expected.try_flush().await?;
701 }
702 self.actual.try_flush().await
703 }
704
705 async fn init(&mut self, options: InitOptions) -> StorageResult<()> {
706 self.actual.init(options.clone()).await?;
707 if let Some(expected) = &mut self.expected {
708 expected.init(options).await?;
709 }
710 Ok(())
711 }
712
713 fn seal_current_epoch(&mut self, next_epoch: u64, opts: SealCurrentEpochOptions) {
714 if let Some(expected) = &mut self.expected {
715 expected.seal_current_epoch(next_epoch, opts.clone());
716 }
717 self.actual.seal_current_epoch(next_epoch, opts);
718 }
719 }
720
721 impl<A: StateStore, E: StateStore> StateStore for VerifyStateStore<A, E> {
722 type Local = VerifyStateStore<A::Local, E::Local>;
723 type ReadSnapshot = VerifyStateStore<A::ReadSnapshot, E::ReadSnapshot>;
724 type VectorWriter = A::VectorWriter;
725
726 fn try_wait_epoch(
727 &self,
728 epoch: HummockReadEpoch,
729 options: TryWaitEpochOptions,
730 ) -> impl Future<Output = StorageResult<()>> + Send + '_ {
731 self.actual.try_wait_epoch(epoch, options)
732 }
733
734 async fn new_local(&self, option: NewLocalOptions) -> Self::Local {
735 let expected = if let Some(expected) = &self.expected {
736 Some(expected.new_local(option.clone()).await)
737 } else {
738 None
739 };
740 VerifyStateStore {
741 actual: self.actual.new_local(option).await,
742 expected,
743 _phantom: PhantomData::<()>,
744 }
745 }
746
747 async fn new_read_snapshot(
748 &self,
749 epoch: HummockReadEpoch,
750 options: NewReadSnapshotOptions,
751 ) -> StorageResult<Self::ReadSnapshot> {
752 let expected = if let Some(expected) = &self.expected {
753 Some(expected.new_read_snapshot(epoch, options).await?)
754 } else {
755 None
756 };
757 Ok(VerifyStateStore {
758 actual: self.actual.new_read_snapshot(epoch, options).await?,
759 expected,
760 _phantom: PhantomData::<()>,
761 })
762 }
763
764 fn new_vector_writer(
765 &self,
766 options: NewVectorWriterOptions,
767 ) -> impl Future<Output = Self::VectorWriter> + Send + '_ {
768 self.actual.new_vector_writer(options)
769 }
770 }
771
772 impl<A, E> Deref for VerifyStateStore<A, E> {
773 type Target = A;
774
775 fn deref(&self) -> &Self::Target {
776 &self.actual
777 }
778 }
779}
780
781impl StateStoreImpl {
782 #[cfg_attr(not(target_os = "linux"), allow(unused_variables))]
783 #[expect(clippy::borrowed_box)]
784 pub async fn new(
785 s: &str,
786 role: Role,
787 opts: Arc<StorageOpts>,
788 hummock_meta_client: Arc<MonitoredHummockMetaClient>,
789 state_store_metrics: Arc<HummockStateStoreMetrics>,
790 object_store_metrics: Arc<ObjectStoreMetrics>,
791 storage_metrics: Arc<MonitoredStorageMetrics>,
792 compactor_metrics: Arc<CompactorMetrics>,
793 await_tree_config: Option<await_tree::Config>,
794 use_new_object_prefix_strategy: bool,
795 ) -> StorageResult<Self> {
796 const KB: usize = 1 << 10;
797 const MB: usize = 1 << 20;
798
799 let meta_cache = {
800 let mut builder = HybridCacheBuilder::new()
801 .with_name("foyer.meta")
802 .with_metrics_registry(FOYER_METRICS_REGISTRY.clone())
803 .memory(opts.meta_cache_capacity_mb * MB)
804 .with_shards(opts.meta_cache_shard_num)
805 .with_eviction_config(opts.meta_cache_eviction_config.clone())
806 .with_weighter(|_: &HummockSstableObjectId, value: &Box<Sstable>| {
807 std::mem::size_of::<HummockSstableObjectId>()
808 + value.estimated_meta_cache_memory_weight()
809 })
810 .storage();
811
812 if !opts.meta_file_cache_dir.is_empty() {
813 if let Err(e) = Feature::ElasticDiskCache.check_available() {
814 tracing::warn!(error = %e.as_report(), "ElasticDiskCache is not available.");
815 } else {
816 let device = FsDeviceBuilder::new(&opts.meta_file_cache_dir)
817 .with_capacity(opts.meta_file_cache_capacity_mb * MB)
818 .with_throttle(opts.meta_file_cache_throttle.clone())
819 .build()
820 .map_err(HummockError::foyer_error)?;
821 let engine_builder = BlockEngineConfig::new(device)
822 .with_block_size(opts.meta_file_cache_file_capacity_mb * MB)
823 .with_indexer_shards(opts.meta_file_cache_indexer_shards)
824 .with_flushers(opts.meta_file_cache_flushers)
825 .with_reclaimers(opts.meta_file_cache_reclaimers)
826 .with_buffer_pool_size(opts.meta_file_cache_flush_buffer_threshold_mb * MB)
827 .with_submit_queue_size_threshold(
828 opts.meta_file_cache_submit_queue_size_threshold_mb * MB,
829 )
830 .with_clean_block_threshold(
831 opts.meta_file_cache_reclaimers + opts.meta_file_cache_reclaimers / 2,
832 )
833 .with_recover_concurrency(opts.meta_file_cache_recover_concurrency)
834 .with_blob_index_size(opts.meta_file_cache_blob_index_size_kb * KB)
835 .with_eviction_pickers(vec![Box::new(FifoPicker::new(
836 opts.meta_file_cache_fifo_probation_ratio,
837 ))]);
838 builder = builder
839 .with_engine_config(engine_builder)
840 .with_recover_mode(opts.meta_file_cache_recover_mode)
841 .with_compression(opts.meta_file_cache_compression);
842 builder = builder.with_spawner(build_file_cache_spawner(
843 "foyer.meta",
844 &opts.meta_file_cache_runtime_config,
845 )?);
846 }
847 }
848
849 builder.build().await.map_err(HummockError::foyer_error)?
850 };
851
852 let block_cache = {
853 let mut builder = HybridCacheBuilder::new()
854 .with_name("foyer.data")
855 .with_metrics_registry(FOYER_METRICS_REGISTRY.clone())
856 .with_event_listener(Arc::new(BlockCacheEventListener::new(
857 state_store_metrics.clone(),
858 )))
859 .memory(opts.block_cache_capacity_mb * MB)
860 .with_shards(opts.block_cache_shard_num)
861 .with_eviction_config(opts.block_cache_eviction_config.clone())
862 .with_weighter(|_: &SstableBlockIndex, value: &Box<Block>| {
863 std::mem::size_of::<SstableBlockIndex>() + value.estimated_memory_weight()
864 })
865 .storage();
866
867 if !opts.data_file_cache_dir.is_empty() {
868 if let Err(e) = Feature::ElasticDiskCache.check_available() {
869 tracing::warn!(error = %e.as_report(), "ElasticDiskCache is not available.");
870 } else {
871 let device = FsDeviceBuilder::new(&opts.data_file_cache_dir)
872 .with_capacity(opts.data_file_cache_capacity_mb * MB)
873 .with_throttle(opts.data_file_cache_throttle.clone())
874 .build()
875 .map_err(HummockError::foyer_error)?;
876 let engine_builder = BlockEngineConfig::new(device)
877 .with_block_size(opts.data_file_cache_file_capacity_mb * MB)
878 .with_indexer_shards(opts.data_file_cache_indexer_shards)
879 .with_flushers(opts.data_file_cache_flushers)
880 .with_reclaimers(opts.data_file_cache_reclaimers)
881 .with_buffer_pool_size(opts.data_file_cache_flush_buffer_threshold_mb * MB)
882 .with_submit_queue_size_threshold(
883 opts.data_file_cache_submit_queue_size_threshold_mb * MB,
884 )
885 .with_clean_block_threshold(
886 opts.data_file_cache_reclaimers + opts.data_file_cache_reclaimers / 2,
887 )
888 .with_recover_concurrency(opts.data_file_cache_recover_concurrency)
889 .with_blob_index_size(opts.data_file_cache_blob_index_size_kb * KB)
890 .with_eviction_pickers(vec![Box::new(FifoPicker::new(
891 opts.data_file_cache_fifo_probation_ratio,
892 ))]);
893 builder = builder
894 .with_engine_config(engine_builder)
895 .with_recover_mode(opts.data_file_cache_recover_mode)
896 .with_compression(opts.data_file_cache_compression);
897 builder = builder.with_spawner(build_file_cache_spawner(
898 "foyer.data",
899 &opts.data_file_cache_runtime_config,
900 )?);
901 }
902 }
903
904 builder.build().await.map_err(HummockError::foyer_error)?
905 };
906
907 let vector_meta_cache = CacheBuilder::new(opts.vector_meta_cache_capacity_mb * MB)
908 .with_shards(opts.vector_meta_cache_shard_num)
909 .with_eviction_config(opts.vector_meta_cache_eviction_config.clone())
910 .build();
911
912 let vector_block_cache = CacheBuilder::new(opts.vector_block_cache_capacity_mb * MB)
913 .with_shards(opts.vector_block_cache_shard_num)
914 .with_eviction_config(opts.vector_block_cache_eviction_config.clone())
915 .build();
916
917 let recent_filter = if opts.data_file_cache_dir.is_empty() {
918 Arc::new(NoneRecentFilter::default().into())
919 } else if opts.cache_refill_recent_filter_shards == 1 {
920 Arc::new(
921 SimpleRecentFilter::new(
922 opts.cache_refill_recent_filter_layers,
923 Duration::from_millis(
924 opts.cache_refill_recent_filter_rotate_interval_ms as u64,
925 ),
926 )
927 .into(),
928 )
929 } else if opts.cache_refill_skip_recent_filter {
930 Arc::new(AllRecentFilter::default().into())
931 } else {
932 Arc::new(
933 ShardedRecentFilter::new(
934 opts.cache_refill_recent_filter_layers,
935 Duration::from_millis(
936 opts.cache_refill_recent_filter_rotate_interval_ms as u64,
937 ),
938 opts.cache_refill_recent_filter_shards,
939 )
940 .into(),
941 )
942 };
943
944 let store = match s {
945 hummock if hummock.starts_with("hummock+") => {
946 let object_store = build_remote_object_store(
947 hummock.strip_prefix("hummock+").unwrap(),
948 object_store_metrics.clone(),
949 "Hummock",
950 Arc::new(opts.object_store_config.clone()),
951 )
952 .await;
953
954 let sstable_store = Arc::new(SstableStore::new(SstableStoreConfig {
955 store: Arc::new(object_store),
956 path: opts.data_directory.clone(),
957 prefetch_buffer_capacity: opts.prefetch_buffer_capacity_mb * (1 << 20),
958 max_prefetch_block_number: opts.max_prefetch_block_number,
959 recent_filter,
960 state_store_metrics: state_store_metrics.clone(),
961 use_new_object_prefix_strategy,
962 skip_bloom_filter_in_serde: opts.sst_skip_bloom_filter_in_serde,
963
964 meta_cache,
965 block_cache,
966 vector_meta_cache,
967 vector_block_cache,
968 }));
969 let notification_client =
970 RpcNotificationClient::new(hummock_meta_client.get_inner().clone());
971 let compaction_catalog_manager_ref =
972 Arc::new(CompactionCatalogManager::new(Box::new(
973 RemoteTableAccessor::new(hummock_meta_client.get_inner().clone()),
974 )));
975
976 let inner = HummockStorage::new(
977 role,
978 opts.clone(),
979 sstable_store,
980 hummock_meta_client.clone(),
981 notification_client,
982 compaction_catalog_manager_ref,
983 state_store_metrics.clone(),
984 compactor_metrics.clone(),
985 await_tree_config,
986 )
987 .await?;
988
989 StateStoreImpl::hummock(inner, storage_metrics)
990 }
991
992 "in_memory" | "in-memory" => {
993 tracing::warn!(
994 "In-memory state store should never be used in end-to-end benchmarks or production environment. Scaling and recovery are not supported."
995 );
996 StateStoreImpl::shared_in_memory_store(storage_metrics.clone())
997 }
998
999 sled if sled.starts_with("sled://") => {
1000 tracing::warn!(
1001 "sled state store should never be used in end-to-end benchmarks or production environment. Scaling and recovery are not supported."
1002 );
1003 let path = sled.strip_prefix("sled://").unwrap();
1004 StateStoreImpl::sled(SledStateStore::new(path), storage_metrics.clone())
1005 }
1006
1007 other => unimplemented!("{} state store is not supported", other),
1008 };
1009
1010 Ok(store)
1011 }
1012}
1013
1014pub trait AsHummock: Send + Sync {
1015 fn as_hummock(&self) -> Option<&HummockStorage>;
1016
1017 fn sync(
1018 &self,
1019 sync_table_epochs: Vec<(HummockEpoch, HashSet<TableId>)>,
1020 ) -> BoxFuture<'_, StorageResult<SyncResult>> {
1021 async move {
1022 if let Some(hummock) = self.as_hummock() {
1023 hummock.sync(sync_table_epochs).await
1024 } else {
1025 Ok(SyncResult::default())
1026 }
1027 }
1028 .boxed()
1029 }
1030}
1031
1032impl AsHummock for HummockStorage {
1033 fn as_hummock(&self) -> Option<&HummockStorage> {
1034 Some(self)
1035 }
1036}
1037
1038impl AsHummock for MemoryStateStore {
1039 fn as_hummock(&self) -> Option<&HummockStorage> {
1040 None
1041 }
1042}
1043
1044impl AsHummock for SledStateStore {
1045 fn as_hummock(&self) -> Option<&HummockStorage> {
1046 None
1047 }
1048}
1049
1050#[cfg(debug_assertions)]
1051mod dyn_state_store {
1052 use std::future::Future;
1053 use std::ops::DerefMut;
1054 use std::sync::Arc;
1055
1056 use bytes::Bytes;
1057 use risingwave_common::array::VectorRef;
1058 use risingwave_common::bitmap::Bitmap;
1059 use risingwave_common::hash::VirtualNode;
1060 use risingwave_hummock_sdk::HummockReadEpoch;
1061 use risingwave_hummock_sdk::key::{TableKey, TableKeyRange};
1062
1063 use crate::error::StorageResult;
1064 use crate::hummock::HummockStorage;
1065 use crate::store::*;
1066 use crate::store_impl::AsHummock;
1067 use crate::vector::VectorDistance;
1068
1069 #[async_trait::async_trait]
1070 pub trait DynStateStoreIter<T: IterItem>: Send {
1071 async fn try_next(&mut self) -> StorageResult<Option<T::ItemRef<'_>>>;
1072 }
1073
1074 #[async_trait::async_trait]
1075 impl<T: IterItem, I: StateStoreIter<T>> DynStateStoreIter<T> for I {
1076 async fn try_next(&mut self) -> StorageResult<Option<T::ItemRef<'_>>> {
1077 self.try_next().await
1078 }
1079 }
1080
1081 pub type BoxStateStoreIter<'a, T> = Box<dyn DynStateStoreIter<T> + 'a>;
1082 impl<T: IterItem> StateStoreIter<T> for BoxStateStoreIter<'_, T> {
1083 fn try_next(
1084 &mut self,
1085 ) -> impl Future<Output = StorageResult<Option<T::ItemRef<'_>>>> + Send + '_ {
1086 self.deref_mut().try_next()
1087 }
1088 }
1089
1090 pub type BoxStateStoreReadIter = BoxStateStoreIter<'static, StateStoreKeyedRow>;
1093 pub type BoxStateStoreReadChangeLogIter = BoxStateStoreIter<'static, StateStoreReadLogItem>;
1094
1095 #[async_trait::async_trait]
1096 pub trait DynStateStoreGet: StaticSendSync {
1097 async fn get_keyed_row(
1098 &self,
1099 key: TableKey<Bytes>,
1100 read_options: ReadOptions,
1101 ) -> StorageResult<Option<StateStoreKeyedRow>>;
1102 }
1103
1104 #[async_trait::async_trait]
1105 pub trait DynStateStoreRead: DynStateStoreGet + StaticSendSync {
1106 async fn iter(
1107 &self,
1108 key_range: TableKeyRange,
1109
1110 read_options: ReadOptions,
1111 ) -> StorageResult<BoxStateStoreReadIter>;
1112
1113 async fn rev_iter(
1114 &self,
1115 key_range: TableKeyRange,
1116
1117 read_options: ReadOptions,
1118 ) -> StorageResult<BoxStateStoreReadIter>;
1119 }
1120
1121 #[async_trait::async_trait]
1122 pub trait DynStateStoreReadLog: StaticSendSync {
1123 async fn next_epoch(&self, epoch: u64, options: NextEpochOptions) -> StorageResult<u64>;
1124 async fn iter_log(
1125 &self,
1126 epoch_range: (u64, u64),
1127 key_range: TableKeyRange,
1128 options: ReadLogOptions,
1129 ) -> StorageResult<BoxStateStoreReadChangeLogIter>;
1130 }
1131
1132 pub type StateStoreReadDynRef = StateStorePointer<Arc<dyn DynStateStoreRead>>;
1133
1134 #[async_trait::async_trait]
1135 impl<S: StateStoreGet> DynStateStoreGet for S {
1136 async fn get_keyed_row(
1137 &self,
1138 key: TableKey<Bytes>,
1139 read_options: ReadOptions,
1140 ) -> StorageResult<Option<StateStoreKeyedRow>> {
1141 self.on_key_value(key, read_options, move |key, value| {
1142 Ok((key.copy_into(), Bytes::copy_from_slice(value)))
1143 })
1144 .await
1145 }
1146 }
1147
1148 #[async_trait::async_trait]
1149 impl<S: StateStoreRead> DynStateStoreRead for S {
1150 async fn iter(
1151 &self,
1152 key_range: TableKeyRange,
1153
1154 read_options: ReadOptions,
1155 ) -> StorageResult<BoxStateStoreReadIter> {
1156 Ok(Box::new(self.iter(key_range, read_options).await?))
1157 }
1158
1159 async fn rev_iter(
1160 &self,
1161 key_range: TableKeyRange,
1162
1163 read_options: ReadOptions,
1164 ) -> StorageResult<BoxStateStoreReadIter> {
1165 Ok(Box::new(self.rev_iter(key_range, read_options).await?))
1166 }
1167 }
1168
1169 #[async_trait::async_trait]
1170 impl<S: StateStoreReadLog> DynStateStoreReadLog for S {
1171 async fn next_epoch(&self, epoch: u64, options: NextEpochOptions) -> StorageResult<u64> {
1172 self.next_epoch(epoch, options).await
1173 }
1174
1175 async fn iter_log(
1176 &self,
1177 epoch_range: (u64, u64),
1178 key_range: TableKeyRange,
1179 options: ReadLogOptions,
1180 ) -> StorageResult<BoxStateStoreReadChangeLogIter> {
1181 Ok(Box::new(
1182 self.iter_log(epoch_range, key_range, options).await?,
1183 ))
1184 }
1185 }
1186
1187 pub type BoxLocalStateStoreIterStream<'a> = BoxStateStoreIter<'a, StateStoreKeyedRow>;
1189 #[async_trait::async_trait]
1190 pub trait DynLocalStateStore:
1191 DynStateStoreGet + DynStateStoreWriteEpochControl + StaticSendSync
1192 {
1193 async fn iter(
1194 &self,
1195 key_range: TableKeyRange,
1196 read_options: ReadOptions,
1197 ) -> StorageResult<BoxLocalStateStoreIterStream<'_>>;
1198
1199 async fn rev_iter(
1200 &self,
1201 key_range: TableKeyRange,
1202 read_options: ReadOptions,
1203 ) -> StorageResult<BoxLocalStateStoreIterStream<'_>>;
1204
1205 fn new_flushed_snapshot_reader(&self) -> StateStoreReadDynRef;
1206
1207 fn insert(
1208 &mut self,
1209 key: TableKey<Bytes>,
1210 new_val: Bytes,
1211 old_val: Option<Bytes>,
1212 ) -> StorageResult<()>;
1213
1214 fn delete(&mut self, key: TableKey<Bytes>, old_val: Bytes) -> StorageResult<()>;
1215
1216 async fn update_vnode_bitmap(&mut self, vnodes: Arc<Bitmap>) -> StorageResult<Arc<Bitmap>>;
1217
1218 fn get_table_watermark(&self, vnode: VirtualNode) -> Option<Bytes>;
1219 }
1220
1221 #[async_trait::async_trait]
1222 pub trait DynStateStoreWriteEpochControl: StaticSendSync {
1223 async fn flush(&mut self) -> StorageResult<usize>;
1224
1225 async fn try_flush(&mut self) -> StorageResult<()>;
1226
1227 async fn init(&mut self, epoch: InitOptions) -> StorageResult<()>;
1228
1229 fn seal_current_epoch(&mut self, next_epoch: u64, opts: SealCurrentEpochOptions);
1230 }
1231
1232 #[async_trait::async_trait]
1233 impl<S: LocalStateStore> DynLocalStateStore for S {
1234 async fn iter(
1235 &self,
1236 key_range: TableKeyRange,
1237 read_options: ReadOptions,
1238 ) -> StorageResult<BoxLocalStateStoreIterStream<'_>> {
1239 Ok(Box::new(self.iter(key_range, read_options).await?))
1240 }
1241
1242 async fn rev_iter(
1243 &self,
1244 key_range: TableKeyRange,
1245 read_options: ReadOptions,
1246 ) -> StorageResult<BoxLocalStateStoreIterStream<'_>> {
1247 Ok(Box::new(self.rev_iter(key_range, read_options).await?))
1248 }
1249
1250 fn new_flushed_snapshot_reader(&self) -> StateStoreReadDynRef {
1251 StateStorePointer(Arc::new(self.new_flushed_snapshot_reader()) as _)
1252 }
1253
1254 fn insert(
1255 &mut self,
1256 key: TableKey<Bytes>,
1257 new_val: Bytes,
1258 old_val: Option<Bytes>,
1259 ) -> StorageResult<()> {
1260 self.insert(key, new_val, old_val)
1261 }
1262
1263 fn delete(&mut self, key: TableKey<Bytes>, old_val: Bytes) -> StorageResult<()> {
1264 self.delete(key, old_val)
1265 }
1266
1267 async fn update_vnode_bitmap(&mut self, vnodes: Arc<Bitmap>) -> StorageResult<Arc<Bitmap>> {
1268 self.update_vnode_bitmap(vnodes).await
1269 }
1270
1271 fn get_table_watermark(&self, vnode: VirtualNode) -> Option<Bytes> {
1272 self.get_table_watermark(vnode)
1273 }
1274 }
1275
1276 #[async_trait::async_trait]
1277 impl<S: StateStoreWriteEpochControl> DynStateStoreWriteEpochControl for S {
1278 async fn flush(&mut self) -> StorageResult<usize> {
1279 self.flush().await
1280 }
1281
1282 async fn try_flush(&mut self) -> StorageResult<()> {
1283 self.try_flush().await
1284 }
1285
1286 async fn init(&mut self, options: InitOptions) -> StorageResult<()> {
1287 self.init(options).await
1288 }
1289
1290 fn seal_current_epoch(&mut self, next_epoch: u64, opts: SealCurrentEpochOptions) {
1291 self.seal_current_epoch(next_epoch, opts)
1292 }
1293 }
1294
1295 pub type BoxDynLocalStateStore = StateStorePointer<Box<dyn DynLocalStateStore>>;
1296
1297 impl LocalStateStore for BoxDynLocalStateStore {
1298 type FlushedSnapshotReader = StateStoreReadDynRef;
1299 type Iter<'a> = BoxLocalStateStoreIterStream<'a>;
1300 type RevIter<'a> = BoxLocalStateStoreIterStream<'a>;
1301
1302 fn iter(
1303 &self,
1304 key_range: TableKeyRange,
1305 read_options: ReadOptions,
1306 ) -> impl Future<Output = StorageResult<Self::Iter<'_>>> + Send + '_ {
1307 (*self.0).iter(key_range, read_options)
1308 }
1309
1310 fn rev_iter(
1311 &self,
1312 key_range: TableKeyRange,
1313 read_options: ReadOptions,
1314 ) -> impl Future<Output = StorageResult<Self::RevIter<'_>>> + Send + '_ {
1315 (*self.0).rev_iter(key_range, read_options)
1316 }
1317
1318 fn new_flushed_snapshot_reader(&self) -> Self::FlushedSnapshotReader {
1319 (*self.0).new_flushed_snapshot_reader()
1320 }
1321
1322 fn get_table_watermark(&self, vnode: VirtualNode) -> Option<Bytes> {
1323 (*self.0).get_table_watermark(vnode)
1324 }
1325
1326 fn insert(
1327 &mut self,
1328 key: TableKey<Bytes>,
1329 new_val: Bytes,
1330 old_val: Option<Bytes>,
1331 ) -> StorageResult<()> {
1332 (*self.0).insert(key, new_val, old_val)
1333 }
1334
1335 fn delete(&mut self, key: TableKey<Bytes>, old_val: Bytes) -> StorageResult<()> {
1336 (*self.0).delete(key, old_val)
1337 }
1338
1339 async fn update_vnode_bitmap(&mut self, vnodes: Arc<Bitmap>) -> StorageResult<Arc<Bitmap>> {
1340 (*self.0).update_vnode_bitmap(vnodes).await
1341 }
1342 }
1343
1344 impl<P> StateStoreWriteEpochControl for StateStorePointer<P>
1345 where
1346 StateStorePointer<P>: AsMut<dyn DynStateStoreWriteEpochControl> + StaticSendSync,
1347 {
1348 fn flush(&mut self) -> impl Future<Output = StorageResult<usize>> + Send + '_ {
1349 self.as_mut().flush()
1350 }
1351
1352 fn try_flush(&mut self) -> impl Future<Output = StorageResult<()>> + Send + '_ {
1353 self.as_mut().try_flush()
1354 }
1355
1356 fn init(
1357 &mut self,
1358 options: InitOptions,
1359 ) -> impl Future<Output = StorageResult<()>> + Send + '_ {
1360 self.as_mut().init(options)
1361 }
1362
1363 fn seal_current_epoch(&mut self, next_epoch: u64, opts: SealCurrentEpochOptions) {
1364 self.as_mut().seal_current_epoch(next_epoch, opts)
1365 }
1366 }
1367
1368 #[async_trait::async_trait]
1369 pub trait DynStateStoreWriteVector: DynStateStoreWriteEpochControl + StaticSendSync {
1370 fn insert(&mut self, vec: VectorRef<'_>, info: Bytes) -> StorageResult<()>;
1371 }
1372
1373 #[async_trait::async_trait]
1374 impl<S: StateStoreWriteVector> DynStateStoreWriteVector for S {
1375 fn insert(&mut self, vec: VectorRef<'_>, info: Bytes) -> StorageResult<()> {
1376 self.insert(vec, info)
1377 }
1378 }
1379
1380 pub type BoxDynStateStoreWriteVector = StateStorePointer<Box<dyn DynStateStoreWriteVector>>;
1381
1382 impl StateStoreWriteVector for BoxDynStateStoreWriteVector {
1383 fn insert(&mut self, vec: VectorRef<'_>, info: Bytes) -> StorageResult<()> {
1384 self.0.insert(vec, info)
1385 }
1386 }
1387
1388 #[async_trait::async_trait]
1391 pub trait DynStateStoreReadVector: StaticSendSync {
1392 async fn nearest(
1393 &self,
1394 vec: VectorRef<'_>,
1395 options: VectorNearestOptions,
1396 ) -> StorageResult<Vec<(Vector, VectorDistance, Bytes)>>;
1397 }
1398
1399 #[async_trait::async_trait]
1400 impl<S: StateStoreReadVector> DynStateStoreReadVector for S {
1401 async fn nearest(
1402 &self,
1403 vec: VectorRef<'_>,
1404 options: VectorNearestOptions,
1405 ) -> StorageResult<Vec<(Vector, VectorDistance, Bytes)>> {
1406 use risingwave_common::types::ScalarRef;
1407 self.nearest(vec, options, |vec, distance, info| {
1408 (
1409 vec.to_owned_scalar(),
1410 distance,
1411 Bytes::copy_from_slice(info),
1412 )
1413 })
1414 .await
1415 }
1416 }
1417
1418 impl<P> StateStoreReadVector for StateStorePointer<P>
1419 where
1420 StateStorePointer<P>: AsRef<dyn DynStateStoreReadVector> + StaticSendSync,
1421 {
1422 async fn nearest<'a, O: Send + 'a>(
1423 &'a self,
1424 vec: VectorRef<'a>,
1425 options: VectorNearestOptions,
1426 on_nearest_item_fn: impl OnNearestItemFn<'a, O>,
1427 ) -> StorageResult<Vec<O>> {
1428 let output = self.as_ref().nearest(vec, options).await?;
1429 Ok(output
1430 .into_iter()
1431 .map(|(vec, distance, info)| {
1432 on_nearest_item_fn(vec.to_ref(), distance, info.as_ref())
1433 })
1434 .collect())
1435 }
1436 }
1437
1438 pub trait DynStateStoreReadSnapshot:
1439 DynStateStoreRead + DynStateStoreReadVector + StaticSendSync
1440 {
1441 }
1442
1443 impl<S: DynStateStoreRead + DynStateStoreReadVector + StaticSendSync> DynStateStoreReadSnapshot
1444 for S
1445 {
1446 }
1447
1448 pub type StateStoreReadSnapshotDynRef = StateStorePointer<Arc<dyn DynStateStoreReadSnapshot>>;
1449 #[async_trait::async_trait]
1450 pub trait DynStateStoreExt: StaticSendSync {
1451 async fn try_wait_epoch(
1452 &self,
1453 epoch: HummockReadEpoch,
1454 options: TryWaitEpochOptions,
1455 ) -> StorageResult<()>;
1456
1457 async fn new_local(&self, option: NewLocalOptions) -> BoxDynLocalStateStore;
1458 async fn new_read_snapshot(
1459 &self,
1460 epoch: HummockReadEpoch,
1461 options: NewReadSnapshotOptions,
1462 ) -> StorageResult<StateStoreReadSnapshotDynRef>;
1463 async fn new_vector_writer(
1464 &self,
1465 options: NewVectorWriterOptions,
1466 ) -> BoxDynStateStoreWriteVector;
1467 }
1468
1469 #[async_trait::async_trait]
1470 impl<S: StateStore> DynStateStoreExt for S {
1471 async fn try_wait_epoch(
1472 &self,
1473 epoch: HummockReadEpoch,
1474 options: TryWaitEpochOptions,
1475 ) -> StorageResult<()> {
1476 self.try_wait_epoch(epoch, options).await
1477 }
1478
1479 async fn new_local(&self, option: NewLocalOptions) -> BoxDynLocalStateStore {
1480 StateStorePointer(Box::new(self.new_local(option).await))
1481 }
1482
1483 async fn new_read_snapshot(
1484 &self,
1485 epoch: HummockReadEpoch,
1486 options: NewReadSnapshotOptions,
1487 ) -> StorageResult<StateStoreReadSnapshotDynRef> {
1488 Ok(StateStorePointer(Arc::new(
1489 self.new_read_snapshot(epoch, options).await?,
1490 )))
1491 }
1492
1493 async fn new_vector_writer(
1494 &self,
1495 options: NewVectorWriterOptions,
1496 ) -> BoxDynStateStoreWriteVector {
1497 StateStorePointer(Box::new(self.new_vector_writer(options).await))
1498 }
1499 }
1500
1501 pub type StateStoreDynRef = StateStorePointer<Arc<dyn DynStateStore>>;
1502
1503 macro_rules! state_store_pointer_dyn_as_ref {
1504 ($pointer:ident < dyn $source_dyn_trait:ident > , $target_dyn_trait:ident) => {
1505 impl AsRef<dyn $target_dyn_trait>
1506 for StateStorePointer<$pointer<dyn $source_dyn_trait>>
1507 {
1508 fn as_ref(&self) -> &dyn $target_dyn_trait {
1509 (&*self.0) as _
1510 }
1511 }
1512 };
1513 }
1514
1515 state_store_pointer_dyn_as_ref!(Arc<dyn DynStateStoreReadSnapshot>, DynStateStoreRead);
1516 state_store_pointer_dyn_as_ref!(Arc<dyn DynStateStoreReadSnapshot>, DynStateStoreGet);
1517 state_store_pointer_dyn_as_ref!(Arc<dyn DynStateStoreReadSnapshot>, DynStateStoreReadVector);
1518 state_store_pointer_dyn_as_ref!(Arc<dyn DynStateStoreRead>, DynStateStoreRead);
1519 state_store_pointer_dyn_as_ref!(Arc<dyn DynStateStoreRead>, DynStateStoreGet);
1520 state_store_pointer_dyn_as_ref!(Box<dyn DynLocalStateStore>, DynStateStoreGet);
1521
1522 macro_rules! state_store_pointer_dyn_as_mut {
1523 ($pointer:ident < dyn $source_dyn_trait:ident > , $target_dyn_trait:ident) => {
1524 impl AsMut<dyn $target_dyn_trait>
1525 for StateStorePointer<$pointer<dyn $source_dyn_trait>>
1526 {
1527 fn as_mut(&mut self) -> &mut dyn $target_dyn_trait {
1528 (&mut *self.0) as _
1529 }
1530 }
1531 };
1532 }
1533
1534 state_store_pointer_dyn_as_mut!(Box<dyn DynLocalStateStore>, DynStateStoreWriteEpochControl);
1535 state_store_pointer_dyn_as_mut!(
1536 Box<dyn DynStateStoreWriteVector>,
1537 DynStateStoreWriteEpochControl
1538 );
1539
1540 #[derive(Clone)]
1541 pub struct StateStorePointer<P>(pub(crate) P);
1542
1543 impl<P> StateStoreGet for StateStorePointer<P>
1544 where
1545 StateStorePointer<P>: AsRef<dyn DynStateStoreGet> + StaticSendSync,
1546 {
1547 async fn on_key_value<'a, O: Send + 'a>(
1548 &'a self,
1549 key: TableKey<Bytes>,
1550 read_options: ReadOptions,
1551 on_key_value_fn: impl KeyValueFn<'a, O>,
1552 ) -> StorageResult<Option<O>> {
1553 let option = self.as_ref().get_keyed_row(key, read_options).await?;
1554 option
1555 .map(|(key, value)| on_key_value_fn(key.to_ref(), value.as_ref()))
1556 .transpose()
1557 }
1558 }
1559
1560 impl<P> StateStoreRead for StateStorePointer<P>
1561 where
1562 StateStorePointer<P>: AsRef<dyn DynStateStoreRead> + StateStoreGet + StaticSendSync,
1563 {
1564 type Iter = BoxStateStoreReadIter;
1565 type RevIter = BoxStateStoreReadIter;
1566
1567 fn iter(
1568 &self,
1569 key_range: TableKeyRange,
1570
1571 read_options: ReadOptions,
1572 ) -> impl Future<Output = StorageResult<Self::Iter>> + '_ {
1573 self.as_ref().iter(key_range, read_options)
1574 }
1575
1576 fn rev_iter(
1577 &self,
1578 key_range: TableKeyRange,
1579
1580 read_options: ReadOptions,
1581 ) -> impl Future<Output = StorageResult<Self::RevIter>> + '_ {
1582 self.as_ref().rev_iter(key_range, read_options)
1583 }
1584 }
1585
1586 impl StateStoreReadLog for StateStoreDynRef {
1587 type ChangeLogIter = BoxStateStoreReadChangeLogIter;
1588
1589 async fn next_epoch(&self, epoch: u64, options: NextEpochOptions) -> StorageResult<u64> {
1590 (*self.0).next_epoch(epoch, options).await
1591 }
1592
1593 fn iter_log(
1594 &self,
1595 epoch_range: (u64, u64),
1596 key_range: TableKeyRange,
1597 options: ReadLogOptions,
1598 ) -> impl Future<Output = StorageResult<Self::ChangeLogIter>> + Send + '_ {
1599 (*self.0).iter_log(epoch_range, key_range, options)
1600 }
1601 }
1602
1603 pub trait DynStateStore: DynStateStoreReadLog + DynStateStoreExt + AsHummock {}
1604
1605 impl AsHummock for StateStoreDynRef {
1606 fn as_hummock(&self) -> Option<&HummockStorage> {
1607 (*self.0).as_hummock()
1608 }
1609 }
1610
1611 impl<S: DynStateStoreReadLog + DynStateStoreExt + AsHummock> DynStateStore for S {}
1612
1613 impl StateStore for StateStoreDynRef {
1614 type Local = BoxDynLocalStateStore;
1615 type ReadSnapshot = StateStoreReadSnapshotDynRef;
1616 type VectorWriter = BoxDynStateStoreWriteVector;
1617
1618 fn try_wait_epoch(
1619 &self,
1620 epoch: HummockReadEpoch,
1621 options: TryWaitEpochOptions,
1622 ) -> impl Future<Output = StorageResult<()>> + Send + '_ {
1623 (*self.0).try_wait_epoch(epoch, options)
1624 }
1625
1626 fn new_local(
1627 &self,
1628 option: NewLocalOptions,
1629 ) -> impl Future<Output = Self::Local> + Send + '_ {
1630 (*self.0).new_local(option)
1631 }
1632
1633 async fn new_read_snapshot(
1634 &self,
1635 epoch: HummockReadEpoch,
1636 options: NewReadSnapshotOptions,
1637 ) -> StorageResult<Self::ReadSnapshot> {
1638 (*self.0).new_read_snapshot(epoch, options).await
1639 }
1640
1641 fn new_vector_writer(
1642 &self,
1643 options: NewVectorWriterOptions,
1644 ) -> impl Future<Output = Self::VectorWriter> + Send + '_ {
1645 (*self.0).new_vector_writer(options)
1646 }
1647 }
1648}