Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce37fc1a2d | ||
|
|
2cfd384339 | ||
|
|
8c013107f9 | ||
|
|
64a4466d30 | ||
|
|
1596c23eb4 | ||
|
|
129badd4e1 | ||
|
|
6f7c080180 | ||
|
|
af92561ef6 | ||
|
|
d833a3e40d |
Generated
+1
-1
@@ -1096,7 +1096,7 @@ checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-rs-relay"
|
name = "nostr-rs-relay"
|
||||||
version = "0.7.11"
|
version = "0.7.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitcoin_hashes",
|
"bitcoin_hashes",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nostr-rs-relay"
|
name = "nostr-rs-relay"
|
||||||
version = "0.7.11"
|
version = "0.7.12"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Greg Heartsfield <scsibug@imap.cc>"]
|
authors = ["Greg Heartsfield <scsibug@imap.cc>"]
|
||||||
description = "A relay implementation for the Nostr protocol"
|
description = "A relay implementation for the Nostr protocol"
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ pub async fn db_writer(
|
|||||||
&settings,
|
&settings,
|
||||||
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
|
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
|
||||||
1,
|
1,
|
||||||
4,
|
2,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if settings.database.in_memory {
|
if settings.database.in_memory {
|
||||||
@@ -636,9 +636,16 @@ pub async fn db_query(
|
|||||||
query_tx: tokio::sync::mpsc::Sender<QueryResult>,
|
query_tx: tokio::sync::mpsc::Sender<QueryResult>,
|
||||||
mut abandon_query_rx: tokio::sync::oneshot::Receiver<()>,
|
mut abandon_query_rx: tokio::sync::oneshot::Receiver<()>,
|
||||||
) {
|
) {
|
||||||
let start = Instant::now();
|
let pre_spawn_start = Instant::now();
|
||||||
task::spawn_blocking(move || {
|
task::spawn_blocking(move || {
|
||||||
debug!("moved DB query to thread in {:?}", start.elapsed());
|
let db_queue_time = pre_spawn_start.elapsed();
|
||||||
|
// report queuing time if it is slow
|
||||||
|
if db_queue_time > Duration::from_secs(1) {
|
||||||
|
debug!(
|
||||||
|
"(slow) DB query queued for {:?} (cid: {}, sub: {:?})",
|
||||||
|
db_queue_time, client_id, sub.id
|
||||||
|
);
|
||||||
|
}
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut row_count: usize = 0;
|
let mut row_count: usize = 0;
|
||||||
// generate SQL query
|
// generate SQL query
|
||||||
@@ -648,8 +655,12 @@ pub async fn db_query(
|
|||||||
log_pool_stats(&pool);
|
log_pool_stats(&pool);
|
||||||
// cutoff for displaying slow queries
|
// cutoff for displaying slow queries
|
||||||
let slow_cutoff = Duration::from_millis(2000);
|
let slow_cutoff = Duration::from_millis(2000);
|
||||||
|
// any client that doesn't cause us to generate new rows in 5
|
||||||
|
// seconds gets dropped.
|
||||||
|
let abort_cutoff = Duration::from_secs(5);
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut slow_first_event;
|
let mut slow_first_event;
|
||||||
|
let mut last_successful_send = Instant::now();
|
||||||
if let Ok(conn) = pool.get() {
|
if let Ok(conn) = pool.get() {
|
||||||
// execute the query. Don't cache, since queries vary so much.
|
// execute the query. Don't cache, since queries vary so much.
|
||||||
let mut stmt = conn.prepare(&q)?;
|
let mut stmt = conn.prepare(&q)?;
|
||||||
@@ -667,12 +678,12 @@ pub async fn db_query(
|
|||||||
}
|
}
|
||||||
// logging for slow queries; show sub and SQL.
|
// logging for slow queries; show sub and SQL.
|
||||||
// to reduce logging; only show 1/16th of clients (leading 0)
|
// to reduce logging; only show 1/16th of clients (leading 0)
|
||||||
if slow_first_event && client_id.starts_with('0') {
|
if slow_first_event && client_id.starts_with("00") {
|
||||||
info!(
|
debug!(
|
||||||
"query req (slow): {:?} (cid: {}, sub: {:?})",
|
"query req (slow): {:?} (cid: {}, sub: {:?})",
|
||||||
sub, client_id, sub.id
|
sub, client_id, sub.id
|
||||||
);
|
);
|
||||||
info!(
|
debug!(
|
||||||
"query string (slow): {} (cid: {}, sub: {:?})",
|
"query string (slow): {} (cid: {}, sub: {:?})",
|
||||||
q, client_id, sub.id
|
q, client_id, sub.id
|
||||||
);
|
);
|
||||||
@@ -697,12 +708,33 @@ pub async fn db_query(
|
|||||||
}
|
}
|
||||||
row_count += 1;
|
row_count += 1;
|
||||||
let event_json = row.get(0)?;
|
let event_json = row.get(0)?;
|
||||||
|
loop {
|
||||||
|
if query_tx.capacity() != 0 {
|
||||||
|
// we have capacity to add another item
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// the queue is full
|
||||||
|
trace!("db reader thread is stalled");
|
||||||
|
if last_successful_send + abort_cutoff < Instant::now() {
|
||||||
|
// the queue has been full for too long, abort
|
||||||
|
info!("aborting database query due to slow client");
|
||||||
|
let ok: Result<()> = Ok(());
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
// give the queue a chance to clear before trying again
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: we could use try_send, but we'd have to juggle
|
||||||
|
// getting the query result back as part of the error
|
||||||
|
// result.
|
||||||
query_tx
|
query_tx
|
||||||
.blocking_send(QueryResult {
|
.blocking_send(QueryResult {
|
||||||
sub_id: sub.get_id(),
|
sub_id: sub.get_id(),
|
||||||
event: event_json,
|
event: event_json,
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
last_successful_send = Instant::now();
|
||||||
}
|
}
|
||||||
query_tx
|
query_tx
|
||||||
.blocking_send(QueryResult {
|
.blocking_send(QueryResult {
|
||||||
@@ -711,10 +743,11 @@ pub async fn db_query(
|
|||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
debug!(
|
debug!(
|
||||||
"query completed in {:?} (cid: {}, sub: {:?}, rows: {})",
|
"query completed in {:?} (cid: {}, sub: {:?}, db_time: {:?}, rows: {})",
|
||||||
start.elapsed(),
|
pre_spawn_start.elapsed(),
|
||||||
client_id,
|
client_id,
|
||||||
sub.id,
|
sub.id,
|
||||||
|
start.elapsed(),
|
||||||
row_count
|
row_count
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ pub const STARTUP_SQL: &str = r##"
|
|||||||
PRAGMA main.synchronous=NORMAL;
|
PRAGMA main.synchronous=NORMAL;
|
||||||
PRAGMA foreign_keys = ON;
|
PRAGMA foreign_keys = ON;
|
||||||
PRAGMA journal_size_limit=32768;
|
PRAGMA journal_size_limit=32768;
|
||||||
pragma mmap_size = 1073741824; -- 1024MB of mmap
|
pragma mmap_size = 17179869184; -- cap mmap at 16GB
|
||||||
"##;
|
"##;
|
||||||
|
|
||||||
/// Latest database version
|
/// Latest database version
|
||||||
|
|||||||
+1
-2
@@ -339,8 +339,7 @@ pub fn start_server(settings: Settings, shutdown_rx: MpscReceiver<()>) -> Result
|
|||||||
let pool = db::build_pool(
|
let pool = db::build_pool(
|
||||||
"client query",
|
"client query",
|
||||||
&settings,
|
&settings,
|
||||||
rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY
|
rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY,
|
||||||
| rusqlite::OpenFlags::SQLITE_OPEN_SHARED_CACHE,
|
|
||||||
db_min_conn,
|
db_min_conn,
|
||||||
db_max_conn,
|
db_max_conn,
|
||||||
true,
|
true,
|
||||||
|
|||||||
Reference in New Issue
Block a user