New settings: num_relays_per_person, max_relays (with new relay picker logic)

This commit is contained in:
Mike Dilger 2022-12-27 16:39:34 +13:00
parent c8c6fb04af
commit 8e95ccab00
6 changed files with 94 additions and 15 deletions

View File

@ -107,7 +107,7 @@ fn upgrade(db: &Connection, mut version: u16) -> Result<(), Error> {
apply_sql!(db, version, 2, "schema2.sql"); apply_sql!(db, version, 2, "schema2.sql");
apply_sql!(db, version, 3, "schema3.sql"); apply_sql!(db, version, 3, "schema3.sql");
apply_sql!(db, version, 4, "schema4.sql"); apply_sql!(db, version, 4, "schema4.sql");
apply_sql!(db, version, 5, "schema5.sql");
info!("Database is at version {}", version); info!("Database is at version {}", version);
Ok(()) Ok(())
} }

2
src/db/schema5.sql Normal file
View File

@ -0,0 +1,2 @@
INSERT INTO settings (key, value) values ('num_relays_per_person', '2');
INSERT INTO settings (key, value) values ('max_relays', '15');

View File

@ -174,16 +174,37 @@ impl Overlord {
// Pick Relays and start Minions // Pick Relays and start Minions
{ {
let pubkeys: Vec<PublicKeyHex> = crate::globals::followed_pubkeys().await; let pubkeys: Vec<PublicKeyHex> = crate::globals::followed_pubkeys().await;
let num_relays_per_person = GLOBALS.settings.lock().await.num_relays_per_person;
let max_relays = GLOBALS.settings.lock().await.max_relays;
let mut pubkey_counts: HashMap<PublicKeyHex, u8> = HashMap::new();
for pk in pubkeys.iter() {
pubkey_counts.insert(pk.clone(), num_relays_per_person);
}
let mut relay_picker = RelayPicker { let mut relay_picker = RelayPicker {
relays: all_relays, relays: all_relays,
pubkeys: pubkeys.clone(), pubkey_counts,
person_relays: DbPersonRelay::fetch_for_pubkeys(&pubkeys).await?, person_relays: DbPersonRelay::fetch_for_pubkeys(&pubkeys).await?,
}; };
let mut best_relay: BestRelay; let mut best_relay: BestRelay;
let mut relay_count = 0;
loop { loop {
if relay_count >= max_relays {
warn!(
"Safety catch: we have picked {} relays. That's enough.",
max_relays
);
break;
}
if relay_picker.is_degenerate() { if relay_picker.is_degenerate() {
info!(
"Relay picker is degenerate, relays={} pubkey_counts={}, person_relays={}",
relay_picker.relays.len(),
relay_picker.pubkey_counts.len(),
relay_picker.person_relays.len()
);
break; break;
} }
@ -192,6 +213,7 @@ impl Overlord {
relay_picker = rp; relay_picker = rp;
if best_relay.is_degenerate() { if best_relay.is_degenerate() {
info!("Best relay is now degenerate.");
break; break;
} }
@ -206,11 +228,15 @@ impl Overlord {
}); });
info!( info!(
"Picked relay {}, {} people left", "Picked relay {} covering {} people.",
&best_relay.relay.url, &best_relay.relay.url,
relay_picker.pubkeys.len() best_relay.pubkeys.len()
); );
relay_count += 1;
} }
info!("Listening on {} relays", relay_count);
} }
// Get desired events from relays // Get desired events from relays

View File

