- adds build metadata when writing db version file, if any.

- adds the build metadata to the db version file before adding indexes.
- deletes indexes when running without the `indexer` feature
This commit is contained in:
Arya 2024-10-24 21:04:18 -04:00
parent 661316cf5b
commit e6a8654c44
5 changed files with 121 additions and 2 deletions

View File

@ -500,7 +500,11 @@ pub(crate) mod hidden {
) -> Result<(), BoxError> {
let version_path = config.version_file_path(db_kind, changed_version.major, network);
let version = format!("{}.{}", changed_version.minor, changed_version.patch);
let mut version = format!("{}.{}", changed_version.minor, changed_version.patch);
if !changed_version.build.is_empty() {
version.push_str(&format!("+{}", changed_version.build));
}
// Write the version file atomically so the cache is not corrupted if Zebra shuts down or
// crashes.

View File

@ -32,6 +32,9 @@ use crate::{
Config,
};
#[cfg(not(feature = "indexer"))]
use crate::constants::STATE_DATABASE_KIND;
// Doc-only imports
#[allow(unused_imports)]
use super::{TypedColumnFamily, WriteTypedBatch};
@ -863,6 +866,18 @@ impl DiskDb {
DB::open_cf_descriptors(&db_options, &path, column_families)
};
#[cfg(not(feature = "indexer"))]
let db_result = match db_result {
Ok(mut db) if db_kind == STATE_DATABASE_KIND => {
if let Err(err) = db.drop_cf(super::zebra_db::transparent::TX_LOC_BY_SPENT_OUT_LOC)
{
warn!(?err, "failed to drop unused column family");
}
Ok(db)
}
other => other,
};
match db_result {
Ok(db) => {
info!("Opened Zebra state cache at {}", path.display());

View File

@ -29,6 +29,9 @@ pub(crate) mod add_subtrees;
pub(crate) mod cache_genesis_roots;
pub(crate) mod fix_tree_key_type;
#[cfg(not(feature = "indexer"))]
pub(crate) mod drop_tx_locs_by_spends;
#[cfg(feature = "indexer")]
pub(crate) mod track_tx_locs_by_spends;
@ -350,6 +353,16 @@ impl DbFormatChange {
// Indexing transaction locations by their spent outpoints and revealed nullifiers.
let timer = CodeTimer::start();
// Add build metadata to on-disk version file just before starting to add indexes
let mut version = db
.format_version_on_disk()
.expect("unable to read database format version file")
.expect("should write database format version file above");
version.build = db.format_version_in_code().build;
db.update_format_version_on_disk(&version)
.expect("unable to write database format version file to disk");
info!("started checking/adding indexes for spending tx ids");
track_tx_locs_by_spends::run(initial_tip_height, db, cancel_receiver)?;
info!("finished checking/adding indexes for spending tx ids");
@ -357,6 +370,34 @@ impl DbFormatChange {
timer.finish(module_path!(), line!(), "indexing spending transaction ids");
};
#[cfg(not(feature = "indexer"))]
if let (
Upgrade { .. } | CheckOpenCurrent { .. } | Downgrade { .. },
Some(initial_tip_height),
) = (self, initial_tip_height)
{
let mut version = db
.format_version_on_disk()
.expect("unable to read database format version file")
.expect("should write database format version file above");
if version.build.contains("indexer") {
// Indexing transaction locations by their spent outpoints and revealed nullifiers.
let timer = CodeTimer::start();
info!("started removing indexes for spending tx ids");
drop_tx_locs_by_spends::run(initial_tip_height, db, cancel_receiver)?;
info!("finished removing indexes for spending tx ids");
// Remove build metadata to on-disk version file after indexes have been dropped.
version.build = db.format_version_in_code().build;
db.update_format_version_on_disk(&version)
.expect("unable to write database format version file to disk");
timer.finish(module_path!(), line!(), "removing spending transaction ids");
}
};
// These checks should pass for all format changes:
// - upgrades should produce a valid format (and they already do that check)
// - an empty state should pass all the format checks

View File

@ -0,0 +1,59 @@
//! Tracks transaction locations by their inputs and revealed nullifiers.
use crossbeam_channel::{Receiver, TryRecvError};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use zebra_chain::block::Height;
use crate::service::finalized_state::ZebraDb;
use super::{super::super::DiskWriteBatch, CancelFormatChange};
/// Runs disk format upgrade for tracking transaction locations by their inputs and revealed nullifiers.
///
/// Returns `Ok` if the upgrade completed, and `Err` if it was cancelled.
#[allow(clippy::unwrap_in_result)]
#[instrument(skip(zebra_db, cancel_receiver))]
pub fn run(
initial_tip_height: Height,
zebra_db: &ZebraDb,
cancel_receiver: &Receiver<CancelFormatChange>,
) -> Result<(), CancelFormatChange> {
if !matches!(cancel_receiver.try_recv(), Err(TryRecvError::Empty)) {
return Err(CancelFormatChange);
}
// The `TX_LOC_BY_SPENT_OUT_LOC` column family should be dropped
// when opening the database without the `indexer` feature.
(0..=initial_tip_height.0)
.into_par_iter()
.try_for_each(|height| {
let height = Height(height);
let mut batch = DiskWriteBatch::new();
for (_tx_loc, tx) in zebra_db.transactions_by_height(height) {
if tx.is_coinbase() {
continue;
}
batch
.prepare_nullifier_batch(zebra_db, &tx)
.expect("method should never return an error");
}
if !matches!(cancel_receiver.try_recv(), Err(TryRecvError::Empty)) {
return Err(CancelFormatChange);
}
zebra_db
.write_batch(batch)
.expect("unexpected database write failure");
if !matches!(cancel_receiver.try_recv(), Err(TryRecvError::Empty)) {
return Err(CancelFormatChange);
}
Ok(())
})
}

View File

@ -84,7 +84,7 @@ pub fn run(
batch
.prepare_nullifier_batch(zebra_db, &tx, tx_loc)
.expect("should not return an error");
.expect("method should never return an error");
}
if !matches!(cancel_receiver.try_recv(), Err(TryRecvError::Empty)) {