Skip to content

Commit 2a5f0f5

Browse files
committed
Migrate trailing slash base URLs #895
1 parent 87c85b3 commit 2a5f0f5

File tree

2 files changed

+83
-9
lines changed

2 files changed

+83
-9
lines changed

lib/src/db.rs

-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ impl Db {
114114
default_agent: Arc::new(std::sync::Mutex::new(None)),
115115
resources,
116116
reference_index,
117-
on_commit: None,
118117
query_index,
119118
prop_val_sub_index,
120119
server_url: AtomicUrl::try_from(server_url)?,

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 [crate::db::trees]
1313
*/
1414

15-
use crate::{errors::AtomicResult, Db};
15+
use crate::{errors::AtomicResult, resources::PropVals, Db};
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)