Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 56f1369

Browse files
committedJul 23, 2024
Migrate trailing slash base URLs #895
1 parent b06a34d commit 56f1369

File tree

2 files changed

+86
-10
lines changed

2 files changed

+86
-10
lines changed
 

‎lib/src/db.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::{
1616
};
1717

1818
use mail_send::{Connected, Transport};
19+
use migrations::{REFERENCE_INDEX_CURRENT, RESOURCE_TREE_CURRENT};
1920
use tracing::{info, instrument};
2021

2122
use crate::{
@@ -100,8 +101,8 @@ impl Db {
100101
/// It is used for distinguishing locally defined items from externally defined ones.
101102
pub fn init(path: &std::path::Path, server_url: &str) -> AtomicResult<Db> {
102103
let db = sled::open(path).map_err(|e|format!("Failed opening DB at this location: {:?} . Is another instance of Atomic Server running? {}", path, e))?;
103-
let resources = db.open_tree("resources_v1").map_err(|e|format!("Failed building resources. Your DB might be corrupt. Go back to a previous version and export your data. {}", e))?;
104-
let reference_index = db.open_tree("reference_index_v1")?;
104+
let resources = db.open_tree(RESOURCE_TREE_CURRENT).map_err(|e|format!("Failed building resources. Your DB might be corrupt. Go back to a previous version and export your data. {}", e))?;
105+
let reference_index = db.open_tree(REFERENCE_INDEX_CURRENT)?;
105106
let query_index = db.open_tree("members_index")?;
106107
let prop_val_sub_index = db.open_tree("prop_val_sub_index")?;
107108
let watched_queries = db.open_tree("watched_queries")?;

‎lib/src/db/migrations.rs

+83-8
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,42 @@ Therefore, we need migrations to convert the old schema to the new one.
1212
- Update the Tree key used in [Db::init]
1313
*/
1414

15-
use crate::{errors::AtomicResult, Db, Storelike};
15+
use crate::{errors::AtomicResult, resources::PropVals, Db, Storelike};
16+
17+
const RESOURCE_TREE_V0: &str = "resources";
18+
const RESOURCE_TREE_V1: &str = "resources_v1";
19+
const RESOURCE_TREE_V2: &str = "resources_v2";
20+
pub const RESOURCE_TREE_CURRENT: &str = RESOURCE_TREE_V2;
21+
22+
const REFERENCE_INDEX_V0: &str = "reference_index";
23+
const REFERENCE_INDEX_V1: &str = "reference_index_v1";
24+
pub const REFERENCE_INDEX_CURRENT: &str = REFERENCE_INDEX_V1;
1625

1726
/// Checks the current version(s) of the internal Store, and performs migrations if needed.
1827
pub fn migrate_maybe(store: &Db) -> AtomicResult<()> {
1928
for tree in store.db.tree_names() {
2029
match String::from_utf8_lossy(&tree).as_ref() {
2130
// Add migrations for outdated Trees to this list
22-
"resources" => v0_to_v1(store)?,
23-
"reference_index" => ref_v0_to_v1(store)?,
31+
RESOURCE_TREE_V0 => res_v0_to_v1(store)?,
32+
RESOURCE_TREE_V1 => res_v1_to_v2(store)?,
33+
REFERENCE_INDEX_V0 => ref_v0_to_v1(store)?,
2434
_other => {}
2535
}
2636
}
2737
Ok(())
2838
}
2939

3040
/// Change the subjects from `bincode` to `.as_bytes()`
31-
fn v0_to_v1(store: &Db) -> AtomicResult<()> {
41+
fn res_v0_to_v1(store: &Db) -> AtomicResult<()> {
3242
tracing::warn!("Migrating resources schema from v0 to v1...");
33-
let new = store.db.open_tree("resources_v1")?;
34-
let old_key = "resources";
43+
let new = store.db.open_tree(RESOURCE_TREE_V1)?;
44+
let old_key = RESOURCE_TREE_V0;
3545
let old = store.db.open_tree(old_key)?;
3646
let mut count = 0;
3747

3848
for item in old.into_iter() {
3949
let (subject, resource_bin) = item.expect("Unable to convert into iterable");
40-
let subject: String =
41-
bincode::deserialize(&subject).expect("Unable to deserialize subject");
50+
let subject: String = String::from_utf8_lossy(&subject).to_string();
4251
new.insert(subject.as_bytes(), resource_bin)?;
4352
count += 1;
4453
}
@@ -73,6 +82,72 @@ fn v0_to_v1(store: &Db) -> AtomicResult<()> {
7382
Ok(())
7483
}
7584

85+
/// add a trailing slash to all "home" subjects
86+
fn res_v1_to_v2(store: &Db) -> AtomicResult<()> {
87+
tracing::warn!("Migrating resources schema from v1 to v2...");
88+
let new = store.db.open_tree(RESOURCE_TREE_V2)?;
89+
let old_key = RESOURCE_TREE_V1;
90+
let old = store.db.open_tree(old_key)?;
91+
let mut count = 0;
92+
93+
fn migrate_subject(subject: &str) -> String {
94+
let url = url::Url::parse(subject).expect("Unable to parse subject URL");
95+
if subject != url.to_string() {
96+
println!("Migrating: {} -> {}", subject, url.to_string())
97+
};
98+
url.to_string()
99+
}
100+
101+
for item in old.into_iter() {
102+
let (subject, resource_bin) = item.expect("Unable to convert into iterable");
103+
let subject: String = String::from_utf8_lossy(&subject).to_string();
104+
105+
let mut propvals: PropVals = bincode::deserialize(&resource_bin)?;
106+
107+
for (_prop, val) in propvals.iter_mut() {
108+
match val {
109+
crate::Value::AtomicUrl(a) => {
110+
*a = migrate_subject(a);
111+
}
112+
crate::Value::ResourceArray(arr) => {
113+
for url in arr.iter_mut() {
114+
match url {
115+
crate::values::SubResource::Subject(s) => {
116+
*s = migrate_subject(s);
117+
}
118+
// This skips nested resources
119+
_other => {}
120+
}
121+
}
122+
}
123+
// This skips nested resources
124+
_other => {}
125+
};
126+
}
127+
new.insert(migrate_subject(&subject), bincode::serialize(&propvals)?)?;
128+
count += 1;
129+
}
130+
131+
assert_eq!(
132+
new.len(),
133+
store.resources.len(),
134+
"Not all resources were migrated."
135+
);
136+
137+
assert!(
138+
store.db.drop_tree(old_key)?,
139+
"Old resources tree not properly removed."
140+
);
141+
142+
tracing::warn!("Rebuilding indexes due to migrating to new version...");
143+
store.db.drop_tree(old_key)?;
144+
store.build_index(true)?;
145+
tracing::warn!("Rebuilding index finished!");
146+
147+
tracing::warn!("Finished migration of {} resources", count);
148+
Ok(())
149+
}
150+
76151
/// Add `prop_val_sub` index
77152
fn ref_v0_to_v1(store: &Db) -> AtomicResult<()> {
78153
tracing::warn!("Rebuilding indexes due to migrating to new version...");

0 commit comments

Comments
 (0)
Please sign in to comment.