@ -1,18 +1,19 @@
use crate::db::{DbPersonRelay, DbRelay}; use crate::db::{DbPersonRelay, DbRelay};
use crate::error::Error; use crate::error::Error;
use nostr_types::PublicKeyHex; use nostr_types::PublicKeyHex;
use std::collections::HashMap;
use tracing::info; use tracing::info;
/// See RelayPicker::best() /// See RelayPicker::best()
pub struct RelayPicker { pub struct RelayPicker {
pub relays: Vec<DbRelay>, pub relays: Vec<DbRelay>,
pub pubkeys: Vec<PublicKeyHex>, pub pubkey_counts: HashMap<PublicKeyHex, u8>,
pub person_relays: Vec<DbPersonRelay>, pub person_relays: Vec<DbPersonRelay>,
} }
impl RelayPicker { impl RelayPicker {
pub fn is_degenerate(&self) -> bool { pub fn is_degenerate(&self) -> bool {
self.relays.is_empty() || self.pubkeys.is_empty() || self.person_relays.is_empty() self.relays.is_empty() || self.pubkey_counts.is_empty() || self.person_relays.is_empty()
} }
/// This function takes a RelayPicker which consists of a list of relays, /// This function takes a RelayPicker which consists of a list of relays,
@ -21,7 +22,7 @@ impl RelayPicker {
/// the public keys such a relay will cover. It also outpus a new RelayPicker /// the public keys such a relay will cover. It also outpus a new RelayPicker
/// that contains only the remaining relays and public keys. /// that contains only the remaining relays and public keys.
pub fn best(mut self) -> Result<(BestRelay, RelayPicker), Error> { pub fn best(mut self) -> Result<(BestRelay, RelayPicker), Error> {
if self.pubkeys.is_empty() { if self.pubkey_counts.is_empty() {
return Err(Error::General( return Err(Error::General(
"best_relay called for zero people".to_owned(), "best_relay called for zero people".to_owned(),
)); ));
@ -35,7 +36,7 @@ impl RelayPicker {
info!( info!(
"Searching for the best relay among {} for {} people", "Searching for the best relay among {} for {} people",
self.relays.len(), self.relays.len(),
self.pubkeys.len() self.pubkey_counts.len()
); );
// Keep score // Keep score
@ -57,7 +58,7 @@ impl RelayPicker {
// Multiply scores by relay rank // Multiply scores by relay rank
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
for i in 0..self.relays.len() { for i in 0..self.relays.len() {
score[i] *= self.relays[i].rank.unwrap_or(1); score[i] *= self.relays[i].rank.unwrap_or(3);
} }
let winner_index = score let winner_index = score
@ -76,12 +77,30 @@ impl RelayPicker {
.map(|x| PublicKeyHex(x.person.clone())) .map(|x| PublicKeyHex(x.person.clone()))
.collect(); .collect();
self.pubkeys.retain(|x| !covered_public_keys.contains(x)); // Decrement entries where we found another relay for them
let mut changed = false;
for (pubkey, count) in self.pubkey_counts.iter_mut() {
if covered_public_keys.contains(pubkey) {
*count -= 1;
changed = true;
}
}
self.person_relays.retain(|pr| { // If the pubkey_counts did not change
!covered_public_keys.contains(&PublicKeyHex(pr.person.clone())) if !changed {
&& pr.relay != winner.url // then we are now degenerate.
}); // Output a BestRelay with zero public keys to signal this
return Ok((
BestRelay {
relay: winner,
pubkeys: vec![],
},
self,
));
}
// Remove entries with 0 more relays needed
self.pubkey_counts.retain(|_, v| *v > 0);
Ok(( Ok((
BestRelay { BestRelay {

View File

@ -8,6 +8,8 @@ pub const DEFAULT_AUTOFOLLOW: bool = false;
pub const DEFAULT_VIEW_POSTS_REFERRED_TO: bool = true; pub const DEFAULT_VIEW_POSTS_REFERRED_TO: bool = true;
pub const DEFAULT_VIEW_POSTS_REFERRING_TO: bool = false; pub const DEFAULT_VIEW_POSTS_REFERRING_TO: bool = false;
pub const DEFAULT_VIEW_THREADED: bool = true; pub const DEFAULT_VIEW_THREADED: bool = true;
pub const DEFAULT_NUM_RELAYS_PER_PERSON: u8 = 2;
pub const DEFAULT_MAX_RELAYS: u8 = 15;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings { pub struct Settings {
@ -19,6 +21,8 @@ pub struct Settings {
pub view_posts_referred_to: bool, pub view_posts_referred_to: bool,
pub view_posts_referring_to: bool, pub view_posts_referring_to: bool,
pub view_threaded: bool, pub view_threaded: bool,
pub num_relays_per_person: u8,
pub max_relays: u8,
} }
impl Default for Settings { impl Default for Settings {
@ -30,6 +34,8 @@ impl Default for Settings {
view_posts_referred_to: DEFAULT_VIEW_POSTS_REFERRED_TO, view_posts_referred_to: DEFAULT_VIEW_POSTS_REFERRED_TO,
view_posts_referring_to: DEFAULT_VIEW_POSTS_REFERRING_TO, view_posts_referring_to: DEFAULT_VIEW_POSTS_REFERRING_TO,
view_threaded: DEFAULT_VIEW_THREADED, view_threaded: DEFAULT_VIEW_THREADED,
num_relays_per_person: DEFAULT_NUM_RELAYS_PER_PERSON,
max_relays: DEFAULT_MAX_RELAYS,
} }
} }
} }
@ -60,6 +66,13 @@ impl Settings {
settings.view_posts_referring_to = numstr_to_bool(row.1) settings.view_posts_referring_to = numstr_to_bool(row.1)
} }
"view_threaded" => settings.view_threaded = numstr_to_bool(row.1), "view_threaded" => settings.view_threaded = numstr_to_bool(row.1),
"num_relays_per_person" => {
settings.num_relays_per_person =
row.1.parse::<u8>().unwrap_or(DEFAULT_NUM_RELAYS_PER_PERSON)
}
"max_relays" => {
settings.max_relays = row.1.parse::<u8>().unwrap_or(DEFAULT_MAX_RELAYS)
}
_ => {} _ => {}
} }
} }
@ -75,7 +88,8 @@ impl Settings {
"REPLACE INTO settings (key, value) VALUES \ "REPLACE INTO settings (key, value) VALUES \
('feed_chunk', ?),('overlap', ?),('autofollow', ?),\ ('feed_chunk', ?),('overlap', ?),('autofollow', ?),\
('view_posts_referred_to', ?),('view_posts_referring_to', ?),\ ('view_posts_referred_to', ?),('view_posts_referring_to', ?),\
('view_threaded', ?)", ('view_threaded', ?),('num_relays_per_person', ?), \
('max_relays', ?)",
)?; )?;
stmt.execute(( stmt.execute((
self.feed_chunk, self.feed_chunk,
@ -92,6 +106,8 @@ impl Settings {
"0" "0"
}, },
if self.view_threaded { "1" } else { "0" }, if self.view_threaded { "1" } else { "0" },
self.num_relays_per_person,
self.max_relays,
))?; ))?;
Ok(()) Ok(())

View File

@ -16,6 +16,22 @@ pub(super) fn update(
ui.separator(); ui.separator();
ui.add_space(24.0);
ui.heading("How Many Relays to Query");
ui.horizontal(|ui| {
ui.label("Number of relays to query per person: ").on_hover_text("We will query N relays per person. Many people share the same relays so those will be queried about multiple people. Takes affect on restart.");
ui.add(Slider::new(&mut app.settings.num_relays_per_person, 1..=5).text("relays"));
});
ui.horizontal(|ui| {
ui.label("Maximum total number of relays to query: ")
.on_hover_text(
"We will not connect to more than this many relays. Takes affect on restart.",
);
ui.add(Slider::new(&mut app.settings.max_relays, 1..=30).text("relays"));
});
ui.add_space(24.0); ui.add_space(24.0);
ui.heading("How Many Posts to Load"); ui.heading("How Many Posts to Load");