Skip to content

Instantly share code, notes, and snippets.

@SaulDoesCode
Created June 30, 2023 12:32
Show Gist options
  • Save SaulDoesCode/bbee19533f5035fc3698b1d637a82618 to your computer and use it in GitHub Desktop.
Save SaulDoesCode/bbee19533f5035fc3698b1d637a82618 to your computer and use it in GitHub Desktop.
an alias tree using redb
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