Skip to content

Commit 8ccb676

Browse files
committed
Add doc comments to database layer and AgentApi
1 parent e3ca6c6 commit 8ccb676

3 files changed

Lines changed: 44 additions & 0 deletions

File tree

src/agent/api.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! HTTP client that agents use to communicate with the crater server.
2+
13
use std::time::Duration;
24

35
use crate::agent::Capabilities;
@@ -15,6 +17,7 @@ use reqwest::{Method, StatusCode};
1517
use serde::de::DeserializeOwned;
1618
use serde_json::json;
1719

20+
/// Errors returned by the crater server's agent API.
1821
#[derive(Debug, thiserror::Error)]
1922
pub enum AgentApiError {
2023
#[error("invalid API endpoint called")]
@@ -29,6 +32,7 @@ pub enum AgentApiError {
2932
InternalServerError(String),
3033
}
3134

35+
/// Converts an HTTP response into a typed `ApiResponse`, mapping status codes to errors.
3236
trait ResponseExt {
3337
fn to_api_response<T: DeserializeOwned>(self) -> Fallible<T>;
3438
}
@@ -72,6 +76,7 @@ pub struct AgentApi {
7276
}
7377

7478
impl AgentApi {
79+
/// Creates a new API client targeting the given server URL with an auth token.
7580
pub fn new(url: &str, token: &str) -> Self {
7681
AgentApi {
7782
url: url.to_string(),
@@ -80,6 +85,7 @@ impl AgentApi {
8085
}
8186
}
8287

88+
/// Builds an authenticated HTTP request to the given agent-api endpoint.
8389
fn build_request(&self, method: Method, url: &str) -> RequestBuilder {
8490
utils::http::prepare_sync(method, &format!("{}/agent-api/{url}", self.url)).header(
8591
AUTHORIZATION,
@@ -90,6 +96,11 @@ impl AgentApi {
9096
)
9197
}
9298

99+
/// Retries a request with exponential backoff on transient failures.
100+
// - Retries on ServerUnavailable, reqwest timeouts/connection errors,
101+
// and SQLite "database is locked" errors.
102+
// - Backs off from 16 s up to a cap of 8 minutes between attempts.
103+
// - Non-transient errors are returned immediately.
93104
fn retry<T, F: Fn(&Self) -> Fallible<T>>(&self, f: F) -> Fallible<T> {
94105
let mut retry_interval = 16u64;
95106
loop {
@@ -126,6 +137,7 @@ impl AgentApi {
126137
}
127138
}
128139

140+
/// Sends the agent's capabilities and receives its configuration from the server.
129141
pub fn config(&self, caps: &Capabilities) -> Fallible<AgentConfig> {
130142
self.retry(|this| {
131143
this.build_request(Method::POST, "config")
@@ -135,6 +147,7 @@ impl AgentApi {
135147
})
136148
}
137149

150+
/// Polls the server for the next experiment to run, sleeping 120 s if none is available.
138151
pub fn next_experiment(&self) -> Result<Experiment> {
139152
self.retry(|this| loop {
140153
let resp: Option<_> = this
@@ -154,6 +167,7 @@ impl AgentApi {
154167
})
155168
}
156169

170+
/// Requests the next crate to test for the given experiment, or `None` if the queue is empty.
157171
pub fn next_crate(&self, ex: &str) -> Fallible<Option<Crate>> {
158172
self.retry(|this| {
159173
let resp: Option<Crate> = this
@@ -166,6 +180,7 @@ impl AgentApi {
166180
})
167181
}
168182

183+
/// Uploads a crate's build/test result and base64-encoded log to the server.
169184
pub fn record_progress(
170185
&self,
171186
ex: &Experiment,
@@ -194,6 +209,7 @@ impl AgentApi {
194209
})
195210
}
196211

212+
/// Sends a heartbeat to the server to signal this agent is still alive.
197213
pub fn heartbeat(&self) -> Fallible<()> {
198214
self.retry(|this| {
199215
let _: bool = this
@@ -207,6 +223,7 @@ impl AgentApi {
207223
})
208224
}
209225

226+
/// Reports an error encountered while running an experiment to the server.
210227
pub fn report_error(&self, ex: &Experiment, error: String) -> Fallible<()> {
211228
self.retry(|this| {
212229
let _: bool = this

src/db/migrations.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Schema migrations applied on database startup.
2+
13
use crate::prelude::*;
24
use rand::distr::{Alphanumeric, SampleString};
35
use rusqlite::{Connection, Transaction};
@@ -366,6 +368,11 @@ fn migrations() -> Vec<(&'static str, MigrationKind)> {
366368
migrations
367369
}
368370

371+
/// Applies all pending migrations to the database.
372+
// - Creates the `migrations` tracking table on first run (user_version == 0).
373+
// - Loads the set of already-executed migration names.
374+
// - Iterates the full migration list, running each unapplied one inside
375+
// its own transaction and recording it in the `migrations` table.
369376
pub fn execute(db: &mut Connection) -> Fallible<()> {
370377
// If the database version is 0, create the migrations table and bump it
371378
let version: i32 = db.query_row("PRAGMA user_version;", [], |r| r.get(0))?;

src/db/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ pub struct Database {
7676
}
7777

7878
impl Database {
79+
/// Opens the database at the default path inside [`WORK_DIR`].
80+
// - Checks for legacy database filenames and renames if found.
81+
// - Delegates to `Database::new` for pool setup and migrations.
7982
pub fn open() -> Fallible<Self> {
8083
let path = WORK_DIR.join(DATABASE_PATH);
8184
if !path.exists() {
@@ -100,6 +103,7 @@ impl Database {
100103
Database::new(SqliteConnectionManager { file: path }, None)
101104
}
102105

106+
/// Opens or creates a database at the given filesystem path.
103107
pub fn open_at(path: &Path) -> Fallible<Self> {
104108
std::fs::create_dir_all(&*WORK_DIR)?;
105109
Database::new(
@@ -121,6 +125,11 @@ impl Database {
121125
)
122126
}
123127

128+
/// Builds the connection pool, configures WAL mode, and runs pending migrations.
129+
// - Creates an r2d2 pool with up to 20 connections (covers all production threads).
130+
// - Enables WAL journal mode for concurrent reads during writes.
131+
// - Sets synchronous=NORMAL for better performance (safe under WAL).
132+
// - Runs all pending schema migrations.
124133
fn new(conn: SqliteConnectionManager, tempfile: Option<NamedTempFile>) -> Fallible<Self> {
125134
let pool = Pool::builder()
126135
// By inspection we have 13 threads in production, so make sure each of them can get a
@@ -161,6 +170,7 @@ impl Database {
161170
})
162171
}
163172

173+
/// Runs a closure inside a database transaction, committing on success or rolling back on error.
164174
pub fn transaction<T, F: FnOnce(&TransactionHandle) -> Fallible<T>>(
165175
&self,
166176
will_write: bool,
@@ -194,11 +204,13 @@ pub struct TransactionHandle<'a> {
194204
}
195205

196206
impl TransactionHandle<'_> {
207+
/// Commits the transaction, persisting all changes.
197208
pub fn commit(self) -> Fallible<()> {
198209
self.transaction.commit()?;
199210
Ok(())
200211
}
201212

213+
/// Rolls the transaction back, discarding all changes.
202214
pub fn rollback(self) -> Fallible<()> {
203215
self.transaction.rollback()?;
204216
Ok(())
@@ -207,8 +219,10 @@ impl TransactionHandle<'_> {
207219

208220
/// Convenience methods for executing SQL queries against the database.
209221
pub trait QueryUtils {
222+
/// Acquires a connection and passes it to the closure.
210223
fn with_conn<T, F: FnOnce(&Connection) -> Fallible<T>>(&self, f: F) -> Fallible<T>;
211224

225+
/// Returns `true` if the query matches at least one row.
212226
fn exists(&self, sql: &str, params: &[&dyn ToSql]) -> Fallible<bool> {
213227
self.with_conn(|conn| {
214228
self.trace(sql, || {
@@ -218,6 +232,7 @@ pub trait QueryUtils {
218232
})
219233
}
220234

235+
/// Executes a statement and returns the number of rows changed.
221236
fn execute(&self, sql: &str, params: &[&dyn ToSql]) -> Fallible<usize> {
222237
self.with_conn(|conn| {
223238
self.trace(sql, || {
@@ -228,6 +243,7 @@ pub trait QueryUtils {
228243
})
229244
}
230245

246+
/// Like [`execute`](Self::execute), but uses a prepared-statement cache.
231247
fn execute_cached(&self, sql: &str, params: &[&dyn ToSql]) -> Fallible<usize> {
232248
self.with_conn(|conn| {
233249
self.trace(sql, || {
@@ -238,6 +254,7 @@ pub trait QueryUtils {
238254
})
239255
}
240256

257+
/// Returns the first row of a query, or `None` if the result set is empty.
241258
fn get_row<T, P>(
242259
&self,
243260
sql: &str,
@@ -261,6 +278,7 @@ pub trait QueryUtils {
261278
})
262279
}
263280

281+
/// Executes a query and collects all rows into a `Vec`.
264282
fn query<T, F: FnMut(&Row) -> rusqlite::Result<T>>(
265283
&self,
266284
sql: &str,
@@ -282,6 +300,7 @@ pub trait QueryUtils {
282300
})
283301
}
284302

303+
/// Returns the first row mapped through a fallible closure, or `None`.
285304
fn query_row<T, F: FnOnce(&Row) -> Fallible<T>>(
286305
&self,
287306
sql: &str,
@@ -300,6 +319,7 @@ pub trait QueryUtils {
300319
})
301320
}
302321

322+
/// Runs a closure and logs the SQL statement if it takes longer than 500 ms.
303323
fn trace<T, F: FnOnce() -> T>(&self, sql: &str, f: F) -> T {
304324
let start = Instant::now();
305325
let res = f();

0 commit comments

Comments
 (0)