1use std::collections::HashSet;
16use std::future::Future;
17use std::ops::{Bound, Deref};
18use std::sync::Arc;
19
20use arc_swap::ArcSwap;
21use bytes::Bytes;
22use itertools::Itertools;
23use risingwave_common::array::VectorRef;
24use risingwave_common::catalog::{TableId, TableOption};
25use risingwave_common::dispatch_distance_measurement;
26use risingwave_common::util::epoch::is_max_epoch;
27use risingwave_common_service::{NotificationClient, ObserverManager};
28use risingwave_hummock_sdk::change_log::TableChangeLogs;
29use risingwave_hummock_sdk::key::{
30 TableKey, TableKeyRange, is_empty_key_range, vnode, vnode_range,
31};
32use risingwave_hummock_sdk::sstable_info::SstableInfo;
33use risingwave_hummock_sdk::table_watermark::TableWatermarksIndex;
34use risingwave_hummock_sdk::version::HummockVersion;
35use risingwave_hummock_sdk::{HummockRawObjectId, HummockReadEpoch, SyncResult};
36use risingwave_rpc_client::HummockMetaClient;
37use risingwave_rpc_client::error::RpcError;
38use thiserror_ext::AsReport;
39use tokio::sync::mpsc::{UnboundedSender, unbounded_channel};
40use tokio::sync::oneshot;
41
42use super::local_hummock_storage::LocalHummockStorage;
43use super::version::{CommittedVersion, HummockVersionReader, read_filter_for_version};
44use crate::compaction_catalog_manager::CompactionCatalogManagerRef;
45#[cfg(any(test, feature = "test"))]
46use crate::compaction_catalog_manager::{CompactionCatalogManager, FakeRemoteTableAccessor};
47use crate::error::StorageResult;
48use crate::hummock::backup_reader::{BackupReader, BackupReaderRef};
49use crate::hummock::compactor::{
50 CompactionAwaitTreeRegRef, CompactorContext, new_compaction_await_tree_reg_ref,
51};
52use crate::hummock::event_handler::hummock_event_handler::{BufferTracker, HummockEventSender};
53use crate::hummock::event_handler::{
54 HummockEvent, HummockEventHandler, HummockVersionUpdate, ReadOnlyReadVersionMapping,
55};
56use crate::hummock::iterator::change_log::ChangeLogIterator;
57use crate::hummock::local_version::pinned_version::{PinnedVersion, start_pinned_version_worker};
58use crate::hummock::local_version::recent_versions::RecentVersions;
59use crate::hummock::observer_manager::HummockObserverNode;
60use crate::hummock::store::vector_writer::HummockVectorWriter;
61use crate::hummock::table_change_log_manager::TableChangeLogManager;
62use crate::hummock::time_travel_version_cache::SimpleTimeTravelVersionCache;
63use crate::hummock::utils::{wait_for_epoch, wait_for_update};
64use crate::hummock::write_limiter::{WriteLimiter, WriteLimiterRef};
65use crate::hummock::{
66 HummockEpoch, HummockError, HummockResult, HummockStorageIterator, HummockStorageRevIterator,
67 MemoryLimiter, ObjectIdManager, ObjectIdManagerRef, SstableStoreRef,
68};
69use crate::mem_table::ImmutableMemtable;
70use crate::monitor::{CompactorMetrics, HummockStateStoreMetrics};
71use crate::opts::StorageOpts;
72use crate::store::*;
73
74struct HummockStorageShutdownGuard {
75 shutdown_sender: HummockEventSender,
76}
77
78impl Drop for HummockStorageShutdownGuard {
79 fn drop(&mut self) {
80 let _ = self
81 .shutdown_sender
82 .send(HummockEvent::Shutdown)
83 .inspect_err(|e| tracing::debug!(event = ?e.0, "unable to send shutdown"));
84 }
85}
86
87#[derive(Clone)]
93pub struct HummockStorage {
94 hummock_event_sender: HummockEventSender,
95 _version_update_sender: UnboundedSender<HummockVersionUpdate>,
97
98 context: CompactorContext,
99
100 compaction_catalog_manager_ref: CompactionCatalogManagerRef,
101
102 object_id_manager: ObjectIdManagerRef,
103
104 buffer_tracker: BufferTracker,
105
106 version_update_notifier_tx: Arc<tokio::sync::watch::Sender<PinnedVersion>>,
107
108 recent_versions: Arc<ArcSwap<RecentVersions>>,
109
110 hummock_version_reader: HummockVersionReader,
111
112 _shutdown_guard: Arc<HummockStorageShutdownGuard>,
113
114 read_version_mapping: ReadOnlyReadVersionMapping,
115
116 backup_reader: BackupReaderRef,
117
118 write_limiter: WriteLimiterRef,
119
120 compact_await_tree_reg: Option<CompactionAwaitTreeRegRef>,
121
122 hummock_meta_client: Arc<dyn HummockMetaClient>,
123
124 simple_time_travel_version_cache: Arc<SimpleTimeTravelVersionCache>,
125
126 table_change_log_manager: Arc<TableChangeLogManager>,
127}
128
129pub type ReadVersionTuple = (Vec<ImmutableMemtable>, Vec<SstableInfo>, CommittedVersion);
130
131pub fn get_committed_read_version_tuple(
132 version: PinnedVersion,
133 table_id: TableId,
134 mut key_range: TableKeyRange,
135 epoch: HummockEpoch,
136) -> (TableKeyRange, ReadVersionTuple) {
137 if let Some(table_watermarks) = version.table_watermarks.get(&table_id) {
138 TableWatermarksIndex::new_committed(
139 table_watermarks.clone(),
140 version
141 .state_table_info
142 .info()
143 .get(&table_id)
144 .expect("should exist when having table watermark")
145 .committed_epoch,
146 table_watermarks.watermark_type,
147 )
148 .rewrite_range_with_table_watermark(epoch, &mut key_range)
149 }
150 (key_range, (vec![], vec![], version))
151}
152
153impl HummockStorage {
154 #[allow(clippy::too_many_arguments)]
156 pub async fn new(
157 options: Arc<StorageOpts>,
158 sstable_store: SstableStoreRef,
159 hummock_meta_client: Arc<dyn HummockMetaClient>,
160 notification_client: impl NotificationClient,
161 compaction_catalog_manager_ref: CompactionCatalogManagerRef,
162 state_store_metrics: Arc<HummockStateStoreMetrics>,
163 compactor_metrics: Arc<CompactorMetrics>,
164 await_tree_config: Option<await_tree::Config>,
165 ) -> HummockResult<Self> {
166 let object_id_manager = Arc::new(ObjectIdManager::new(
167 hummock_meta_client.clone(),
168 options.sstable_id_remote_fetch_number,
169 ));
170 let backup_reader = BackupReader::new(
171 &options.backup_storage_url,
172 &options.backup_storage_directory,
173 &options.object_store_config,
174 )
175 .await
176 .map_err(HummockError::read_backup_error)?;
177 let write_limiter = Arc::new(WriteLimiter::default());
178 let (version_update_tx, mut version_update_rx) = unbounded_channel();
179
180 let observer_manager = ObserverManager::new(
181 notification_client,
182 HummockObserverNode::new(
183 compaction_catalog_manager_ref.clone(),
184 backup_reader.clone(),
185 version_update_tx.clone(),
186 write_limiter.clone(),
187 ),
188 )
189 .await;
190 observer_manager.start().await;
191
192 let hummock_version = match version_update_rx.recv().await {
193 Some(HummockVersionUpdate::PinnedVersion(version)) => *version,
194 _ => unreachable!(
195 "the hummock observer manager is the first one to take the event tx. Should be full hummock version"
196 ),
197 };
198
199 let (pin_version_tx, pin_version_rx) = unbounded_channel();
200 let pinned_version = PinnedVersion::new(hummock_version, pin_version_tx);
201 tokio::spawn(start_pinned_version_worker(
202 pin_version_rx,
203 hummock_meta_client.clone(),
204 options.max_version_pinning_duration_sec,
205 ));
206
207 let await_tree_reg = await_tree_config.map(new_compaction_await_tree_reg_ref);
208
209 let compactor_context = CompactorContext::new_local_compact_context(
210 options.clone(),
211 sstable_store.clone(),
212 compactor_metrics.clone(),
213 await_tree_reg.clone(),
214 );
215
216 let hummock_event_handler = HummockEventHandler::new(
217 version_update_rx,
218 pinned_version,
219 compactor_context.clone(),
220 compaction_catalog_manager_ref.clone(),
221 object_id_manager.clone(),
222 state_store_metrics.clone(),
223 );
224
225 let event_tx = hummock_event_handler.event_sender();
226 let table_change_log_manager = Arc::new(TableChangeLogManager::new(
227 options.table_change_log_cache_capacity,
228 hummock_meta_client.clone(),
229 state_store_metrics.clone(),
230 ));
231 let instance = Self {
232 context: compactor_context,
233 compaction_catalog_manager_ref: compaction_catalog_manager_ref.clone(),
234 object_id_manager,
235 buffer_tracker: hummock_event_handler.buffer_tracker().clone(),
236 version_update_notifier_tx: hummock_event_handler.version_update_notifier_tx(),
237 hummock_event_sender: event_tx.clone(),
238 _version_update_sender: version_update_tx,
239 recent_versions: hummock_event_handler.recent_versions(),
240 hummock_version_reader: HummockVersionReader::new(
241 sstable_store,
242 state_store_metrics.clone(),
243 options.max_preload_io_retry_times,
244 ),
245 _shutdown_guard: Arc::new(HummockStorageShutdownGuard {
246 shutdown_sender: event_tx,
247 }),
248 read_version_mapping: hummock_event_handler.read_version_mapping(),
249 backup_reader,
250 write_limiter,
251 compact_await_tree_reg: await_tree_reg,
252 hummock_meta_client,
253 simple_time_travel_version_cache: Arc::new(SimpleTimeTravelVersionCache::new(
254 options.time_travel_version_cache_capacity,
255 )),
256 table_change_log_manager,
257 };
258
259 tokio::spawn(hummock_event_handler.start_hummock_event_handler_worker());
260
261 Ok(instance)
262 }
263}
264
265impl HummockStorageReadSnapshot {
266 async fn get_inner<'a, O>(
274 &'a self,
275 key: TableKey<Bytes>,
276 read_options: ReadOptions,
277 on_key_value_fn: impl KeyValueFn<'a, O>,
278 ) -> StorageResult<Option<O>> {
279 let key_range = (Bound::Included(key.clone()), Bound::Included(key.clone()));
280
281 let (key_range, read_version_tuple) =
282 self.build_read_version_tuple(self.epoch, key_range).await?;
283
284 if is_empty_key_range(&key_range) {
285 return Ok(None);
286 }
287
288 self.hummock_version_reader
289 .get(
290 key,
291 self.epoch.get_epoch(),
292 self.table_id,
293 self.table_option,
294 read_options,
295 read_version_tuple,
296 on_key_value_fn,
297 )
298 .await
299 }
300
301 async fn iter_inner(
302 &self,
303 key_range: TableKeyRange,
304 read_options: ReadOptions,
305 ) -> StorageResult<HummockStorageIterator> {
306 let (key_range, read_version_tuple) =
307 self.build_read_version_tuple(self.epoch, key_range).await?;
308
309 self.hummock_version_reader
310 .iter(
311 key_range,
312 self.epoch.get_epoch(),
313 self.table_id,
314 self.table_option,
315 read_options,
316 read_version_tuple,
317 )
318 .await
319 }
320
321 async fn rev_iter_inner(
322 &self,
323 key_range: TableKeyRange,
324 read_options: ReadOptions,
325 ) -> StorageResult<HummockStorageRevIterator> {
326 let (key_range, read_version_tuple) =
327 self.build_read_version_tuple(self.epoch, key_range).await?;
328
329 self.hummock_version_reader
330 .rev_iter(
331 key_range,
332 self.epoch.get_epoch(),
333 self.table_id,
334 self.table_option,
335 read_options,
336 read_version_tuple,
337 None,
338 )
339 .await
340 }
341
342 async fn get_time_travel_version(
343 &self,
344 epoch: u64,
345 table_id: TableId,
346 ) -> StorageResult<PinnedVersion> {
347 let meta_client = self.hummock_meta_client.clone();
348 let fetch = async move {
349 let pb_version = meta_client
350 .get_version_by_epoch(epoch, table_id)
351 .await
352 .inspect_err(|e| tracing::error!("{}", e.to_report_string()))
353 .map_err(|e| match &e {
354 RpcError::GrpcStatus(status)
355 if status.inner().code() == tonic::Code::OutOfRange =>
356 {
357 HummockError::time_travel_version_expired(table_id, epoch)
358 }
359 _ => HummockError::meta_error(e.to_report_string()),
360 })?;
361 let version = HummockVersion::from_rpc_protobuf(&pb_version);
362 let (tx, _rx) = unbounded_channel();
363 Ok(PinnedVersion::new(version, tx))
364 };
365 let version = self
366 .simple_time_travel_version_cache
367 .get_or_insert(table_id, epoch, fetch)
368 .await?;
369 Ok(version)
370 }
371
372 async fn build_read_version_tuple(
373 &self,
374 epoch: HummockReadEpoch,
375 key_range: TableKeyRange,
376 ) -> StorageResult<(TableKeyRange, ReadVersionTuple)> {
377 match epoch {
378 HummockReadEpoch::Backup(epoch) => {
379 self.build_read_version_tuple_from_backup(epoch, self.table_id, key_range)
380 .await
381 }
382 HummockReadEpoch::Committed(epoch) => {
383 let tuple = self
384 .build_read_version_tuple_from_committed(epoch, self.table_id, key_range)
385 .await?;
386 let (_, (_, _, version)) = &tuple;
387 let Some(committed_epoch) = version.table_committed_epoch(self.table_id) else {
388 return Err(HummockError::other(format!(
389 "table {} not found in version",
390 self.table_id
391 ))
392 .into());
393 };
394 if committed_epoch != epoch {
395 return Err(HummockError::committed_epoch_mismatch(
396 self.table_id,
397 committed_epoch,
398 epoch,
399 )
400 .into());
401 }
402 Ok(tuple)
403 }
404 HummockReadEpoch::BatchQueryCommitted(epoch, _)
405 | HummockReadEpoch::TimeTravel(epoch) => {
406 self.build_read_version_tuple_from_committed(epoch, self.table_id, key_range)
407 .await
408 }
409 HummockReadEpoch::NoWait(epoch) => {
410 self.build_read_version_tuple_from_all(epoch, self.table_id, key_range)
411 .await
412 }
413 }
414 }
415
416 async fn build_read_version_tuple_from_backup(
417 &self,
418 epoch: u64,
419 table_id: TableId,
420 key_range: TableKeyRange,
421 ) -> StorageResult<(TableKeyRange, ReadVersionTuple)> {
422 match self
423 .backup_reader
424 .try_get_hummock_version(table_id, epoch)
425 .await
426 {
427 Ok(Some(backup_version)) => Ok(get_committed_read_version_tuple(
428 backup_version,
429 table_id,
430 key_range,
431 epoch,
432 )),
433 Ok(None) => Err(HummockError::read_backup_error(format!(
434 "backup include epoch {} not found",
435 epoch
436 ))
437 .into()),
438 Err(e) => Err(e),
439 }
440 }
441
442 async fn get_epoch_hummock_version(
443 &self,
444 epoch: u64,
445 table_id: TableId,
446 ) -> StorageResult<PinnedVersion> {
447 match self
448 .recent_versions
449 .load()
450 .get_safe_version(table_id, epoch)
451 {
452 Some(version) => Ok(version),
453 None => self.get_time_travel_version(epoch, table_id).await,
454 }
455 }
456
457 async fn build_read_version_tuple_from_committed(
458 &self,
459 epoch: u64,
460 table_id: TableId,
461 key_range: TableKeyRange,
462 ) -> StorageResult<(TableKeyRange, ReadVersionTuple)> {
463 let version = self.get_epoch_hummock_version(epoch, table_id).await?;
464 Ok(get_committed_read_version_tuple(
465 version, table_id, key_range, epoch,
466 ))
467 }
468
469 async fn build_read_version_tuple_from_all(
470 &self,
471 epoch: u64,
472 table_id: TableId,
473 key_range: TableKeyRange,
474 ) -> StorageResult<(TableKeyRange, ReadVersionTuple)> {
475 let pinned_version = self.recent_versions.load().latest_version().clone();
476 let info = pinned_version.state_table_info.info().get(&table_id);
477
478 let ret = if let Some(info) = info
480 && epoch <= info.committed_epoch
481 {
482 let pinned_version = if epoch < info.committed_epoch {
483 pinned_version
484 } else {
485 self.get_epoch_hummock_version(epoch, table_id).await?
486 };
487 get_committed_read_version_tuple(pinned_version, table_id, key_range, epoch)
489 } else {
490 let vnode = vnode(&key_range);
491 let mut matched_replicated_read_version_cnt = 0;
492 let read_version_vec = {
493 let read_guard = self.read_version_mapping.read();
494 read_guard
495 .get(&table_id)
496 .map(|v| {
497 v.values()
498 .filter(|v| {
499 let read_version = v.read();
500 if read_version.is_initialized() && read_version.contains(vnode) {
501 if read_version.is_replicated() {
502 matched_replicated_read_version_cnt += 1;
503 false
504 } else {
505 true
507 }
508 } else {
509 false
510 }
511 })
512 .cloned()
513 .collect_vec()
514 })
515 .unwrap_or_default()
516 };
517
518 if read_version_vec.is_empty() {
521 let table_committed_epoch = info.map(|info| info.committed_epoch);
522 if matched_replicated_read_version_cnt > 0 {
523 tracing::warn!(
524 "Read(table_id={} vnode={} epoch={}) is not allowed on replicated read version ({} found). Fall back to committed version (epoch={:?})",
525 table_id,
526 vnode.to_index(),
527 epoch,
528 matched_replicated_read_version_cnt,
529 table_committed_epoch,
530 );
531 } else {
532 tracing::debug!(
533 "No read version found for read(table_id={} vnode={} epoch={}). Fall back to committed version (epoch={:?})",
534 table_id,
535 vnode.to_index(),
536 epoch,
537 table_committed_epoch
538 );
539 }
540 get_committed_read_version_tuple(pinned_version, table_id, key_range, epoch)
541 } else {
542 if read_version_vec.len() != 1 {
543 let read_version_vnodes = read_version_vec
544 .into_iter()
545 .map(|v| {
546 let v = v.read();
547 v.vnodes().iter_ones().collect_vec()
548 })
549 .collect_vec();
550 return Err(HummockError::other(format!("There are {} read version associated with vnode {}. read_version_vnodes={:?}", read_version_vnodes.len(), vnode.to_index(), read_version_vnodes)).into());
551 }
552 read_filter_for_version(
553 epoch,
554 table_id,
555 key_range,
556 read_version_vec.first().unwrap(),
557 )?
558 }
559 };
560
561 Ok(ret)
562 }
563}
564
565impl HummockStorage {
566 async fn new_local_inner(&self, option: NewLocalOptions) -> LocalHummockStorage {
567 let (tx, rx) = tokio::sync::oneshot::channel();
568 self.hummock_event_sender
569 .send(HummockEvent::RegisterReadVersion {
570 table_id: option.table_id,
571 new_read_version_sender: tx,
572 is_replicated: option.is_replicated,
573 vnodes: option.vnodes.clone(),
574 })
575 .unwrap();
576
577 let (basic_read_version, instance_guard) = rx.await.unwrap();
578 let version_update_notifier_tx = self.version_update_notifier_tx.clone();
579 LocalHummockStorage::new(
580 instance_guard,
581 basic_read_version,
582 self.hummock_version_reader.clone(),
583 self.hummock_event_sender.clone(),
584 self.buffer_tracker.get_memory_limiter().clone(),
585 self.write_limiter.clone(),
586 option,
587 version_update_notifier_tx,
588 self.context.storage_opts.mem_table_spill_threshold,
589 )
590 }
591
592 pub async fn clear_shared_buffer(&self) {
593 let (tx, rx) = oneshot::channel();
594 self.hummock_event_sender
595 .send(HummockEvent::Clear(tx, None))
596 .expect("should send success");
597 rx.await.expect("should wait success");
598 }
599
600 pub async fn clear_tables(&self, table_ids: HashSet<TableId>) {
601 if !table_ids.is_empty() {
602 let (tx, rx) = oneshot::channel();
603 self.hummock_event_sender
604 .send(HummockEvent::Clear(tx, Some(table_ids)))
605 .expect("should send success");
606 rx.await.expect("should wait success");
607 }
608 }
609
610 pub fn start_epoch(&self, epoch: HummockEpoch, table_ids: HashSet<TableId>) {
614 let _ = self
615 .hummock_event_sender
616 .send(HummockEvent::StartEpoch { epoch, table_ids });
617 }
618
619 pub fn sstable_store(&self) -> SstableStoreRef {
620 self.context.sstable_store.clone()
621 }
622
623 pub fn object_id_manager(&self) -> &ObjectIdManagerRef {
624 &self.object_id_manager
625 }
626
627 pub fn compaction_catalog_manager_ref(&self) -> CompactionCatalogManagerRef {
628 self.compaction_catalog_manager_ref.clone()
629 }
630
631 pub fn get_memory_limiter(&self) -> Arc<MemoryLimiter> {
632 self.buffer_tracker.get_memory_limiter().clone()
633 }
634
635 pub fn get_pinned_version(&self) -> PinnedVersion {
636 self.recent_versions.load().latest_version().clone()
637 }
638
639 pub fn backup_reader(&self) -> BackupReaderRef {
640 self.backup_reader.clone()
641 }
642
643 pub fn compaction_await_tree_reg(&self) -> Option<&await_tree::Registry> {
644 self.compact_await_tree_reg.as_ref()
645 }
646
647 pub async fn min_uncommitted_object_id(&self) -> Option<HummockRawObjectId> {
648 let (tx, rx) = oneshot::channel();
649 self.hummock_event_sender
650 .send(HummockEvent::GetMinUncommittedObjectId { result_tx: tx })
651 .expect("should send success");
652 rx.await.expect("should await success")
653 }
654
655 pub async fn sync(
656 &self,
657 sync_table_epochs: Vec<(HummockEpoch, HashSet<TableId>)>,
658 ) -> StorageResult<SyncResult> {
659 let (tx, rx) = oneshot::channel();
660 let _ = self.hummock_event_sender.send(HummockEvent::SyncEpoch {
661 sync_result_sender: tx,
662 sync_table_epochs,
663 });
664 let synced_data = rx
665 .await
666 .map_err(|_| HummockError::other("failed to receive sync result"))??;
667 Ok(synced_data.into_sync_result())
668 }
669}
670
671#[derive(Clone)]
672pub struct HummockStorageReadSnapshot {
673 epoch: HummockReadEpoch,
674 table_id: TableId,
675 table_option: TableOption,
676 recent_versions: Arc<ArcSwap<RecentVersions>>,
677 hummock_version_reader: HummockVersionReader,
678 read_version_mapping: ReadOnlyReadVersionMapping,
679 backup_reader: BackupReaderRef,
680 hummock_meta_client: Arc<dyn HummockMetaClient>,
681 simple_time_travel_version_cache: Arc<SimpleTimeTravelVersionCache>,
682}
683
684impl StateStoreGet for HummockStorageReadSnapshot {
685 fn on_key_value<'a, O: Send + 'a>(
686 &'a self,
687 key: TableKey<Bytes>,
688 read_options: ReadOptions,
689 on_key_value_fn: impl KeyValueFn<'a, O>,
690 ) -> impl StorageFuture<'a, Option<O>> {
691 self.get_inner(key, read_options, on_key_value_fn)
692 }
693}
694
695impl StateStoreRead for HummockStorageReadSnapshot {
696 type Iter = HummockStorageIterator;
697 type RevIter = HummockStorageRevIterator;
698
699 fn iter(
700 &self,
701 key_range: TableKeyRange,
702 read_options: ReadOptions,
703 ) -> impl Future<Output = StorageResult<Self::Iter>> + '_ {
704 let (l_vnode_inclusive, r_vnode_exclusive) = vnode_range(&key_range);
705 assert_eq!(
706 r_vnode_exclusive - l_vnode_inclusive,
707 1,
708 "read range {:?} for table {} iter contains more than one vnode",
709 key_range,
710 self.table_id
711 );
712 self.iter_inner(key_range, read_options)
713 }
714
715 fn rev_iter(
716 &self,
717 key_range: TableKeyRange,
718 read_options: ReadOptions,
719 ) -> impl Future<Output = StorageResult<Self::RevIter>> + '_ {
720 let (l_vnode_inclusive, r_vnode_exclusive) = vnode_range(&key_range);
721 assert_eq!(
722 r_vnode_exclusive - l_vnode_inclusive,
723 1,
724 "read range {:?} for table {} iter contains more than one vnode",
725 key_range,
726 self.table_id
727 );
728 self.rev_iter_inner(key_range, read_options)
729 }
730}
731
732impl StateStoreReadVector for HummockStorageReadSnapshot {
733 async fn nearest<'a, O: Send + 'a>(
734 &'a self,
735 vec: VectorRef<'a>,
736 options: VectorNearestOptions,
737 on_nearest_item_fn: impl OnNearestItemFn<'a, O>,
738 ) -> StorageResult<Vec<O>> {
739 let version = match self.epoch {
740 HummockReadEpoch::Committed(epoch)
741 | HummockReadEpoch::BatchQueryCommitted(epoch, _)
742 | HummockReadEpoch::TimeTravel(epoch) => {
743 self.get_epoch_hummock_version(epoch, self.table_id).await?
744 }
745 HummockReadEpoch::Backup(epoch) => self
746 .backup_reader
747 .try_get_hummock_version(self.table_id, epoch)
748 .await?
749 .ok_or_else(|| {
750 HummockError::read_backup_error(format!(
751 "backup include epoch {} not found",
752 epoch
753 ))
754 })?,
755 HummockReadEpoch::NoWait(_) => {
756 return Err(
757 HummockError::other("nearest query does not support NoWait epoch").into(),
758 );
759 }
760 };
761 dispatch_distance_measurement!(options.measure, MeasurementType, {
762 Ok(self
763 .hummock_version_reader
764 .nearest::<MeasurementType, O>(
765 version,
766 self.table_id,
767 vec,
768 options,
769 on_nearest_item_fn,
770 )
771 .await?)
772 })
773 }
774}
775
776impl StateStoreReadLog for HummockStorage {
777 type ChangeLogIter = ChangeLogIterator;
778
779 async fn next_epoch(&self, epoch: u64, options: NextEpochOptions) -> StorageResult<u64> {
780 fn next_epoch(
781 table_change_log: &TableChangeLogs,
782 epoch: u64,
783 table_id: TableId,
784 ) -> HummockResult<Option<u64>> {
785 let table_change_log = table_change_log.get(&table_id).ok_or_else(|| {
786 HummockError::next_epoch(format!("table {} has been dropped", table_id))
787 })?;
788 table_change_log
789 .next_epoch(epoch)
790 .map_err(|_| HummockError::change_log_retention_miss(table_id, epoch))
791 }
792 {
793 if let Some(max_epoch) = self
795 .recent_versions
796 .load()
797 .latest_version()
798 .deref()
799 .state_table_info
800 .info()
801 .get(&options.table_id)
802 .map(|i| i.committed_epoch)
803 && max_epoch > epoch
804 {
805 let table_change_log = self
807 .table_change_log_manager
808 .fetch_table_change_logs(options.table_id, (epoch, max_epoch), true, Some(2))
809 .await?;
810 if let Some(next_epoch) = next_epoch(&table_change_log, epoch, options.table_id)? {
811 return Ok(next_epoch);
812 }
813 }
814 }
815 let mut max_epoch = None;
816 wait_for_update(
817 &self.version_update_notifier_tx,
818 |version| {
819 let Some(mce) = version
820 .state_table_info
821 .info()
822 .get(&options.table_id)
823 .map(|i| i.committed_epoch)
824 else {
825 return Ok(false);
826 };
827 max_epoch = Some(mce);
828 Ok(mce > epoch)
829 },
830 || format!("wait next_epoch: epoch: {} {}", epoch, options.table_id),
831 )
832 .await?;
833 let table_change_log = self
835 .table_change_log_manager
836 .fetch_table_change_logs(
837 options.table_id,
838 (epoch, max_epoch.unwrap_or(u64::MAX)),
839 true,
840 Some(2),
841 )
842 .await?;
843 let next_epoch_ret = next_epoch(&table_change_log, epoch, options.table_id)?;
844 next_epoch_ret.ok_or_else(|| {
845 HummockError::next_epoch(format!(
846 "next_epoch for {} {} should be valid",
847 options.table_id, epoch
848 ))
849 .into()
850 })
851 }
852
853 async fn iter_log(
854 &self,
855 epoch_range: (u64, u64),
856 key_range: TableKeyRange,
857 options: ReadLogOptions,
858 ) -> StorageResult<Self::ChangeLogIter> {
859 let iter = self
860 .hummock_version_reader
861 .iter_log(
862 epoch_range,
863 key_range,
864 options,
865 self.table_change_log_manager.clone(),
866 )
867 .await?;
868 Ok(iter)
869 }
870}
871
872impl HummockStorage {
873 async fn try_wait_epoch_impl(
876 &self,
877 wait_epoch: HummockReadEpoch,
878 table_id: TableId,
879 ) -> StorageResult<()> {
880 tracing::debug!(
881 "try_wait_epoch: epoch: {:?}, table_id: {}",
882 wait_epoch,
883 table_id
884 );
885 match wait_epoch {
886 HummockReadEpoch::Committed(wait_epoch) => {
887 assert!(!is_max_epoch(wait_epoch), "epoch should not be MAX EPOCH");
888 wait_for_epoch(&self.version_update_notifier_tx, wait_epoch, table_id).await?;
889 }
890 HummockReadEpoch::BatchQueryCommitted(wait_epoch, wait_version_id) => {
891 assert!(!is_max_epoch(wait_epoch), "epoch should not be MAX EPOCH");
892 {
894 let recent_versions = self.recent_versions.load();
895 let latest_version = recent_versions.latest_version();
896 if latest_version.id >= wait_version_id
897 && let Some(committed_epoch) =
898 latest_version.table_committed_epoch(table_id)
899 && committed_epoch >= wait_epoch
900 {
901 return Ok(());
902 }
903 }
904 wait_for_update(
905 &self.version_update_notifier_tx,
906 |version| {
907 if wait_version_id > version.id() {
908 return Ok(false);
909 }
910 let committed_epoch =
911 version.table_committed_epoch(table_id).ok_or_else(|| {
912 HummockError::wait_epoch(format!(
916 "table id {} has been dropped",
917 table_id
918 ))
919 })?;
920 Ok(committed_epoch >= wait_epoch)
921 },
922 || {
923 format!(
924 "try_wait_epoch: epoch: {}, version_id: {:?}",
925 wait_epoch, wait_version_id
926 )
927 },
928 )
929 .await?;
930 }
931 _ => {}
932 };
933 Ok(())
934 }
935}
936
937impl StateStore for HummockStorage {
938 type Local = LocalHummockStorage;
939 type ReadSnapshot = HummockStorageReadSnapshot;
940 type VectorWriter = HummockVectorWriter;
941
942 async fn try_wait_epoch(
945 &self,
946 wait_epoch: HummockReadEpoch,
947 options: TryWaitEpochOptions,
948 ) -> StorageResult<()> {
949 self.try_wait_epoch_impl(wait_epoch, options.table_id).await
950 }
951
952 fn new_local(&self, option: NewLocalOptions) -> impl Future<Output = Self::Local> + Send + '_ {
953 self.new_local_inner(option)
954 }
955
956 async fn new_read_snapshot(
957 &self,
958 epoch: HummockReadEpoch,
959 options: NewReadSnapshotOptions,
960 ) -> StorageResult<Self::ReadSnapshot> {
961 self.try_wait_epoch_impl(epoch, options.table_id).await?;
962 Ok(HummockStorageReadSnapshot {
963 epoch,
964 table_id: options.table_id,
965 table_option: options.table_option,
966 recent_versions: self.recent_versions.clone(),
967 hummock_version_reader: self.hummock_version_reader.clone(),
968 read_version_mapping: self.read_version_mapping.clone(),
969 backup_reader: self.backup_reader.clone(),
970 hummock_meta_client: self.hummock_meta_client.clone(),
971 simple_time_travel_version_cache: self.simple_time_travel_version_cache.clone(),
972 })
973 }
974
975 async fn new_vector_writer(&self, options: NewVectorWriterOptions) -> Self::VectorWriter {
976 HummockVectorWriter::new(
977 options.table_id,
978 self.version_update_notifier_tx.clone(),
979 self.context.sstable_store.clone(),
980 self.object_id_manager.clone(),
981 self.hummock_event_sender.clone(),
982 self.hummock_version_reader.stats().clone(),
983 self.context.storage_opts.clone(),
984 )
985 }
986}
987
988#[cfg(any(test, feature = "test"))]
989impl HummockStorage {
990 pub async fn seal_and_sync_epoch(
991 &self,
992 epoch: u64,
993 table_ids: HashSet<TableId>,
994 ) -> StorageResult<risingwave_hummock_sdk::SyncResult> {
995 self.sync(vec![(epoch, table_ids)]).await
996 }
997
998 pub async fn update_version_and_wait(&self, version: HummockVersion) {
1000 use tokio::task::yield_now;
1001 let version_id = version.id;
1002 self._version_update_sender
1003 .send(HummockVersionUpdate::PinnedVersion(Box::new(version)))
1004 .unwrap();
1005 loop {
1006 if self.recent_versions.load().latest_version().id() >= version_id {
1007 break;
1008 }
1009
1010 yield_now().await
1011 }
1012 }
1013
1014 pub async fn wait_version(&self, version: HummockVersion) {
1015 use tokio::task::yield_now;
1016 loop {
1017 if self.recent_versions.load().latest_version().id() >= version.id {
1018 break;
1019 }
1020
1021 yield_now().await
1022 }
1023 }
1024
1025 pub async fn for_test(
1027 options: Arc<StorageOpts>,
1028 sstable_store: SstableStoreRef,
1029 hummock_meta_client: Arc<dyn HummockMetaClient>,
1030 notification_client: impl NotificationClient,
1031 ) -> HummockResult<Self> {
1032 let compaction_catalog_manager = Arc::new(CompactionCatalogManager::new(Box::new(
1033 FakeRemoteTableAccessor {},
1034 )));
1035
1036 Self::new(
1037 options,
1038 sstable_store,
1039 hummock_meta_client,
1040 notification_client,
1041 compaction_catalog_manager,
1042 Arc::new(HummockStateStoreMetrics::unused()),
1043 Arc::new(CompactorMetrics::unused()),
1044 None,
1045 )
1046 .await
1047 }
1048
1049 pub fn storage_opts(&self) -> &Arc<StorageOpts> {
1050 &self.context.storage_opts
1051 }
1052
1053 pub fn version_reader(&self) -> &HummockVersionReader {
1054 &self.hummock_version_reader
1055 }
1056
1057 pub async fn wait_version_update(
1058 &self,
1059 old_id: risingwave_hummock_sdk::HummockVersionId,
1060 ) -> risingwave_hummock_sdk::HummockVersionId {
1061 use tokio::task::yield_now;
1062 loop {
1063 let cur_id = self.recent_versions.load().latest_version().id();
1064 if cur_id > old_id {
1065 return cur_id;
1066 }
1067 yield_now().await;
1068 }
1069 }
1070
1071 #[cfg(any(test, feature = "test"))]
1072 pub async fn flush_events_for_test(&self) {
1073 let (tx, rx) = oneshot::channel();
1074 self.hummock_event_sender
1075 .send(HummockEvent::FlushEvent(tx))
1076 .expect("flush event should succeed");
1077 rx.await.expect("flush event receiver dropped");
1078 }
1079}