Skip to main content

risingwave_storage/hummock/store/
local_hummock_storage.rs

1// Copyright 2023 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::future::Future;
16use std::iter::once;
17use std::ops::Bound;
18use std::sync::Arc;
19
20use await_tree::{InstrumentAwait, SpanExt};
21use bytes::Bytes;
22use risingwave_common::bitmap::Bitmap;
23use risingwave_common::catalog::{TableId, TableOption};
24use risingwave_common::hash::VirtualNode;
25use risingwave_common::util::epoch::{EpochPair, MAX_EPOCH, MAX_SPILL_TIMES};
26use risingwave_hummock_sdk::key::{
27    FullKey, TableKey, TableKeyRange, UserKey, is_empty_key_range, vnode_range,
28};
29use risingwave_hummock_sdk::sstable_info::SstableInfo;
30use risingwave_hummock_sdk::{EpochWithGap, HummockEpoch};
31use tracing::{Instrument, warn};
32
33use super::version::VersionUpdate;
34use crate::error::StorageResult;
35use crate::hummock::event_handler::hummock_event_handler::HummockEventSender;
36use crate::hummock::event_handler::{HummockEvent, HummockReadVersionRef, LocalInstanceGuard};
37use crate::hummock::iterator::{
38    Backward, BackwardUserIterator, ConcatIteratorInner, Forward, HummockIteratorUnion,
39    IteratorFactory, MergeIterator, UserIterator,
40};
41use crate::hummock::local_version::pinned_version::PinnedVersion;
42use crate::hummock::shared_buffer::TableMemoryMetrics;
43use crate::hummock::shared_buffer::shared_buffer_batch::{
44    SharedBufferBatch, SharedBufferBatchIterator, SharedBufferBatchOldValues, SharedBufferItem,
45    SharedBufferValue,
46};
47use crate::hummock::store::version::{HummockVersionReader, read_filter_for_version};
48use crate::hummock::utils::{
49    do_delete_sanity_check, do_insert_sanity_check, do_update_sanity_check, sanity_check_enabled,
50    wait_for_epoch,
51};
52use crate::hummock::write_limiter::WriteLimiterRef;
53use crate::hummock::{
54    BackwardSstableIterator, HummockError, MemoryLimiter, SstableIterator,
55    SstableIteratorReadOptions, SstableStoreRef,
56};
57use crate::mem_table::{KeyOp, MemTable, MemTableHummockIterator, MemTableHummockRevIterator};
58use crate::monitor::{HummockStateStoreMetrics, IterLocalMetricsGuard, StoreLocalStatistic};
59use crate::store::*;
60
61/// `LocalHummockStorage` is a handle for a state table shard to access data from and write data to
62/// the hummock state backend. It is created via `HummockStorage::new_local`.
63pub struct LocalHummockStorage {
64    mem_table: MemTable,
65
66    spill_offset: u16,
67    epoch: Option<EpochPair>,
68
69    table_id: TableId,
70    op_consistency_level: OpConsistencyLevel,
71    table_option: TableOption,
72
73    instance_guard: LocalInstanceGuard,
74
75    /// Read handle.
76    read_version: HummockReadVersionRef,
77
78    /// This indicates that this `LocalHummockStorage` replicates another `LocalHummockStorage`.
79    /// It's used by executors in different CNs to synchronize states.
80    ///
81    /// Within `LocalHummockStorage` we use this flag to avoid uploading local state to be
82    /// persisted, so we won't have duplicate data.
83    ///
84    /// This also handles a corner case where an executor doing replication
85    /// is scheduled to the same CN as its Upstream executor.
86    /// In that case, we use this flag to avoid reading the same data twice,
87    /// by ignoring the replicated `ReadVersion`.
88    is_replicated: bool,
89
90    /// Whether or not send imm to uploader on every flush.
91    upload_on_flush: bool,
92
93    /// Event sender.
94    event_sender: HummockEventSender,
95
96    memory_limiter: Arc<MemoryLimiter>,
97
98    hummock_version_reader: HummockVersionReader,
99
100    table_memory_metrics: Arc<TableMemoryMetrics>,
101
102    write_limiter: WriteLimiterRef,
103
104    version_update_notifier_tx: Arc<tokio::sync::watch::Sender<PinnedVersion>>,
105
106    mem_table_spill_threshold: usize,
107}
108
109impl LocalHummockFlushedSnapshotReader {
110    async fn get_flushed<'a, O>(
111        hummock_version_reader: &'a HummockVersionReader,
112        read_version: &HummockReadVersionRef,
113        user_key: UserKey<Bytes>,
114        table_option: TableOption,
115        read_options: ReadOptions,
116        on_key_value_fn: impl KeyValueFn<'a, O>,
117        epoch: HummockEpoch,
118    ) -> StorageResult<Option<O>> {
119        let table_key_range = (
120            Bound::Included(user_key.table_key.clone()),
121            Bound::Included(user_key.table_key.clone()),
122        );
123
124        let (table_key_range, read_snapshot) =
125            read_filter_for_version(epoch, user_key.table_id, table_key_range, read_version)?;
126
127        if is_empty_key_range(&table_key_range) {
128            return Ok(None);
129        }
130
131        hummock_version_reader
132            .get(
133                user_key.table_key,
134                epoch,
135                user_key.table_id,
136                table_option,
137                read_options,
138                read_snapshot,
139                on_key_value_fn,
140            )
141            .await
142    }
143
144    async fn iter_flushed(
145        &self,
146        table_key_range: TableKeyRange,
147        read_options: ReadOptions,
148        epoch: HummockEpoch,
149    ) -> StorageResult<HummockStorageIterator> {
150        let (table_key_range, read_snapshot) =
151            read_filter_for_version(epoch, self.table_id, table_key_range, &self.read_version)?;
152
153        let table_key_range = table_key_range;
154
155        self.hummock_version_reader
156            .iter(
157                table_key_range,
158                epoch,
159                self.table_id,
160                self.table_option,
161                read_options,
162                read_snapshot,
163            )
164            .await
165    }
166
167    async fn rev_iter_flushed(
168        &self,
169        table_key_range: TableKeyRange,
170        read_options: ReadOptions,
171        epoch: HummockEpoch,
172    ) -> StorageResult<HummockStorageRevIterator> {
173        let (table_key_range, read_snapshot) =
174            read_filter_for_version(epoch, self.table_id, table_key_range, &self.read_version)?;
175
176        let table_key_range = table_key_range;
177
178        self.hummock_version_reader
179            .rev_iter(
180                table_key_range,
181                epoch,
182                self.table_id,
183                self.table_option,
184                read_options,
185                read_snapshot,
186                None,
187            )
188            .await
189    }
190}
191
192impl LocalHummockStorage {
193    fn epoch(&self) -> u64 {
194        self.epoch.expect("should have set the epoch").curr
195    }
196
197    fn current_epoch_with_gap(&self) -> EpochWithGap {
198        EpochWithGap::new(self.epoch(), self.spill_offset)
199    }
200
201    fn mem_table_iter(&self) -> MemTableHummockIterator<'_> {
202        MemTableHummockIterator::new(
203            &self.mem_table.buffer,
204            self.current_epoch_with_gap(),
205            self.table_id,
206        )
207    }
208
209    fn mem_table_rev_iter(&self) -> MemTableHummockRevIterator<'_> {
210        MemTableHummockRevIterator::new(
211            &self.mem_table.buffer,
212            self.current_epoch_with_gap(),
213            self.table_id,
214        )
215    }
216
217    async fn iter_all(
218        &self,
219        table_key_range: TableKeyRange,
220        epoch: u64,
221        read_options: ReadOptions,
222    ) -> StorageResult<LocalHummockStorageIterator<'_>> {
223        let (table_key_range, read_snapshot) =
224            read_filter_for_version(epoch, self.table_id, table_key_range, &self.read_version)?;
225
226        self.hummock_version_reader
227            .iter_with_memtable(
228                table_key_range,
229                epoch,
230                self.table_id,
231                self.table_option,
232                read_options,
233                read_snapshot,
234                Some(self.mem_table_iter()),
235            )
236            .await
237    }
238
239    async fn rev_iter_all(
240        &self,
241        table_key_range: TableKeyRange,
242        epoch: u64,
243        read_options: ReadOptions,
244    ) -> StorageResult<LocalHummockStorageRevIterator<'_>> {
245        let (table_key_range, read_snapshot) =
246            read_filter_for_version(epoch, self.table_id, table_key_range, &self.read_version)?;
247
248        self.hummock_version_reader
249            .rev_iter(
250                table_key_range,
251                epoch,
252                self.table_id,
253                self.table_option,
254                read_options,
255                read_snapshot,
256                Some(self.mem_table_rev_iter()),
257            )
258            .await
259    }
260}
261
262#[derive(Clone)]
263pub struct LocalHummockFlushedSnapshotReader {
264    table_id: TableId,
265    table_option: TableOption,
266    read_version: HummockReadVersionRef,
267    hummock_version_reader: HummockVersionReader,
268    epoch: HummockEpoch,
269}
270
271impl StateStoreGet for LocalHummockFlushedSnapshotReader {
272    async fn on_key_value<'a, O: Send + 'a>(
273        &'a self,
274        key: TableKey<Bytes>,
275        read_options: ReadOptions,
276        on_key_value_fn: impl KeyValueFn<'a, O>,
277    ) -> StorageResult<Option<O>> {
278        let key = UserKey::new(self.table_id, key);
279        Self::get_flushed(
280            &self.hummock_version_reader,
281            &self.read_version,
282            key,
283            self.table_option,
284            read_options,
285            on_key_value_fn,
286            self.epoch,
287        )
288        .await
289    }
290}
291
292impl StateStoreRead for LocalHummockFlushedSnapshotReader {
293    type Iter = HummockStorageIterator;
294    type RevIter = HummockStorageRevIterator;
295
296    fn read_epoch(&self) -> Option<u64> {
297        Some(self.epoch)
298    }
299
300    fn iter(
301        &self,
302        key_range: TableKeyRange,
303        read_options: ReadOptions,
304    ) -> impl Future<Output = StorageResult<Self::Iter>> + '_ {
305        self.iter_flushed(key_range, read_options, self.epoch)
306            .instrument(tracing::trace_span!("hummock_iter"))
307    }
308
309    fn rev_iter(
310        &self,
311        key_range: TableKeyRange,
312        read_options: ReadOptions,
313    ) -> impl Future<Output = StorageResult<Self::RevIter>> + '_ {
314        self.rev_iter_flushed(key_range, read_options, self.epoch)
315            .instrument(tracing::trace_span!("hummock_rev_iter"))
316    }
317}
318
319impl StateStoreGet for LocalHummockStorage {
320    async fn on_key_value<'a, O: Send + 'a>(
321        &'a self,
322        key: TableKey<Bytes>,
323        read_options: ReadOptions,
324        on_key_value_fn: impl KeyValueFn<'a, O>,
325    ) -> StorageResult<Option<O>> {
326        let key = UserKey::new(self.table_id, key);
327        match self.mem_table.buffer.get(&key.table_key) {
328            None => {
329                LocalHummockFlushedSnapshotReader::get_flushed(
330                    &self.hummock_version_reader,
331                    &self.read_version,
332                    key,
333                    self.table_option,
334                    read_options,
335                    on_key_value_fn,
336                    self.epoch(),
337                )
338                .await
339            }
340            Some(op) => match op {
341                KeyOp::Insert(value) | KeyOp::Update((_, value)) => Ok({
342                    Some(on_key_value_fn(
343                        FullKey::new_with_gap_epoch(
344                            self.table_id,
345                            key.table_key.to_ref(),
346                            self.current_epoch_with_gap(),
347                        ),
348                        value.as_ref(),
349                    )?)
350                }),
351                KeyOp::Delete(_) => Ok(None),
352            },
353        }
354    }
355}
356
357impl LocalStateStore for LocalHummockStorage {
358    type FlushedSnapshotReader = LocalHummockFlushedSnapshotReader;
359    type Iter<'a> = LocalHummockStorageIterator<'a>;
360    type RevIter<'a> = LocalHummockStorageRevIterator<'a>;
361
362    async fn iter(
363        &self,
364        key_range: TableKeyRange,
365        read_options: ReadOptions,
366    ) -> StorageResult<Self::Iter<'_>> {
367        let (l_vnode_inclusive, r_vnode_exclusive) = vnode_range(&key_range);
368        assert_eq!(
369            r_vnode_exclusive - l_vnode_inclusive,
370            1,
371            "read range {:?} for table {} iter contains more than one vnode",
372            key_range,
373            self.table_id
374        );
375        self.iter_all(key_range.clone(), self.epoch(), read_options)
376            .await
377    }
378
379    async fn rev_iter(
380        &self,
381        key_range: TableKeyRange,
382        read_options: ReadOptions,
383    ) -> StorageResult<Self::RevIter<'_>> {
384        let (l_vnode_inclusive, r_vnode_exclusive) = vnode_range(&key_range);
385        assert_eq!(
386            r_vnode_exclusive - l_vnode_inclusive,
387            1,
388            "read range {:?} for table {} iter contains more than one vnode",
389            key_range,
390            self.table_id
391        );
392        self.rev_iter_all(key_range.clone(), self.epoch(), read_options)
393            .await
394    }
395
396    fn new_flushed_snapshot_reader(&self) -> Self::FlushedSnapshotReader {
397        assert_eq!(
398            self.table_option.retention_seconds, None,
399            "flushed snapshot reader should not work with table {} with ttl",
400            self.table_id
401        );
402        self.new_flushed_snapshot_reader_inner(MAX_EPOCH)
403    }
404
405    fn get_table_watermark(&self, vnode: VirtualNode) -> Option<Bytes> {
406        self.read_version.read().latest_watermark(vnode)
407    }
408
409    fn insert(
410        &mut self,
411        key: TableKey<Bytes>,
412        new_val: Bytes,
413        old_val: Option<Bytes>,
414    ) -> StorageResult<()> {
415        match old_val {
416            None => self.mem_table.insert(key, new_val)?,
417            Some(old_val) => self.mem_table.update(key, old_val, new_val)?,
418        };
419
420        Ok(())
421    }
422
423    fn delete(&mut self, key: TableKey<Bytes>, old_val: Bytes) -> StorageResult<()> {
424        self.mem_table.delete(key, old_val)?;
425
426        Ok(())
427    }
428
429    async fn update_vnode_bitmap(&mut self, vnodes: Arc<Bitmap>) -> StorageResult<Arc<Bitmap>> {
430        self.update_vnode_bitmap_impl(vnodes).await
431    }
432}
433
434impl StateStoreWriteEpochControl for LocalHummockStorage {
435    async fn flush(&mut self) -> StorageResult<usize> {
436        let buffer = self.mem_table.drain().into_parts();
437        let mut kv_pairs = Vec::with_capacity(buffer.len());
438        let mut old_values = if self.is_flush_old_value() {
439            Some(Vec::with_capacity(buffer.len()))
440        } else {
441            None
442        };
443        let sanity_check_flushed_snapshot_reader = if sanity_check_enabled() {
444            Some(self.new_flushed_snapshot_reader_inner(self.epoch()))
445        } else {
446            None
447        };
448        for (key, key_op) in buffer {
449            match key_op {
450                // Currently, some executors do not strictly comply with these semantics. As
451                // a workaround you may call disable the check by initializing the
452                // state store with `is_consistent_op=false`.
453                KeyOp::Insert(value) => {
454                    if let Some(sanity_check_reader) = &sanity_check_flushed_snapshot_reader {
455                        do_insert_sanity_check(
456                            self.table_id,
457                            &key,
458                            &value,
459                            sanity_check_reader,
460                            &self.op_consistency_level,
461                        )
462                        .await?;
463                    }
464                    kv_pairs.push((key, SharedBufferValue::Insert(value)));
465                    if let Some(old_values) = &mut old_values {
466                        old_values.push(Bytes::new());
467                    }
468                }
469                KeyOp::Delete(old_value) => {
470                    if let Some(sanity_check_reader) = &sanity_check_flushed_snapshot_reader {
471                        do_delete_sanity_check(
472                            self.table_id,
473                            &key,
474                            &old_value,
475                            sanity_check_reader,
476                            &self.op_consistency_level,
477                        )
478                        .await?;
479                    }
480                    kv_pairs.push((key, SharedBufferValue::Delete));
481                    if let Some(old_values) = &mut old_values {
482                        old_values.push(old_value);
483                    }
484                }
485                KeyOp::Update((old_value, new_value)) => {
486                    if let Some(sanity_check_reader) = &sanity_check_flushed_snapshot_reader {
487                        do_update_sanity_check(
488                            self.table_id,
489                            &key,
490                            &old_value,
491                            &new_value,
492                            sanity_check_reader,
493                            &self.op_consistency_level,
494                        )
495                        .await?;
496                    }
497                    kv_pairs.push((key, SharedBufferValue::Update(new_value)));
498                    if let Some(old_values) = &mut old_values {
499                        old_values.push(old_value);
500                    }
501                }
502            }
503        }
504        self.flush_inner(kv_pairs, old_values).await
505    }
506
507    async fn try_flush(&mut self) -> StorageResult<()> {
508        if self.mem_table_spill_threshold != 0
509            && self.mem_table.kv_size.size() > self.mem_table_spill_threshold
510        {
511            if self.spill_offset < MAX_SPILL_TIMES {
512                self.flush().await?;
513                self.table_memory_metrics.mem_table_spill_counts.inc();
514            } else {
515                tracing::warn!("No mem table spill occurs, the gap epoch exceeds available range.");
516            }
517        }
518
519        Ok(())
520    }
521
522    async fn init(&mut self, options: InitOptions) -> StorageResult<()> {
523        let epoch = options.epoch;
524        wait_for_epoch(&self.version_update_notifier_tx, epoch.prev, self.table_id).await?;
525        assert_eq!(
526            self.epoch.replace(epoch),
527            None,
528            "local state store of table id {:?} is init for more than once",
529            self.table_id
530        );
531        self.read_version.write().init();
532        if !self.is_replicated {
533            self.event_sender
534                .send(HummockEvent::InitEpoch {
535                    instance_id: self.instance_id(),
536                    init_epoch: options.epoch.curr,
537                })
538                .map_err(|_| {
539                    HummockError::other("failed to send InitEpoch. maybe shutting down")
540                })?;
541        }
542        Ok(())
543    }
544
545    fn seal_current_epoch(&mut self, next_epoch: u64, mut opts: SealCurrentEpochOptions) {
546        assert!(!self.mem_table.is_dirty());
547        if !self.is_replicated {
548            if self.upload_on_flush {
549                debug_assert_eq!(self.read_version.write().pending_imm_size(), 0);
550            } else {
551                let pending_imms = self.read_version.write().start_upload_pending_imms();
552                if !pending_imms.is_empty()
553                    && self
554                        .event_sender
555                        .send(HummockEvent::ImmToUploader {
556                            instance_id: self.instance_id(),
557                            imms: pending_imms,
558                        })
559                        .is_err()
560                {
561                    warn!("failed to send ImmToUploader during seal. maybe shutting down");
562                }
563            }
564        }
565
566        if let Some(new_level) = &opts.switch_op_consistency_level {
567            self.mem_table.op_consistency_level.update(new_level);
568            self.op_consistency_level.update(new_level);
569        }
570        let epoch = self
571            .epoch
572            .as_mut()
573            .expect("should have init epoch before seal the first epoch");
574        let prev_epoch = epoch.curr;
575        epoch.prev = prev_epoch;
576        epoch.curr = next_epoch;
577        self.spill_offset = 0;
578        assert!(
579            next_epoch > prev_epoch,
580            "new epoch {} should be greater than current epoch: {}",
581            next_epoch,
582            prev_epoch
583        );
584
585        if let Some((direction, watermarks, watermark_type)) = &mut opts.table_watermarks {
586            let mut read_version = self.read_version.write();
587            read_version.filter_regress_watermarks(watermarks);
588            if !watermarks.is_empty() {
589                read_version.update(VersionUpdate::NewTableWatermark {
590                    direction: *direction,
591                    epoch: prev_epoch,
592                    vnode_watermarks: watermarks.clone(),
593                    watermark_type: *watermark_type,
594                });
595            }
596        }
597
598        if !self.is_replicated
599            && self
600                .event_sender
601                .send(HummockEvent::LocalSealEpoch {
602                    instance_id: self.instance_id(),
603                    next_epoch,
604                    opts,
605                })
606                .is_err()
607        {
608            warn!("failed to send LocalSealEpoch. maybe shutting down");
609        }
610    }
611}
612
613impl LocalHummockStorage {
614    async fn update_vnode_bitmap_impl(
615        &mut self,
616        vnodes: Arc<Bitmap>,
617    ) -> StorageResult<Arc<Bitmap>> {
618        wait_for_epoch(
619            &self.version_update_notifier_tx,
620            self.epoch.expect("should have init").prev,
621            self.table_id,
622        )
623        .await?;
624        assert!(!self.mem_table.is_dirty());
625        let mut read_version = self.read_version.write();
626        assert!(
627            read_version.staging().is_empty(),
628            "There is uncommitted staging data in read version table_id {:?} instance_id {:?} on vnode bitmap update",
629            self.table_id(),
630            self.instance_id()
631        );
632        Ok(read_version.update_vnode_bitmap(vnodes))
633    }
634
635    fn new_flushed_snapshot_reader_inner(
636        &self,
637        epoch: HummockEpoch,
638    ) -> LocalHummockFlushedSnapshotReader {
639        LocalHummockFlushedSnapshotReader {
640            table_id: self.table_id,
641            table_option: self.table_option,
642            read_version: self.read_version.clone(),
643            hummock_version_reader: self.hummock_version_reader.clone(),
644            epoch,
645        }
646    }
647
648    async fn flush_inner(
649        &mut self,
650        sorted_items: Vec<SharedBufferItem>,
651        old_values: Option<Vec<Bytes>>,
652    ) -> StorageResult<usize> {
653        let epoch = self.epoch();
654        let table_id = self.table_id;
655
656        self.table_memory_metrics
657            .write_batch_tuple_counts
658            .inc_by(sorted_items.len() as _);
659        let timer = self.table_memory_metrics.write_batch_duration.start_timer();
660
661        let imm_size = if !sorted_items.is_empty() {
662            let (size, old_value_size) =
663                SharedBufferBatch::measure_batch_size(&sorted_items, old_values.as_deref());
664
665            let old_values = old_values.map(|old_values| {
666                SharedBufferBatchOldValues::new(
667                    old_values,
668                    old_value_size,
669                    self.table_memory_metrics.old_value_size.clone(),
670                )
671            });
672
673            let instance_id = self.instance_guard.instance_id;
674            let imm = SharedBufferBatch::build_shared_buffer_batch(
675                epoch,
676                self.spill_offset,
677                sorted_items,
678                old_values,
679                size,
680                table_id,
681                self.table_memory_metrics.clone(),
682            );
683            self.spill_offset += 1;
684
685            if self.is_replicated {
686                // A replicated imm cannot be uploaded independently: it is discarded when the
687                // source table's committed epoch catches up. It therefore bypasses the regular
688                // write and memory limiters. Keep this memory visible through
689                // `state_store_replicated_imm_size`, especially for operators that maintain one
690                // full replica per actor.
691                self.read_version.write().add_replicated_imm(imm);
692            } else {
693                self.write_limiter.wait_permission(self.table_id).await;
694                let limiter = &self.memory_limiter;
695                let (tracker, fast_required_memory) = match limiter.try_require_memory(size as u64)
696                {
697                    Some(tracker) => (tracker, true),
698                    None => {
699                        warn!(
700                            "blocked at requiring memory: {}, current {}",
701                            size,
702                            limiter.get_memory_usage()
703                        );
704                        self.event_sender
705                            .send(HummockEvent::BufferMayFlush)
706                            .expect("should be able to send");
707                        let tracker = limiter
708                            .require_memory(size as u64)
709                            .instrument_await("hummock_require_memory".verbose())
710                            .await;
711                        warn!(
712                            "successfully requiring memory: {}, current {}",
713                            size,
714                            limiter.get_memory_usage()
715                        );
716                        (tracker, false)
717                    }
718                };
719                let mut read_version = self.read_version.write();
720                read_version.add_pending_imm(imm, tracker);
721                if self.upload_on_flush
722                    || read_version.pending_imm_size() >= self.mem_table_spill_threshold
723                    || !fast_required_memory
724                {
725                    let imms = read_version.start_upload_pending_imms();
726                    self.event_sender
727                        .send(HummockEvent::ImmToUploader { instance_id, imms })
728                        .map_err(|_| {
729                            HummockError::other(
730                                "failed to send imm to uploader. maybe shutting down",
731                            )
732                        })?;
733                }
734            }
735
736            size
737        } else {
738            0
739        };
740
741        timer.observe_duration();
742
743        self.table_memory_metrics
744            .write_batch_size
745            .observe(imm_size as _);
746        Ok(imm_size)
747    }
748}
749
750impl LocalHummockStorage {
751    pub fn new(
752        instance_guard: LocalInstanceGuard,
753        read_version: HummockReadVersionRef,
754        hummock_version_reader: HummockVersionReader,
755        event_sender: HummockEventSender,
756        memory_limiter: Arc<MemoryLimiter>,
757        write_limiter: WriteLimiterRef,
758        option: NewLocalOptions,
759        version_update_notifier_tx: Arc<tokio::sync::watch::Sender<PinnedVersion>>,
760        mem_table_spill_threshold: usize,
761    ) -> Self {
762        let table_memory_metrics = Arc::new(TableMemoryMetrics::new(
763            hummock_version_reader.stats(),
764            option.table_id,
765            option.fragment_id,
766            option.is_replicated,
767        ));
768        Self {
769            mem_table: MemTable::new(option.table_id, option.op_consistency_level.clone()),
770            spill_offset: 0,
771            epoch: None,
772            table_id: option.table_id,
773            op_consistency_level: option.op_consistency_level,
774            table_option: option.table_option,
775            is_replicated: option.is_replicated,
776            instance_guard,
777            read_version,
778            event_sender,
779            memory_limiter,
780            hummock_version_reader,
781            table_memory_metrics,
782            write_limiter,
783            version_update_notifier_tx,
784            mem_table_spill_threshold,
785            upload_on_flush: option.upload_on_flush,
786        }
787    }
788
789    /// See `HummockReadVersion::update` for more details.
790    pub fn read_version(&self) -> HummockReadVersionRef {
791        self.read_version.clone()
792    }
793
794    pub fn table_id(&self) -> TableId {
795        self.instance_guard.table_id
796    }
797
798    pub fn instance_id(&self) -> u64 {
799        self.instance_guard.instance_id
800    }
801
802    fn is_flush_old_value(&self) -> bool {
803        matches!(
804            &self.op_consistency_level,
805            OpConsistencyLevel::ConsistentOldValue {
806                is_log_store: true,
807                ..
808            }
809        )
810    }
811}
812
813pub type StagingDataIterator = MergeIterator<
814    HummockIteratorUnion<Forward, SharedBufferBatchIterator<Forward>, SstableIterator>,
815>;
816pub type StagingDataRevIterator = MergeIterator<
817    HummockIteratorUnion<Backward, SharedBufferBatchIterator<Backward>, BackwardSstableIterator>,
818>;
819pub type HummockStorageIteratorPayloadInner<'a> = MergeIterator<
820    HummockIteratorUnion<
821        Forward,
822        StagingDataIterator,
823        SstableIterator,
824        ConcatIteratorInner<SstableIterator>,
825        MemTableHummockIterator<'a>,
826    >,
827>;
828
829pub type StorageRevIteratorPayloadInner<'a> = MergeIterator<
830    HummockIteratorUnion<
831        Backward,
832        StagingDataRevIterator,
833        BackwardSstableIterator,
834        ConcatIteratorInner<BackwardSstableIterator>,
835        MemTableHummockRevIterator<'a>,
836    >,
837>;
838
839pub type HummockStorageIterator = HummockStorageIteratorInner<'static>;
840pub type HummockStorageRevIterator = HummockStorageRevIteratorInner<'static>;
841pub type LocalHummockStorageIterator<'a> = HummockStorageIteratorInner<'a>;
842pub type LocalHummockStorageRevIterator<'a> = HummockStorageRevIteratorInner<'a>;
843
844pub struct HummockStorageIteratorInner<'a> {
845    inner: UserIterator<HummockStorageIteratorPayloadInner<'a>>,
846    initial_read: bool,
847    stats_guard: IterLocalMetricsGuard,
848}
849
850impl StateStoreIter for HummockStorageIteratorInner<'_> {
851    async fn try_next(&mut self) -> StorageResult<Option<StateStoreKeyedRowRef<'_>>> {
852        let iter = &mut self.inner;
853        if !self.initial_read {
854            self.initial_read = true;
855        } else {
856            iter.next().await?;
857        }
858
859        if iter.is_valid() {
860            Ok(Some((iter.key(), iter.value())))
861        } else {
862            Ok(None)
863        }
864    }
865}
866
867impl<'a> HummockStorageIteratorInner<'a> {
868    pub fn new(
869        inner: UserIterator<HummockStorageIteratorPayloadInner<'a>>,
870        metrics: Arc<HummockStateStoreMetrics>,
871        table_id: TableId,
872        mut local_stats: StoreLocalStatistic,
873    ) -> Self {
874        local_stats.found_key = inner.is_valid();
875        local_stats.sub_iter_count = local_stats.staging_imm_iter_count
876            + local_stats.staging_sst_iter_count
877            + local_stats.overlapping_iter_count
878            + local_stats.non_overlapping_iter_count;
879        Self {
880            inner,
881            initial_read: false,
882            stats_guard: IterLocalMetricsGuard::new(metrics, table_id, local_stats),
883        }
884    }
885}
886
887impl Drop for HummockStorageIteratorInner<'_> {
888    fn drop(&mut self) {
889        self.inner
890            .collect_local_statistic(&mut self.stats_guard.local_stats);
891    }
892}
893
894#[derive(Default)]
895pub struct ForwardIteratorFactory {
896    non_overlapping_iters: Vec<ConcatIteratorInner<SstableIterator>>,
897    overlapping_iters: Vec<SstableIterator>,
898    staging_iters:
899        Vec<HummockIteratorUnion<Forward, SharedBufferBatchIterator<Forward>, SstableIterator>>,
900}
901
902impl ForwardIteratorFactory {
903    pub fn build(
904        self,
905        mem_table: Option<MemTableHummockIterator<'_>>,
906    ) -> HummockStorageIteratorPayloadInner<'_> {
907        // 3. build user_iterator
908        let staging_iter = StagingDataIterator::new(self.staging_iters);
909        MergeIterator::new(
910            once(HummockIteratorUnion::First(staging_iter))
911                .chain(
912                    self.overlapping_iters
913                        .into_iter()
914                        .map(HummockIteratorUnion::Second),
915                )
916                .chain(
917                    self.non_overlapping_iters
918                        .into_iter()
919                        .map(HummockIteratorUnion::Third),
920                )
921                .chain(mem_table.into_iter().map(HummockIteratorUnion::Fourth)),
922        )
923    }
924}
925
926pub struct HummockStorageRevIteratorInner<'a> {
927    inner: BackwardUserIterator<StorageRevIteratorPayloadInner<'a>>,
928    initial_read: bool,
929    stats_guard: IterLocalMetricsGuard,
930}
931
932impl StateStoreIter for HummockStorageRevIteratorInner<'_> {
933    async fn try_next(&mut self) -> StorageResult<Option<StateStoreKeyedRowRef<'_>>> {
934        let iter = &mut self.inner;
935        if !self.initial_read {
936            self.initial_read = true;
937        } else {
938            iter.next().await?;
939        }
940
941        if iter.is_valid() {
942            Ok(Some((iter.key(), iter.value())))
943        } else {
944            Ok(None)
945        }
946    }
947}
948
949impl<'a> HummockStorageRevIteratorInner<'a> {
950    pub fn new(
951        inner: BackwardUserIterator<StorageRevIteratorPayloadInner<'a>>,
952        metrics: Arc<HummockStateStoreMetrics>,
953        table_id: TableId,
954        mut local_stats: StoreLocalStatistic,
955    ) -> Self {
956        local_stats.found_key = inner.is_valid();
957        local_stats.sub_iter_count = local_stats.staging_imm_iter_count
958            + local_stats.staging_sst_iter_count
959            + local_stats.overlapping_iter_count
960            + local_stats.non_overlapping_iter_count;
961        Self {
962            inner,
963            initial_read: false,
964            stats_guard: IterLocalMetricsGuard::new(metrics, table_id, local_stats),
965        }
966    }
967}
968
969impl Drop for HummockStorageRevIteratorInner<'_> {
970    fn drop(&mut self) {
971        self.inner
972            .collect_local_statistic(&mut self.stats_guard.local_stats);
973    }
974}
975
976impl IteratorFactory for ForwardIteratorFactory {
977    type Direction = Forward;
978    type SstableIteratorType = SstableIterator;
979
980    fn add_batch_iter(&mut self, batch: SharedBufferBatch) {
981        self.staging_iters
982            .push(HummockIteratorUnion::First(batch.into_forward_iter()));
983    }
984
985    fn add_staging_sst_iter(&mut self, iter: Self::SstableIteratorType) {
986        self.staging_iters.push(HummockIteratorUnion::Second(iter));
987    }
988
989    fn add_overlapping_sst_iter(&mut self, iter: Self::SstableIteratorType) {
990        self.overlapping_iters.push(iter);
991    }
992
993    fn add_concat_sst_iter(
994        &mut self,
995        tables: Vec<SstableInfo>,
996        sstable_store: SstableStoreRef,
997        read_options: Arc<SstableIteratorReadOptions>,
998    ) {
999        self.non_overlapping_iters
1000            .push(ConcatIteratorInner::<Self::SstableIteratorType>::new(
1001                tables,
1002                sstable_store,
1003                read_options,
1004            ));
1005    }
1006}
1007
1008#[derive(Default)]
1009pub struct BackwardIteratorFactory {
1010    non_overlapping_iters: Vec<ConcatIteratorInner<BackwardSstableIterator>>,
1011    overlapping_iters: Vec<BackwardSstableIterator>,
1012    staging_iters: Vec<
1013        HummockIteratorUnion<
1014            Backward,
1015            SharedBufferBatchIterator<Backward>,
1016            BackwardSstableIterator,
1017        >,
1018    >,
1019}
1020
1021impl BackwardIteratorFactory {
1022    pub fn build(
1023        self,
1024        mem_table: Option<MemTableHummockRevIterator<'_>>,
1025    ) -> StorageRevIteratorPayloadInner<'_> {
1026        // 3. build user_iterator
1027        let staging_iter = StagingDataRevIterator::new(self.staging_iters);
1028        MergeIterator::new(
1029            once(HummockIteratorUnion::First(staging_iter))
1030                .chain(
1031                    self.overlapping_iters
1032                        .into_iter()
1033                        .map(HummockIteratorUnion::Second),
1034                )
1035                .chain(
1036                    self.non_overlapping_iters
1037                        .into_iter()
1038                        .map(HummockIteratorUnion::Third),
1039                )
1040                .chain(mem_table.into_iter().map(HummockIteratorUnion::Fourth)),
1041        )
1042    }
1043}
1044
1045impl IteratorFactory for BackwardIteratorFactory {
1046    type Direction = Backward;
1047    type SstableIteratorType = BackwardSstableIterator;
1048
1049    fn add_batch_iter(&mut self, batch: SharedBufferBatch) {
1050        self.staging_iters
1051            .push(HummockIteratorUnion::First(batch.into_backward_iter()));
1052    }
1053
1054    fn add_staging_sst_iter(&mut self, iter: Self::SstableIteratorType) {
1055        self.staging_iters.push(HummockIteratorUnion::Second(iter));
1056    }
1057
1058    fn add_overlapping_sst_iter(&mut self, iter: Self::SstableIteratorType) {
1059        self.overlapping_iters.push(iter);
1060    }
1061
1062    fn add_concat_sst_iter(
1063        &mut self,
1064        mut tables: Vec<SstableInfo>,
1065        sstable_store: SstableStoreRef,
1066        read_options: Arc<SstableIteratorReadOptions>,
1067    ) {
1068        tables.reverse();
1069        self.non_overlapping_iters
1070            .push(ConcatIteratorInner::<Self::SstableIteratorType>::new(
1071                tables,
1072                sstable_store,
1073                read_options,
1074            ));
1075    }
1076}