node: sync project routing for known nodes

Keep the node's understanding of project hosting location current by
updating how Inventory Announcement messages are processed.

The Inventory Announcements contain a node's entire listing of projects.
Replace the routing table information for the announcer with those from the
message.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2022-11-03 13:49:59 -05:00
parent 186eb42145
commit a74cb416c1
2 changed files with 44 additions and 3 deletions

View File

@ -6,7 +6,7 @@ pub mod routing;
pub mod session;
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::{fmt, net, net::IpAddr, str};
@ -876,17 +876,23 @@ where
/// Process a peer inventory announcement by updating our routing table.
fn process_inventory(
&mut self,
inventory: &Inventory,
inventory: &Vec<Id>,
from: NodeId,
timestamp: &Timestamp,
) -> Result<(), Error> {
let mut included = HashSet::new();
for proj_id in inventory {
// TODO: Fire an event on routing update.
included.insert(proj_id);
if self.routing.insert(*proj_id, from, *timestamp)? && self.config.is_tracking(proj_id)
{
log::info!("Routing table updated for {} with seed {}", proj_id, from);
}
}
for id in self.routing.get_resources(&from)?.into_iter() {
if !included.contains(&id) {
self.routing.remove(&id, &from)?;
}
}
Ok(())
}

View File

@ -57,6 +57,8 @@ impl Table {
pub trait Store {
/// Get the nodes seeding the given id.
fn get(&self, id: &Id) -> Result<HashSet<NodeId>, Error>;
/// Get the resources seeded by the given node.
fn get_resources(&self, node_id: &NodeId) -> Result<HashSet<Id>, Error>;
/// Get a specific entry.
fn entry(&self, id: &Id, node: &NodeId) -> Result<Option<Timestamp>, Error>;
/// Add a new node seeding the given id.
@ -83,6 +85,19 @@ impl Store for Table {
Ok(nodes)
}
fn get_resources(&self, node: &NodeId) -> Result<HashSet<Id>, Error> {
let mut stmt = self
.db
.prepare("SELECT resource FROM routing WHERE node = ?")?;
stmt.bind(1, node)?;
let mut resources = HashSet::new();
for row in stmt.into_cursor() {
resources.insert(row?.get::<Id, _>("resource"));
}
Ok(resources)
}
fn entry(&self, id: &Id, node: &NodeId) -> Result<Option<Timestamp>, Error> {
let mut stmt = self
.db
@ -179,6 +194,26 @@ mod test {
}
}
#[test]
fn test_insert_and_get_resources() {
let ids = arbitrary::set::<Id>(5..10);
let nodes = arbitrary::set::<NodeId>(5..10);
let mut db = Table::open(":memory:").unwrap();
for id in &ids {
for node in &nodes {
assert!(db.insert(*id, *node, 0).unwrap());
}
}
for node in &nodes {
let projects = db.get_resources(node).unwrap();
for id in &ids {
assert!(projects.contains(id));
}
}
}
#[test]
fn test_entries() {
let ids = arbitrary::set::<Id>(6..9);