Skip to content

Commit 2279731

Browse files
Fix memory accounting, update validation, and vector exclusion regressions
1 parent 444b755 commit 2279731

3 files changed

Lines changed: 69 additions & 9 deletions

File tree

crates/contextdb-core/src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Value {
5050
if s.len() <= 16 {
5151
32 + s.len().saturating_mul(8)
5252
} else {
53-
48 + s.len().saturating_mul(2)
53+
160 + s.len().saturating_mul(72)
5454
}
5555
}
5656
Value::Uuid(_) => 32,

crates/contextdb-engine/src/database.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,14 +1087,8 @@ impl Database {
10871087
if trigger_state != source.state {
10881088
continue;
10891089
}
1090-
if let Some(row) = self.relational.point_lookup_with_tx(
1091-
Some(ctx.tx),
1092-
source.table,
1093-
"id",
1094-
&Value::Uuid(source.uuid),
1095-
ctx.snapshot,
1096-
)? {
1097-
self.delete_vector(ctx.tx, row.row_id)?;
1090+
for row_id in self.logical_row_ids_for_uuid(ctx.tx, source.table, source.uuid) {
1091+
self.delete_vector(ctx.tx, row_id)?;
10981092
}
10991093
}
11001094

@@ -1140,6 +1134,33 @@ impl Database {
11401134
.point_lookup_with_tx(Some(tx), table, col, value, snapshot)
11411135
}
11421136

1137+
pub(crate) fn logical_row_ids_for_uuid(
1138+
&self,
1139+
tx: TxId,
1140+
table: &str,
1141+
uuid: uuid::Uuid,
1142+
) -> Vec<RowId> {
1143+
let mut row_ids = HashSet::new();
1144+
1145+
if let Some(rows) = self.relational_store.tables.read().get(table) {
1146+
for row in rows {
1147+
if row.values.get("id") == Some(&Value::Uuid(uuid)) {
1148+
row_ids.insert(row.row_id);
1149+
}
1150+
}
1151+
}
1152+
1153+
let _ = self.tx_mgr.with_write_set(tx, |ws| {
1154+
for (insert_table, row) in &ws.relational_inserts {
1155+
if insert_table == table && row.values.get("id") == Some(&Value::Uuid(uuid)) {
1156+
row_ids.insert(row.row_id);
1157+
}
1158+
}
1159+
});
1160+
1161+
row_ids.into_iter().collect()
1162+
}
1163+
11431164
pub fn insert_edge(
11441165
&self,
11451166
tx: TxId,

crates/contextdb-engine/src/executor.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,7 @@ fn exec_update(
10861086
let value = eval_assignment_expr(vexpr, &row.values, params)?;
10871087
values.insert(k.clone(), coerce_value_for_column(db, &p.table, k, value)?);
10881088
}
1089+
validate_update_state_transition(db, &p.table, row, &values)?;
10891090
let row_uuid = values.get("id").and_then(Value::as_uuid).copied();
10901091
let new_state = db
10911092
.table_meta(&p.table)
@@ -1155,6 +1156,44 @@ fn estimate_table_row_bytes(
11551156
Ok(estimate_row_bytes_for_meta(values, &meta, false))
11561157
}
11571158

1159+
fn validate_update_state_transition(
1160+
db: &Database,
1161+
table: &str,
1162+
existing: &VersionedRow,
1163+
next_values: &HashMap<String, Value>,
1164+
) -> Result<()> {
1165+
let Some(meta) = db.table_meta(table) else {
1166+
return Ok(());
1167+
};
1168+
let Some(state_machine) = meta.state_machine else {
1169+
return Ok(());
1170+
};
1171+
1172+
let old_state = existing
1173+
.values
1174+
.get(&state_machine.column)
1175+
.and_then(Value::as_text);
1176+
let new_state = next_values
1177+
.get(&state_machine.column)
1178+
.and_then(Value::as_text);
1179+
1180+
let (Some(old_state), Some(new_state)) = (old_state, new_state) else {
1181+
return Ok(());
1182+
};
1183+
1184+
if old_state == new_state
1185+
|| db
1186+
.relational_store()
1187+
.validate_state_transition(table, &state_machine.column, old_state, new_state)
1188+
{
1189+
return Ok(());
1190+
}
1191+
1192+
Err(Error::InvalidStateTransition(format!(
1193+
"{old_state} -> {new_state}"
1194+
)))
1195+
}
1196+
11581197
fn estimate_row_bytes_for_meta(
11591198
values: &HashMap<String, Value>,
11601199
meta: &TableMeta,

0 commit comments

Comments
 (0)