cfx_storage/storage_db/
delta_db_manager.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5// The trait for database manager of Delta MPT.
6
7pub type DeltaDbOwnedReadTraitObj<'db> =
8    dyn 'db + KeyValueDbTraitOwnedRead<ValueType = Box<[u8]>>;
9
10pub type DeltaDbTransactionTraitObj =
11    dyn KeyValueDbTransactionTrait<ValueType = Box<[u8]>>;
12
13pub trait DeltaDbTrait:
14    KeyValueDbTypes<ValueType = Box<[u8]>>
15    + KeyValueDbToOwnedReadTrait
16    + KeyValueDbTraitRead
17    + KeyValueDbTraitTransactionalDyn
18    + MallocSizeOf
19    + Send
20    + Sync
21{
22}
23
24pub trait DeltaDbManagerTrait {
25    type DeltaDb: DeltaDbTrait;
26
27    fn get_delta_db_dir(&self) -> &Path;
28    fn get_delta_db_name(&self, snapshot_epoch_id: &EpochId) -> String;
29    fn get_delta_db_path(&self, delta_db_name: &str) -> PathBuf;
30
31    // Scan delta db dir, remove extra files and return the list of missing
32    // snapshots for which the delta db is missing.
33    fn scan_persist_state(
34        &self, snapshot_info_map: &HashMap<EpochId, SnapshotInfo>,
35    ) -> Result<(Vec<EpochId>, HashMap<EpochId, Self::DeltaDb>)> {
36        let mut possible_delta_db_paths = HashMap::new();
37        for (snapshot_epoch_id, snapshot_info) in snapshot_info_map {
38            // Delta MPT
39            possible_delta_db_paths.insert(
40                self.get_delta_db_name(snapshot_epoch_id).into_bytes(),
41                snapshot_epoch_id.clone(),
42            );
43            // Intermediate Delta MPT
44            possible_delta_db_paths.insert(
45                self.get_delta_db_name(&snapshot_info.parent_snapshot_epoch_id)
46                    .into_bytes(),
47                snapshot_info.parent_snapshot_epoch_id.clone(),
48            );
49        }
50        let mut delta_mpts = HashMap::new();
51
52        // Scan the delta db dir. Remove extra files, and return the list of
53        // snapshots for which the delta db is missing.
54        for entry in fs::read_dir(self.get_delta_db_dir())? {
55            let entry = entry?;
56            let path = entry.path();
57            let dir_name = path.as_path().file_name().unwrap().to_str();
58            if dir_name.is_none() {
59                error!(
60                    "Unexpected delta db path {}, deleted.",
61                    entry.path().display()
62                );
63                fs::remove_dir_all(entry.path())?;
64                continue;
65            }
66            let dir_name = dir_name.unwrap();
67            if !possible_delta_db_paths.contains_key(dir_name.as_bytes()) {
68                error!(
69                    "Unexpected delta db path {}, deleted.",
70                    entry.path().display()
71                );
72                fs::remove_dir_all(entry.path())?;
73            } else {
74                let snapshot_epoch_id = possible_delta_db_paths
75                    .remove(dir_name.as_bytes())
76                    .unwrap();
77                delta_mpts.insert(
78                    snapshot_epoch_id,
79                    self.get_delta_db(
80                        &self.get_delta_db_name(&snapshot_epoch_id),
81                    )?
82                    .unwrap(),
83                );
84            }
85        }
86
87        let mut missing_delta_dbs = vec![];
88        for (snapshot_epoch_id, snapshot_info) in snapshot_info_map {
89            // Skip if the snapshot doesn't exist.
90            if snapshot_info.snapshot_info_kept_to_provide_sync
91                == SnapshotKeptToProvideSyncStatus::No
92            {
93                if !delta_mpts.contains_key(snapshot_epoch_id) {
94                    missing_delta_dbs.push(snapshot_epoch_id.clone())
95                }
96            }
97        }
98
99        Ok((missing_delta_dbs, delta_mpts))
100    }
101
102    fn new_empty_delta_db(&self, delta_db_name: &str) -> Result<Self::DeltaDb>;
103
104    fn get_delta_db(
105        &self, delta_db_name: &str,
106    ) -> Result<Option<Self::DeltaDb>>;
107
108    /// Destroy a Delta DB. Keep in mind that this method is irrecoverable.
109    /// Ref-counting is necessary for Delta1 MPT in Snapshot.
110    fn destroy_delta_db(&self, delta_db_name: &str) -> Result<()>;
111}
112
113use crate::{
114    impls::errors::*,
115    storage_db::{
116        key_value_db::*, SnapshotInfo, SnapshotKeptToProvideSyncStatus,
117    },
118};
119use malloc_size_of::MallocSizeOf;
120use primitives::EpochId;
121use std::{
122    collections::HashMap,
123    fs,
124    path::{Path, PathBuf},
125};