Skip to main content

risingwave_storage/hummock/
block_cache.rs

1// Copyright 2022 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::ops::Deref;
16use std::sync::Arc;
17
18use await_tree::{InstrumentAwait, SpanExt};
19use foyer::{HybridCacheEntry, HybridGetOrFetch};
20use risingwave_common::config::EvictionConfig;
21
22use super::{Block, HummockResult, SstableBlockIndex};
23use crate::hummock::HummockError;
24
25type HybridCachedBlockEntry = HybridCacheEntry<SstableBlockIndex, Box<Block>>;
26
27pub enum BlockEntry {
28    HybridCache(HybridCachedBlockEntry),
29    Owned(Box<Block>),
30    RefEntry(Arc<Block>),
31}
32
33pub struct BlockHolder {
34    _handle: BlockEntry,
35    // Keep private so safe callers cannot invalidate the pointer used by Deref.
36    block: *const Block,
37}
38
39impl BlockHolder {
40    pub fn from_ref_block(block: Arc<Block>) -> Self {
41        let ptr = block.as_ref() as *const _;
42        Self {
43            _handle: BlockEntry::RefEntry(block),
44            block: ptr,
45        }
46    }
47
48    pub fn from_owned_block(block: Box<Block>) -> Self {
49        let ptr = block.as_ref() as *const _;
50        Self {
51            _handle: BlockEntry::Owned(block),
52            block: ptr,
53        }
54    }
55
56    pub fn from_hybrid_cache_entry(entry: HybridCachedBlockEntry) -> Self {
57        let ptr = entry.value().as_ref() as *const _;
58        Self {
59            _handle: BlockEntry::HybridCache(entry),
60            block: ptr,
61        }
62    }
63
64    pub fn entry(&self) -> &BlockEntry {
65        &self._handle
66    }
67}
68
69impl Deref for BlockHolder {
70    type Target = Block;
71
72    fn deref(&self) -> &Self::Target {
73        // SAFETY: Each constructor points into the heap allocation kept alive by _handle.
74        // Moving the holder does not move the Block, and both fields remain unchanged.
75        unsafe { &(*self.block) }
76    }
77}
78
79unsafe impl Send for BlockHolder {}
80unsafe impl Sync for BlockHolder {}
81
82#[derive(Debug)]
83pub struct BlockCacheConfig {
84    pub capacity: usize,
85    pub shard_num: usize,
86    pub eviction: EvictionConfig,
87}
88
89pub enum BlockResponse {
90    Block(BlockHolder),
91    Fetch(HybridGetOrFetch<SstableBlockIndex, Box<Block>>),
92}
93
94impl BlockResponse {
95    pub async fn wait(self) -> HummockResult<BlockHolder> {
96        let fetch = match self {
97            BlockResponse::Block(block) => return Ok(block),
98            BlockResponse::Fetch(fetch) => fetch,
99        };
100        let fetch = match fetch.try_unwrap() {
101            Ok(entry) => return Ok(BlockHolder::from_hybrid_cache_entry(entry)),
102            Err(fetch) => fetch,
103        };
104        fetch
105            .instrument_await("wait_pending_fetch_block".verbose())
106            .await
107            .map(BlockHolder::from_hybrid_cache_entry)
108            .map_err(HummockError::foyer_error)
109    }
110}