@@ -6,7 +6,7 @@ use botloft_core::ids::{BotId, DeliveryId};
66use botloft_core:: protocol:: { Delivery , DeliveryBacklog , DeliveryState } ;
77use rusqlite:: { Connection , OptionalExtension , Row , params} ;
88
9- use crate :: { Result , Store , parse_column, to_sql_int} ;
9+ use crate :: { Result , Store , cached_execute , cached_row , parse_column, to_sql_int} ;
1010
1111const COLUMNS : & str =
1212 "id, message_id, bot_id, state, attempts, next_attempt_at, last_error, read_at, updated_at" ;
@@ -46,7 +46,8 @@ pub enum DeliveryOutcome<'a> {
4646
4747impl Store {
4848 pub ( crate ) fn insert_delivery_in ( conn : & Connection , delivery : & Delivery ) -> Result < ( ) > {
49- conn. execute (
49+ cached_execute (
50+ conn,
5051 & format ! (
5152 "INSERT INTO deliveries ({COLUMNS}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"
5253 ) ,
@@ -82,7 +83,7 @@ impl Store {
8283 state : Option < DeliveryState > ,
8384 bot : Option < & BotId > ,
8485 ) -> Result < Vec < Delivery > > {
85- let mut stmt = self . conn . prepare ( & format ! (
86+ let mut stmt = self . conn . prepare_cached ( & format ! (
8687 "SELECT {COLUMNS} FROM deliveries \
8788 WHERE (?1 IS NULL OR state = ?1) AND (?2 IS NULL OR bot_id = ?2) \
8889 ORDER BY updated_at DESC, rowid DESC LIMIT ?3"
@@ -102,7 +103,7 @@ impl Store {
102103 /// due and nothing else of that bot is being sent. Keeps each bot's
103104 /// messages in order, one at a time.
104105 pub fn due_deliveries ( & self , now : i64 ) -> Result < Vec < Delivery > > {
105- let mut stmt = self . conn . prepare ( & format ! (
106+ let mut stmt = self . conn . prepare_cached ( & format ! (
106107 "SELECT {COLUMNS} FROM deliveries AS d \
107108 WHERE d.state = 'pending' AND d.next_attempt_at <= ?1 \
108109 AND d.rowid = (SELECT MIN(rowid) FROM deliveries \
@@ -123,17 +124,16 @@ impl Store {
123124 now : i64 ,
124125 lease_until : i64 ,
125126 ) -> Result < Option < Delivery > > {
126- Ok ( self
127- . conn
128- . query_row (
129- & format ! (
130- "UPDATE deliveries SET state = 'sending', lease_until = ?2, updated_at = ?3 \
127+ Ok ( cached_row (
128+ & self . conn ,
129+ & format ! (
130+ "UPDATE deliveries SET state = 'sending', lease_until = ?2, updated_at = ?3 \
131131 WHERE id = ?1 AND state = 'pending' RETURNING {COLUMNS}"
132- ) ,
133- params ! [ id. as_str( ) , lease_until, now] ,
134- from_row,
135- )
136- . optional ( ) ?)
132+ ) ,
133+ params ! [ id. as_str( ) , lease_until, now] ,
134+ from_row,
135+ )
136+ . optional ( ) ?)
137137 }
138138
139139 /// Records how a pending or sending delivery ended. `None` if it was in
@@ -145,16 +145,16 @@ impl Store {
145145 now : i64 ,
146146 ) -> Result < Option < Delivery > > {
147147 let update = |set : & str , values : & [ & dyn rusqlite:: ToSql ] | {
148- self . conn
149- . query_row (
150- & format ! (
151- "UPDATE deliveries SET {set}, lease_until = NULL \
148+ cached_row (
149+ & self . conn ,
150+ & format ! (
151+ "UPDATE deliveries SET {set}, lease_until = NULL \
152152 WHERE id = ?1 AND state IN ('pending', 'sending') RETURNING {COLUMNS}"
153- ) ,
154- values,
155- from_row,
156- )
157- . optional ( )
153+ ) ,
154+ values,
155+ from_row,
156+ )
157+ . optional ( )
158158 } ;
159159 let id = id. as_str ( ) ;
160160 let row = match outcome {
@@ -197,24 +197,23 @@ impl Store {
197197 /// The bot began the turn for the delivery sent with `turn_uuid`
198198 /// (spec 9.1). `None` if no unread delivery went with that uuid.
199199 pub fn mark_read ( & self , turn_uuid : & str , now : i64 ) -> Result < Option < Delivery > > {
200- Ok ( self
201- . conn
202- . query_row (
203- & format ! (
204- "UPDATE deliveries SET read_at = ?2, updated_at = ?2 \
200+ Ok ( cached_row (
201+ & self . conn ,
202+ & format ! (
203+ "UPDATE deliveries SET read_at = ?2, updated_at = ?2 \
205204 WHERE turn_uuid = ?1 AND state = 'sent' AND read_at IS NULL \
206205 RETURNING {COLUMNS}"
207- ) ,
208- params ! [ turn_uuid, now] ,
209- from_row,
210- )
211- . optional ( ) ?)
206+ ) ,
207+ params ! [ turn_uuid, now] ,
208+ from_row,
209+ )
210+ . optional ( ) ?)
212211 }
213212
214213 /// Deliveries written to the process of `generation` that it never
215214 /// began, oldest first.
216215 pub fn unread_deliveries ( & self , bot : & BotId , generation : u64 ) -> Result < Vec < Delivery > > {
217- let mut stmt = self . conn . prepare ( & format ! (
216+ let mut stmt = self . conn . prepare_cached ( & format ! (
218217 "SELECT {COLUMNS} FROM deliveries \
219218 WHERE bot_id = ?1 AND sent_generation = ?2 AND state = 'sent' AND read_at IS NULL \
220219 ORDER BY rowid"
@@ -253,7 +252,7 @@ impl Store {
253252
254253 /// Returns deliveries whose sender died mid-send to `pending`.
255254 pub fn recover_leases ( & self , now : i64 ) -> Result < Vec < Delivery > > {
256- let mut stmt = self . conn . prepare ( & format ! (
255+ let mut stmt = self . conn . prepare_cached ( & format ! (
257256 "UPDATE deliveries SET state = 'pending', lease_until = NULL, updated_at = ?1 \
258257 WHERE state = 'sending' AND lease_until <= ?1 RETURNING {COLUMNS}"
259258 ) ) ?;
@@ -280,8 +279,9 @@ impl Store {
280279
281280 pub fn delivery_backlog ( & self ) -> Result < DeliveryBacklog > {
282281 Ok ( self . conn . query_row (
283- "SELECT COALESCE(SUM(state IN ('pending', 'sending')), 0), \
284- COALESCE(SUM(state = 'dead'), 0) FROM deliveries",
282+ // Counted through the state index, not by reading every row.
283+ "SELECT (SELECT COUNT(*) FROM deliveries WHERE state IN ('pending', 'sending')), \
284+ (SELECT COUNT(*) FROM deliveries WHERE state = 'dead')",
285285 [ ] ,
286286 |row| {
287287 Ok ( DeliveryBacklog {
0 commit comments