Skip to content

Commit 3eb5edb

Browse files
committed
Different approach for catching foreign key violation
1 parent f068b34 commit 3eb5edb

File tree

4 files changed

+129
-19
lines changed

4 files changed

+129
-19
lines changed

database/src/pool.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ pub trait Connection: Send + Sync {
234234
benchmark_set: u32,
235235
) -> anyhow::Result<u32>;
236236

237+
/// Add a benchmark job which is explicitly using a `parent_sha` we split
238+
/// this out to improve our error handling. A `parent_sha` may not have
239+
/// an associated request in the `benchmarek`
240+
async fn enqueue_parent_benchmark_job(
241+
&self,
242+
parent_sha: &str,
243+
target: Target,
244+
backend: CodegenBackend,
245+
profile: Profile,
246+
benchmark_set: u32,
247+
) -> (bool, anyhow::Result<u32>);
248+
237249
/// Returns a set of compile-time benchmark test cases that were already computed for the
238250
/// given artifact.
239251
/// Note that for efficiency reasons, the function only checks if we have at least a single
@@ -1187,4 +1199,26 @@ mod tests {
11871199
})
11881200
.await;
11891201
}
1202+
1203+
#[tokio::test]
1204+
async fn enqueue_parent_benchmark_job() {
1205+
run_postgres_test(|ctx| async {
1206+
let db = ctx.db();
1207+
1208+
let (violates_foreign_key, _) = db
1209+
.enqueue_parent_benchmark_job(
1210+
"sha-0",
1211+
Target::X86_64UnknownLinuxGnu,
1212+
CodegenBackend::Llvm,
1213+
Profile::Debug,
1214+
0,
1215+
)
1216+
.await;
1217+
1218+
assert!(violates_foreign_key);
1219+
1220+
Ok(ctx)
1221+
})
1222+
.await;
1223+
}
11901224
}

database/src/pool/postgres.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::str::FromStr;
2222
use std::sync::Arc;
2323
use std::time::Duration;
2424
use tokio::sync::Mutex;
25+
use tokio_postgres::error::SqlState;
2526
use tokio_postgres::Statement;
2627
use tokio_postgres::{GenericClient, Row};
2728

@@ -1738,6 +1739,64 @@ where
17381739
})
17391740
}
17401741

