Created
June 30, 2023 12:32
-
-
Save SaulDoesCode/bbee19533f5035fc3698b1d637a82618 to your computer and use it in GitHub Desktop.
an alias tree using redb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{collections::HashMap, sync::{Arc}}; | |
use rand::{thread_rng, distributions::Alphanumeric, Rng}; | |
use redb::{Database, MultimapTableDefinition, ReadableMultimapTable}; | |
lazy_static! { | |
static ref DB: Database = { | |
let db = Database::create("./alias_tree.db").expect("Failed to open database."); | |
db | |
}; | |
} | |
type Astr = Arc<str>; | |
const SV_MONIKER_TANGLE_LOOKUP: MultimapTableDefinition<&str, u64> = MultimapTableDefinition::new("name_lookup"); | |
const SV_MONIKER_TANGLE_LOOKUP_REVERSE: MultimapTableDefinition<u64, &str> = MultimapTableDefinition::new("name_lookup_reverse"); | |
struct AliasTree{ | |
root: Astr, | |
id: u64, | |
degree: usize, | |
nested: bool, | |
children: HashMap<Astr, AliasTree> | |
} | |
impl AliasTree{ | |
fn new(root: Astr, id: Option<u64>, degree: usize, nested: bool) -> anyhow::Result<AliasTree> { | |
let at = AliasTree{ | |
root, | |
id: match id { | |
Some(id) => id, | |
None => { | |
let mut rng = rand::thread_rng(); | |
let mut id = rng.gen(); | |
let rtx = DB.begin_read()?; | |
let t = rtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP_REVERSE)?; | |
let mut mmv = t.get(id)?; | |
while let Some(Ok(_)) = mmv.next() { | |
id = rng.gen(); | |
mmv = t.get(id)?; | |
} | |
id | |
} | |
}, | |
degree, | |
nested, | |
children: HashMap::new() | |
}; | |
at.save()?; | |
Ok(at) | |
} | |
fn aliases(&self) -> Vec<Astr>{ | |
let mut aliases = vec![]; | |
for (_, child) in self.children.iter() { | |
aliases.append(&mut child.aliases()); | |
} | |
aliases | |
} | |
fn save(&self) -> anyhow::Result<()> { | |
let wrtx = DB.begin_write()?; | |
{ | |
let mut t = wrtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP)?; | |
t.insert(self.root.as_ref(), self.id)?; | |
let mut t = wrtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP_REVERSE)?; | |
t.insert(self.id, self.root.as_ref())?; | |
} | |
wrtx.commit()?; | |
Ok(()) | |
} | |
fn get_id(moniker: &str) -> anyhow::Result<u64> { | |
let rtx = DB.begin_read()?; | |
let ft = rtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP)?; | |
let mut mmv = ft.get(moniker)?; | |
while let Some(Ok(ag)) = mmv.next() { | |
return Ok(ag.value()); | |
} | |
Err(anyhow!("No id found for moniker: {}", moniker)) | |
} | |
fn lookup_aliases(moniker: &str, id: Option<u64>, degrees: usize) -> anyhow::Result<Self> { | |
let rtx = DB.begin_read()?; | |
let ft = rtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP)?; | |
let mut mmv = ft.get(moniker)?; | |
let mut aliases = vec![]; | |
while let Some(Ok(ag)) = mmv.next() { | |
aliases.push(ag.value()); | |
} | |
let rt = rtx.open_multimap_table(SV_MONIKER_TANGLE_LOOKUP_REVERSE)?; | |
let mut alias_monikers: Astrs = vec![]; | |
for a in aliases.iter() { | |
let mut mmv = rt.get(*a)?; | |
while let Some(Ok(ag)) = mmv.next() { | |
alias_monikers.push(Arc::from(ag.value())); | |
} | |
} | |
if alias_monikers.len() == 0 { | |
Err(anyhow::anyhow!("moniker not found")) | |
} else { | |
if degrees != 0 { | |
let mut alias_results = vec![]; | |
for a in alias_monikers { | |
alias_results.push(Self::lookup_aliases( | |
a.as_ref(), | |
match Self::get_id(a.as_ref()) { | |
Ok(id) => Some(id), | |
Err(_) => None | |
}, | |
degrees - 1 | |
)?); | |
} | |
} | |
Self::new( | |
Arc::from(moniker), | |
match id { | |
Some(id) => Some(id), | |
None => Some(aliases[0]) | |
}, | |
degrees, | |
degrees != 0 | |
) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment