Skip to main content

forest/db/
db_impl.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::{
5    car::ManyCar,
6    parity_db::{GarbageCollectableDb, GarbageCollectableParityDb, ParityDb},
7    *,
8};
9use crate::{
10    db::car::ReloadableManyCar, libp2p_bitswap::*, prelude::*,
11    tool::subcommands::api_cmd::generate_test_snapshot::ReadOpsTrackingStore,
12};
13use ambassador::Delegate;
14use spire_enum::prelude::delegated_enum;
15use std::path::PathBuf;
16
17#[derive(Delegate)]
18#[delegate(SettingsStore)]
19#[delegate(EthMappingsStore)]
20#[delegate(EthBlockBloomStore)]
21#[delegate(HeaviestTipsetKeyProvider)]
22#[delegate(BitswapStoreRead)]
23#[delegate(BitswapStoreReadWrite)]
24#[delegated_enum(impl_conversions)]
25pub enum DbImpl {
26    ManyCarWithGarbageCollectableParityDb(Arc<ManyCar<Arc<GarbageCollectableParityDb>>>),
27    ManyCarWithMemoryDB(Arc<ManyCar<MemoryDB>>),
28    ManyCarParityDb(Arc<ManyCar<ParityDb>>),
29    Memory(Arc<MemoryDB>),
30    ReadOpsTrackingManyCarParityDb(Arc<ReadOpsTrackingStore<ManyCar<ParityDb>>>),
31}
32
33impl ShallowClone for DbImpl {
34    fn shallow_clone(&self) -> Self {
35        delegate_db_impl!(self.shallow_clone().into())
36    }
37}
38
39impl Blockstore for DbImpl {
40    fn get(&self, k: &Cid) -> anyhow::Result<Option<Vec<u8>>> {
41        delegate_db_impl!(self => |i| Blockstore::get(i, k))
42    }
43
44    fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> {
45        delegate_db_impl!(self => |i| Blockstore::put_keyed(i, k, block))
46    }
47
48    fn has(&self, k: &Cid) -> anyhow::Result<bool> {
49        delegate_db_impl!(self => |i| Blockstore::has(i, k))
50    }
51
52    #[allow(clippy::disallowed_types)]
53    fn put<D>(
54        &self,
55        mh_code: multihash_codetable::Code,
56        block: &fvm_ipld_blockstore::Block<D>,
57    ) -> anyhow::Result<Cid>
58    where
59        Self: Sized,
60        D: AsRef<[u8]>,
61    {
62        delegate_db_impl!(self => |i| Blockstore::put(i, mh_code, block))
63    }
64
65    #[allow(clippy::disallowed_types)]
66    fn put_many<D, I>(&self, blocks: I) -> anyhow::Result<()>
67    where
68        Self: Sized,
69        D: AsRef<[u8]>,
70        I: IntoIterator<Item = (multihash_codetable::Code, fvm_ipld_blockstore::Block<D>)>,
71    {
72        delegate_db_impl!(self => |i| Blockstore::put_many(i, blocks))
73    }
74
75    fn put_many_keyed<D, I>(&self, blocks: I) -> anyhow::Result<()>
76    where
77        Self: Sized,
78        D: AsRef<[u8]>,
79        I: IntoIterator<Item = (Cid, D)>,
80    {
81        delegate_db_impl!(self => |i| Blockstore::put_many_keyed(i, blocks))
82    }
83}
84
85impl GarbageCollectableDb for DbImpl {
86    fn reset_gc_columns(&self) -> anyhow::Result<()> {
87        match self {
88            Self::ManyCarWithGarbageCollectableParityDb(db) => db.reset_gc_columns(),
89            _ => anyhow::bail!("db is not garbage collectable"),
90        }
91    }
92}
93
94impl BlockstoreWriteOpsSubscribable for DbImpl {
95    fn subscribe_write_ops(
96        &self,
97    ) -> anyhow::Result<tokio::sync::broadcast::Receiver<Vec<(Cid, bytes::Bytes)>>> {
98        if let Self::ManyCarWithGarbageCollectableParityDb(db) = self {
99            db.subscribe_write_ops()
100        } else {
101            anyhow::bail!("not supported")
102        }
103    }
104
105    fn unsubscribe_write_ops(&self) {
106        if let Self::ManyCarWithGarbageCollectableParityDb(db) = self {
107            db.unsubscribe_write_ops();
108        }
109    }
110}
111
112impl ReloadableManyCar for DbImpl {
113    fn clear_and_reload_cars(&self, files: impl Iterator<Item = PathBuf>) -> anyhow::Result<()> {
114        match self {
115            Self::ManyCarWithGarbageCollectableParityDb(db) => db.clear_and_reload_cars(files),
116            Self::ManyCarWithMemoryDB(db) => db.clear_and_reload_cars(files),
117            Self::ManyCarParityDb(db) => db.clear_and_reload_cars(files),
118            _ => anyhow::bail!("not supported"),
119        }
120    }
121
122    fn heaviest_car_tipset(&self) -> anyhow::Result<Tipset> {
123        match self {
124            Self::ManyCarWithGarbageCollectableParityDb(db) => db.heaviest_car_tipset(),
125            Self::ManyCarWithMemoryDB(db) => db.heaviest_car_tipset(),
126            Self::ManyCarParityDb(db) => db.heaviest_car_tipset(),
127            _ => anyhow::bail!("not supported"),
128        }
129    }
130}