pict-rs/src/migrate/mod.rs

231 lines
5.5 KiB
Rust
Raw Normal View History

2020-07-11 20:40:40 +00:00
use crate::UploadError;
2020-09-14 21:42:31 +00:00
use sled;
2020-07-11 20:40:40 +00:00
use std::path::PathBuf;
use tracing::{debug, info, warn};
2020-09-14 21:42:31 +00:00
mod s032;
mod s034;
type SledIter = Box<dyn Iterator<Item = Result<(Vec<u8>, Vec<u8>), UploadError>>>;
trait SledDb {
type SledTree: SledTree;
fn open_tree(&self, name: &str) -> Result<Self::SledTree, UploadError>;
fn self_tree(&self) -> &Self::SledTree;
}
impl<T> SledDb for &T
where
T: SledDb,
{
type SledTree = T::SledTree;
fn open_tree(&self, name: &str) -> Result<Self::SledTree, UploadError> {
(*self).open_tree(name)
}
fn self_tree(&self) -> &Self::SledTree {
(*self).self_tree()
}
}
trait SledTree {
fn get<K>(&self, key: K) -> Result<Option<Vec<u8>>, UploadError>
where
K: AsRef<[u8]>;
fn insert<K, V>(&self, key: K, value: V) -> Result<(), UploadError>
where
K: AsRef<[u8]>,
V: AsRef<[u8]>;
fn iter(&self) -> SledIter;
fn range<K, R>(&self, range: R) -> SledIter
where
K: AsRef<[u8]>,
R: std::ops::RangeBounds<K>;
}
2020-07-11 20:40:40 +00:00
pub(crate) struct LatestDb {
root_dir: PathBuf,
version: DbVersion,
}
impl LatestDb {
pub(crate) fn exists(root_dir: PathBuf) -> Self {
let version = DbVersion::exists(root_dir.clone());
LatestDb { root_dir, version }
}
2020-09-14 21:42:31 +00:00
pub(crate) fn migrate(self) -> Result<sled::Db, UploadError> {
2020-07-11 20:40:40 +00:00
let LatestDb { root_dir, version } = self;
version.migrate(root_dir)
}
}
enum DbVersion {
Sled0320Rc1,
Sled032,
2020-09-10 16:12:42 +00:00
Sled034,
2020-07-11 20:40:40 +00:00
Fresh,
}
impl DbVersion {
fn exists(root: PathBuf) -> Self {
2020-09-14 21:42:31 +00:00
if s034::exists(root.clone()) {
2020-09-10 16:12:42 +00:00
return DbVersion::Sled034;
}
2020-09-14 21:42:31 +00:00
if s032::exists(root.clone()) {
2020-07-11 20:40:40 +00:00
return DbVersion::Sled032;
}
2020-09-14 21:42:31 +00:00
if s032::exists_rc1(root.clone()) {
2020-07-11 20:40:40 +00:00
return DbVersion::Sled0320Rc1;
}
DbVersion::Fresh
}
2020-09-14 21:42:31 +00:00
fn migrate(self, root: PathBuf) -> Result<sled::Db, UploadError> {
2020-07-11 20:40:40 +00:00
match self {
2020-09-14 21:42:31 +00:00
DbVersion::Sled0320Rc1 => migrate_0_32_0_rc1(root),
2020-09-10 16:12:42 +00:00
DbVersion::Sled032 => migrate_0_32(root),
2020-09-14 21:42:31 +00:00
DbVersion::Sled034 | DbVersion::Fresh => s034::open(root),
2020-07-11 20:40:40 +00:00
}
}
}
2020-09-14 21:42:31 +00:00
fn migrate_0_32_0_rc1(root: PathBuf) -> Result<sled::Db, UploadError> {
2020-10-11 00:38:07 +00:00
info!("Migrating database from 0.32.0-rc1 to 0.34.0");
2020-09-10 16:12:42 +00:00
2020-09-14 21:42:31 +00:00
let old_db = s032::open_rc1(root.clone())?;
let new_db = s034::open(root)?;
2020-09-10 16:12:42 +00:00
2020-09-14 21:42:31 +00:00
migrate(old_db, new_db)
2020-09-10 16:12:42 +00:00
}
2020-09-14 21:42:31 +00:00
fn migrate_0_32(root: PathBuf) -> Result<sled::Db, UploadError> {
info!("Migrating database from 0.32 to 0.34");
2020-07-11 20:40:40 +00:00
2020-09-14 21:42:31 +00:00
let old_db = s032::open(root.clone())?;
let new_db = s034::open(root)?;
2020-07-11 20:40:40 +00:00
2020-09-14 21:42:31 +00:00
migrate(old_db, new_db)
}
2020-07-11 20:40:40 +00:00
2020-09-14 21:42:31 +00:00
fn migrate<Old, New>(old_db: Old, new_db: New) -> Result<New, UploadError>
where
Old: SledDb,
New: SledDb,
{
2020-07-11 20:40:40 +00:00
let old_alias_tree = old_db.open_tree("alias")?;
let new_alias_tree = new_db.open_tree("alias")?;
let old_fname_tree = old_db.open_tree("filename")?;
let new_fname_tree = new_db.open_tree("filename")?;
2020-09-14 21:42:31 +00:00
for res in old_alias_tree.iter() {
let (k, _) = res?;
2020-07-11 20:40:40 +00:00
if let Some(v) = old_alias_tree.get(&k)? {
if !k.contains(&b"/"[0]) {
// k is an alias
migrate_main_tree(&k, &v, &old_db, &new_db)?;
debug!(
"Moving alias -> hash for alias {}",
String::from_utf8_lossy(k.as_ref()),
);
} else {
debug!(
"Moving {}, {}",
String::from_utf8_lossy(k.as_ref()),
String::from_utf8_lossy(v.as_ref())
);
}
new_alias_tree.insert(k, v)?;
} else {
warn!("MISSING {}", String::from_utf8_lossy(k.as_ref()));
}
}
2020-09-14 21:42:31 +00:00
for res in old_fname_tree.iter() {
let (k, _) = res?;
2020-07-11 20:40:40 +00:00
if let Some(v) = old_fname_tree.get(&k)? {
debug!(
"Moving file -> hash for file {}",
String::from_utf8_lossy(k.as_ref()),
);
new_fname_tree.insert(&k, &v)?;
} else {
warn!("MISSING {}", String::from_utf8_lossy(k.as_ref()));
}
}
2020-09-14 21:42:31 +00:00
Ok(new_db)
2020-07-11 20:40:40 +00:00
}
2020-09-14 21:42:31 +00:00
fn migrate_main_tree<Old, New>(
alias: &[u8],
hash: &[u8],
old_db: Old,
new_db: New,
) -> Result<(), UploadError>
where
Old: SledDb,
New: SledDb,
{
let main_tree = new_db.open_tree("main")?;
2020-07-11 20:40:40 +00:00
debug!(
"Migrating files for {}",
String::from_utf8_lossy(alias.as_ref())
);
2020-09-14 21:42:31 +00:00
if let Some(v) = old_db.self_tree().get(&hash)? {
main_tree.insert(&hash, v)?;
2020-07-11 20:40:40 +00:00
} else {
warn!("Missing filename");
}
let (start, end) = alias_key_bounds(&hash);
2020-09-14 21:42:31 +00:00
for res in old_db.self_tree().range(start..end) {
2020-07-11 20:40:40 +00:00
let (k, v) = res?;
debug!("Moving alias {}", String::from_utf8_lossy(v.as_ref()));
2020-09-14 21:42:31 +00:00
main_tree.insert(k, v)?;
2020-07-11 20:40:40 +00:00
}
let (start, end) = variant_key_bounds(&hash);
2020-09-14 21:42:31 +00:00
for res in old_db.self_tree().range(start..end) {
2020-07-11 20:40:40 +00:00
let (k, v) = res?;
debug!("Moving variant {}", String::from_utf8_lossy(v.as_ref()));
2020-09-14 21:42:31 +00:00
main_tree.insert(k, v)?;
2020-07-11 20:40:40 +00:00
}
Ok(())
}
pub(crate) fn alias_key_bounds(hash: &[u8]) -> (Vec<u8>, Vec<u8>) {
let mut start = hash.to_vec();
start.extend(&[0]);
let mut end = hash.to_vec();
end.extend(&[1]);
(start, end)
}
pub(crate) fn variant_key_bounds(hash: &[u8]) -> (Vec<u8>, Vec<u8>) {
let mut start = hash.to_vec();
start.extend(&[2]);
let mut end = hash.to_vec();
end.extend(&[3]);
(start, end)
}