referrerpolicy=no-referrer-when-downgrade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

//! A `RocksDB` instance for storing parachain data; availability data, and approvals.

#[cfg(feature = "full-node")]
use {
	polkadot_node_subsystem_util::database::Database, std::io, std::path::PathBuf, std::sync::Arc,
};

#[cfg(feature = "full-node")]
mod upgrade;

const LOG_TARGET: &str = "parachain::db";

/// Column configuration per version.
#[cfg(any(test, feature = "full-node"))]
pub(crate) mod columns {
	pub mod v0 {
		pub const NUM_COLUMNS: u32 = 3;
	}

	pub mod v1 {
		pub const NUM_COLUMNS: u32 = 5;
	}

	pub mod v2 {
		pub const NUM_COLUMNS: u32 = 6;

		#[cfg(test)]
		pub const COL_SESSION_WINDOW_DATA: u32 = 5;
	}

	// Version 4 only changed structures in approval voting, so we can re-export the v4 definitions.
	pub mod v3 {
		pub use super::v4::{NUM_COLUMNS, ORDERED_COL};
	}

	pub mod v4 {
		pub const NUM_COLUMNS: u32 = 5;
		pub const COL_AVAILABILITY_DATA: u32 = 0;
		pub const COL_AVAILABILITY_META: u32 = 1;
		pub const COL_APPROVAL_DATA: u32 = 2;
		pub const COL_CHAIN_SELECTION_DATA: u32 = 3;
		pub const COL_DISPUTE_COORDINATOR_DATA: u32 = 4;

		pub const ORDERED_COL: &[u32] =
			&[COL_AVAILABILITY_META, COL_CHAIN_SELECTION_DATA, COL_DISPUTE_COORDINATOR_DATA];
	}
}

/// Columns used by different subsystems.
#[cfg(any(test, feature = "full-node"))]
#[derive(Debug, Clone)]
pub struct ColumnsConfig {
	/// The column used by the av-store for data.
	pub col_availability_data: u32,
	/// The column used by the av-store for meta information.
	pub col_availability_meta: u32,
	/// The column used by approval voting for data.
	pub col_approval_data: u32,
	/// The column used by chain selection for data.
	pub col_chain_selection_data: u32,
	/// The column used by dispute coordinator for data.
	pub col_dispute_coordinator_data: u32,
}

/// The real columns used by the parachains DB.
#[cfg(any(test, feature = "full-node"))]
pub const REAL_COLUMNS: ColumnsConfig = ColumnsConfig {
	col_availability_data: columns::v4::COL_AVAILABILITY_DATA,
	col_availability_meta: columns::v4::COL_AVAILABILITY_META,
	col_approval_data: columns::v4::COL_APPROVAL_DATA,
	col_chain_selection_data: columns::v4::COL_CHAIN_SELECTION_DATA,
	col_dispute_coordinator_data: columns::v4::COL_DISPUTE_COORDINATOR_DATA,
};

#[derive(PartialEq, Copy, Clone)]
pub(crate) enum DatabaseKind {
	ParityDB,
	RocksDB,
}

/// The cache size for each column, in megabytes.
#[derive(Debug, Clone)]
pub struct CacheSizes {
	/// Cache used by availability data.
	pub availability_data: usize,
	/// Cache used by availability meta.
	pub availability_meta: usize,
	/// Cache used by approval data.
	pub approval_data: usize,
}

impl Default for CacheSizes {
	fn default() -> Self {
		CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 }
	}
}

#[cfg(feature = "full-node")]
pub(crate) fn other_io_error(err: String) -> io::Error {
	io::Error::new(io::ErrorKind::Other, err)
}

/// Open the database on disk, creating it if it doesn't exist.
#[cfg(feature = "full-node")]
pub fn open_creating_rocksdb(
	root: PathBuf,
	cache_sizes: CacheSizes,
) -> io::Result<Arc<dyn Database>> {
	use kvdb_rocksdb::{Database, DatabaseConfig};

	let path = root.join("parachains").join("db");

	let mut db_config = DatabaseConfig::with_columns(columns::v4::NUM_COLUMNS);

	let _ = db_config
		.memory_budget
		.insert(columns::v4::COL_AVAILABILITY_DATA, cache_sizes.availability_data);
	let _ = db_config
		.memory_budget
		.insert(columns::v4::COL_AVAILABILITY_META, cache_sizes.availability_meta);
	let _ = db_config
		.memory_budget
		.insert(columns::v4::COL_APPROVAL_DATA, cache_sizes.approval_data);

	let path_str = path
		.to_str()
		.ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?;

	std::fs::create_dir_all(&path_str)?;
	upgrade::try_upgrade_db(&path, DatabaseKind::RocksDB, upgrade::CURRENT_VERSION)?;
	let db = Database::open(&db_config, &path_str)?;
	let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(
		db,
		columns::v4::ORDERED_COL,
	);

	Ok(Arc::new(db))
}

/// Open a parity db database.
#[cfg(feature = "full-node")]
pub fn open_creating_paritydb(
	root: PathBuf,
	_cache_sizes: CacheSizes,
) -> io::Result<Arc<dyn Database>> {
	let path = root.join("parachains");
	let path_str = path
		.to_str()
		.ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?;

	std::fs::create_dir_all(&path_str)?;
	upgrade::try_upgrade_db(&path, DatabaseKind::ParityDB, upgrade::CURRENT_VERSION)?;

	let db = parity_db::Db::open_or_create(&upgrade::paritydb_version_3_config(&path))
		.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;

	let db = polkadot_node_subsystem_util::database::paritydb_impl::DbAdapter::new(
		db,
		columns::v4::ORDERED_COL,
	);
	Ok(Arc::new(db))
}