1742+
async fn enqueue_parent_benchmark_job(
1743+
&self,
1744+
parent_sha: &str,
1745+
target: Target,
1746+
backend: CodegenBackend,
1747+
profile: Profile,
1748+
benchmark_set: u32,
1749+
) -> (bool, anyhow::Result<u32>) {
1750+
let row_result = self
1751+
.conn()
1752+
.query_one(
1753+
r#"
1754+
INSERT INTO job_queue(
1755+
request_tag,
1756+
target,
1757+
backend,
1758+
profile,
1759+
benchmark_set,
1760+
status
1761+
)
1762+
VALUES ($1, $2, $3, $4, $5, $6)
1763+
ON CONFLICT DO NOTHING
1764+
RETURNING job_queue.id
1765+
"#,
1766+
&[
1767+
&parent_sha,
1768+
&target,
1769+
&backend,
1770+
&profile,
1771+
&(benchmark_set as i32),
1772+
&BENCHMARK_JOB_STATUS_QUEUED_STR,
1773+
],
1774+
)
1775+
.await;
1776+
1777+
match row_result {
1778+
Ok(row) => (false, Ok(row.get::<_, i32>(0) as u32)),
1779+
Err(e) => {
1780+
if let Some(db_err) = e.as_db_error() {
1781+
if db_err.code() == &SqlState::FOREIGN_KEY_VIOLATION {
1782+
let constraint = db_err.constraint().unwrap_or("benchmark_tag constraint");
1783+
let detail = db_err.detail().unwrap_or("");
1784+
return (
1785+
true,
1786+
Err(anyhow::anyhow!(
1787+
"Foreign key violation on {} for request_tag='{}'. {}",
1788+
constraint,
1789+
parent_sha,
1790+
detail
1791+
)),
1792+
);
1793+
}
1794+
}
1795+
(false, Err(e.into()))
1796+
}
1797+
}
1798+
}
1799+
17411800
async fn enqueue_benchmark_job(
17421801
&self,
17431802
request_tag: &str,

database/src/pool/sqlite.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,17 @@ impl Connection for SqliteConnection {
13391339
no_queue_implementation_abort!()
13401340
}
13411341

1342+
async fn enqueue_parent_benchmark_job(
1343+
&self,
1344+
_parent_sha: &str,
1345+
_target: Target,
1346+
_backend: CodegenBackend,
1347+
_profile: Profile,
1348+
_benchmark_set: u32,
1349+
) -> (bool, anyhow::Result<u32>) {
1350+
no_queue_implementation_abort!()
1351+
}
1352+
13421353
async fn get_compile_test_cases_with_measurements(
13431354
&self,
13441355
artifact_row_id: &ArtifactIdNumber,

site/src/job_queue/mod.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ pub async fn build_queue(
205205
pub async fn enqueue_benchmark_request(
206206
conn: &mut dyn database::pool::Connection,
207207
benchmark_request: &BenchmarkRequest,
208-
index: &BenchmarkRequestIndex,
209208
) -> anyhow::Result<()> {
210209
let mut tx = conn.transaction().await;
211210

@@ -240,21 +239,29 @@ pub async fn enqueue_benchmark_request(
240239
// but was already benchmarked then the collector will ignore
241240
// it as it will see it already has results.
242241
if let Some(parent_sha) = benchmark_request.parent_sha() {
243-
if !has_emitted_parent_sha_error && !index.contains_tag(parent_sha) {
244-
log::error!("Parent tag; {parent_sha} does not exist in request benchmarks. Skipping");
245-
has_emitted_parent_sha_error = true;
246-
}
247-
248-
if !has_emitted_parent_sha_error {
249-
tx.conn()
250-
.enqueue_benchmark_job(
251-
parent_sha,
252-
target,
253-
backend,
254-
profile,
255-
benchmark_set as u32,
256-
)
257-
.await?;
242+
let (is_foreign_key_violation, result) = tx
243+
.conn()
244+
.enqueue_parent_benchmark_job(
245+
parent_sha,
246+
target,
247+
backend,
248+
profile,
249+
benchmark_set as u32,
250+
)
251+
.await;
252+
253+
// At some point in time the parent_sha may not refer
254+
// to a `benchmark_request` and we want to be able to
255+
// see that error.
256+
if let Err(e) = result {
257+
if is_foreign_key_violation && !has_emitted_parent_sha_error {
258+
log::error!("Failed to create job for parent sha {e:?}");
259+
has_emitted_parent_sha_error = true;
260+
} else if has_emitted_parent_sha_error && is_foreign_key_violation {
261+
continue;
262+
} else {
263+
return Err(e);
264+
}
258265
}
259266
}
260267
}
@@ -277,7 +284,6 @@ pub async fn enqueue_benchmark_request(
277284
/// Returns benchmark requests that were completed.
278285
async fn process_benchmark_requests(
279286
conn: &mut dyn database::pool::Connection,
280-
index: &BenchmarkRequestIndex,
281287
) -> anyhow::Result<Vec<BenchmarkRequest>> {
282288
let queue = build_queue(conn).await?;
283289

@@ -293,7 +299,7 @@ async fn process_benchmark_requests(
293299
break;
294300
}
295301
BenchmarkRequestStatus::ArtifactsReady => {
296-
enqueue_benchmark_request(conn, &request, index).await?;
302+
enqueue_benchmark_request(conn, &request).await?;
297303
break;
298304
}
299305
BenchmarkRequestStatus::WaitingForArtifacts
@@ -317,7 +323,7 @@ async fn cron_enqueue_jobs(ctxt: &SiteCtxt) -> anyhow::Result<()> {
317323
// Put the releases into the `benchmark_requests` queue
318324
requests_inserted |= create_benchmark_request_releases(&*conn, &index).await?;
319325
// Enqueue waiting requests and try to complete in-progress ones
320-
let completed_reqs = process_benchmark_requests(&mut *conn, &index).await?;
326+
let completed_reqs = process_benchmark_requests(&mut *conn).await?;
321327

322328
// If some change happened, reload the benchmark request index
323329
if requests_inserted {

0 commit comments

Comments
 (0)