Skip to content

Commit dcbec23

Browse files
goffrieConvex, Inc.
authored and
Convex, Inc.
committed
Record SchemaRegistry::get_by_state read under the right index (#37277)
GitOrigin-RevId: c8cd3a3ff318905135ba64d80f64dd70d9205b12
1 parent c9514cc commit dcbec23

File tree

2 files changed

+83
-7
lines changed

2 files changed

+83
-7
lines changed

crates/database/src/schema_registry.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ impl SchemaRegistry {
226226
};
227227
let fields = IndexedFields::try_from(vec![SCHEMA_STATE_FIELD.clone()])?;
228228
let interval = index_range.compile(fields.clone())?;
229-
reads.record_indexed_derived(TabletIndexName::by_id(schema_tablet), fields, interval);
229+
reads.record_indexed_derived(
230+
TabletIndexName::new(schema_tablet, SCHEMAS_STATE_INDEX.descriptor().clone())?,
231+
fields,
232+
interval,
233+
);
230234

231235
let namespaced_registry = self.namespaced.get(&namespace);
232236
let Some(namespaced_registry) = namespaced_registry else {

crates/database/src/tests/mod.rs

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ use ::usage_tracking::FunctionUsageTracker;
1313
use cmd_util::env::env_config;
1414
use common::{
1515
assert_obj,
16-
bootstrap_model::index::{
17-
database_index::{
18-
DeveloperDatabaseIndexConfig,
19-
IndexedFields,
16+
bootstrap_model::{
17+
index::{
18+
database_index::{
19+
DeveloperDatabaseIndexConfig,
20+
IndexedFields,
21+
},
22+
IndexConfig,
23+
IndexMetadata,
2024
},
21-
IndexConfig,
22-
IndexMetadata,
25+
schema::SchemaState,
2326
},
2427
db_schema,
2528
document::{
@@ -2445,3 +2448,72 @@ async fn test_subtransaction_failure_rolls_back_table_creation(
24452448
assert!(!TableModel::new(&mut tx).table_exists(TableNamespace::test_user(), &table_name));
24462449
Ok(())
24472450
}
2451+
2452+
// regression test for ENG-8184
2453+
#[convex_macro::test_runtime]
2454+
async fn test_schema_registry_takes_read_dependency(rt: TestRuntime) -> anyhow::Result<()> {
2455+
let db = DbFixtures::new(&rt).await?.db;
2456+
let nonexistent_schema_id = {
2457+
// create an ID for a schema document that doesn't exist
2458+
let mut tx = db.begin_system().await?;
2459+
SchemaModel::new(&mut tx, TableNamespace::Global)
2460+
.submit_pending(db_schema!())
2461+
.await?
2462+
.0
2463+
};
2464+
2465+
// Create a transaction that does a by-id lookup on schemas & also observes the
2466+
// lack of a pending schema
2467+
let mut read_pending_tx = db.begin_system().await?;
2468+
assert!(read_pending_tx.get(nonexistent_schema_id).await?.is_none());
2469+
assert!(
2470+
SchemaModel::new(&mut read_pending_tx, TableNamespace::Global)
2471+
.get_by_state(SchemaState::Pending)
2472+
.await?
2473+
.is_none()
2474+
);
2475+
let read_pending_token = read_pending_tx.into_token()?;
2476+
2477+
// Now create a pending schema
2478+
let schema_id;
2479+
{
2480+
let mut tx = db.begin_system().await?;
2481+
schema_id = SchemaModel::new(&mut tx, TableNamespace::Global)
2482+
.submit_pending(db_schema!())
2483+
.await?
2484+
.0;
2485+
db.commit(tx).await?;
2486+
}
2487+
2488+
// The earlier read should be invalidated.
2489+
assert_eq!(
2490+
db.refresh_token(read_pending_token, *db.now_ts_for_reads())
2491+
.await?,
2492+
None
2493+
);
2494+
2495+
// Now test the converse: create a transaction that observes the presence of
2496+
// the pending schema.
2497+
let mut read_pending_again_tx = db.begin_system().await?;
2498+
assert!(
2499+
SchemaModel::new(&mut read_pending_again_tx, TableNamespace::Global)
2500+
.get_by_state(SchemaState::Pending)
2501+
.await?
2502+
.is_some()
2503+
);
2504+
let read_pending_again_token = read_pending_again_tx.into_token()?;
2505+
{
2506+
let mut tx = db.begin_system().await?;
2507+
SchemaModel::new(&mut tx, TableNamespace::Global)
2508+
.mark_validated(schema_id)
2509+
.await?;
2510+
db.commit(tx).await?;
2511+
}
2512+
// The read should again be invalidated as the schema is no longer pending.
2513+
assert_eq!(
2514+
db.refresh_token(read_pending_again_token, *db.now_ts_for_reads())
2515+
.await?,
2516+
None
2517+
);
2518+
Ok(())
2519+
}

0 commit comments

Comments
 (0)