Skip to content

Commit 083cc23

Browse files
committed
fix catalog ownership reassignment recovery
1 parent 3eaa498 commit 083cc23

43 files changed

Lines changed: 1644 additions & 524 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

nodedb-types/src/wire_version.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
1717
/// Cluster-wide wire format version. Stamped on every `NodeInfo` and
1818
/// returned by `nodedb::version::WIRE_FORMAT_VERSION` (a re-export).
19-
pub const WIRE_FORMAT_VERSION: u16 = 7;
19+
pub const WIRE_FORMAT_VERSION: u16 = 8;
2020

2121
/// Minimum wire format version this build can read. Equal to
2222
/// `WIRE_FORMAT_VERSION`: floor == ceiling, no backward compat window.

nodedb/src/control/catalog_entry/apply/mod.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,19 @@ use crate::control::security::catalog::SystemCatalog;
4646
/// developer runs instead of deferring to the next restart, so
4747
/// reviewers don't need to rely on a user report to surface
4848
/// half-finished sync work. Release builds skip the check.
49-
pub fn apply_to(entry: &CatalogEntry, catalog: &SystemCatalog) {
50-
apply_to_inner(entry, catalog);
49+
pub fn apply_to(entry: &CatalogEntry, catalog: &SystemCatalog) -> bool {
50+
let applied = match entry {
51+
CatalogEntry::PutTenantWithAdmin { tenant, admin } => {
52+
tenant::put_with_admin(tenant, admin, catalog)
53+
}
54+
_ => {
55+
apply_to_inner(entry, catalog);
56+
true
57+
}
58+
};
59+
if !applied {
60+
return false;
61+
}
5162
#[cfg(debug_assertions)]
5263
{
5364
// Narrow to OrphanRow — the "half-finished sync" class this
@@ -72,6 +83,7 @@ pub fn apply_to(entry: &CatalogEntry, catalog: &SystemCatalog) {
7283
orphans,
7384
);
7485
}
86+
true
7587
}
7688

7789
fn apply_to_inner(entry: &CatalogEntry, catalog: &SystemCatalog) {
@@ -139,6 +151,8 @@ fn apply_to_inner(entry: &CatalogEntry, catalog: &SystemCatalog) {
139151
name,
140152
} => continuous_aggregate::delete(*database_id, *tenant_id, name, catalog),
141153
CatalogEntry::PutTenant(stored) => tenant::put(stored, catalog),
154+
// Applied by `apply_to` so its commit outcome can suppress post-apply.
155+
CatalogEntry::PutTenantWithAdmin { .. } => {}
142156
CatalogEntry::DeleteTenant { tenant_id } => tenant::delete(*tenant_id, catalog),
143157
CatalogEntry::PutRlsPolicy(stored) => rls::put(stored, catalog),
144158
CatalogEntry::DeleteRlsPolicy {

nodedb/src/control/catalog_entry/apply/tenant.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
55
use tracing::warn;
66

7-
use crate::control::security::catalog::{StoredCollection, StoredTenant, SystemCatalog};
7+
use crate::control::security::catalog::{
8+
StoredCollection, StoredTenant, StoredUser, SystemCatalog,
9+
};
810
use crate::types::DatabaseId;
911

1012
pub fn put(stored: &StoredTenant, catalog: &SystemCatalog) {
@@ -18,6 +20,22 @@ pub fn put(stored: &StoredTenant, catalog: &SystemCatalog) {
1820
}
1921
}
2022

23+
pub fn put_with_admin(tenant: &StoredTenant, admin: &StoredUser, catalog: &SystemCatalog) -> bool {
24+
match catalog.put_tenant_with_admin(tenant, admin) {
25+
Ok(()) => true,
26+
Err(error) => {
27+
warn!(
28+
tenant = tenant.tenant_id,
29+
name = %tenant.name,
30+
admin = %admin.username,
31+
%error,
32+
"catalog_entry: put_tenant_with_admin failed"
33+
);
34+
false
35+
}
36+
}
37+
}
38+
2139
pub fn delete(tenant_id: u64, catalog: &SystemCatalog) {
2240
if let Err(e) = catalog.delete_tenant(tenant_id) {
2341
warn!(

nodedb/src/control/catalog_entry/descriptor_stamp.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ pub fn stamp(entry: CatalogEntry, clock: &HlcClock, catalog: &SystemCatalog) ->
194194
| CatalogEntry::PutApiKey(_)
195195
| CatalogEntry::RevokeApiKey { .. }
196196
| CatalogEntry::PutTenant(_)
197+
| CatalogEntry::PutTenantWithAdmin { .. }
197198
| CatalogEntry::DeleteTenant { .. }
198199
| CatalogEntry::PutRlsPolicy(_)
199200
| CatalogEntry::DeleteRlsPolicy { .. }

nodedb/src/control/catalog_entry/entry.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ pub enum CatalogEntry {
195195
/// default quota on every node so reads work immediately after
196196
/// creation.
197197
PutTenant(Box<StoredTenant>),
198+
/// Atomically create a tenant and its authoritative administrator.
199+
PutTenantWithAdmin {
200+
tenant: Box<StoredTenant>,
201+
admin: Box<StoredUser>,
202+
},
198203
/// Hard-delete a tenant identity record. Tenant data is not
199204
/// purged — that is a separate `PURGE TENANT CONFIRM` Data
200205
/// Plane meta op.
@@ -364,6 +369,7 @@ impl CatalogEntry {
364369
Self::PutContinuousAggregate(_) => "put_continuous_aggregate",
365370
Self::DeleteContinuousAggregate { .. } => "delete_continuous_aggregate",
366371
Self::PutTenant(_) => "put_tenant",
372+
Self::PutTenantWithAdmin { .. } => "put_tenant_with_admin",
367373
Self::DeleteTenant { .. } => "delete_tenant",
368374
Self::PutRlsPolicy(_) => "put_rls_policy",
369375
Self::DeleteRlsPolicy { .. } => "delete_rls_policy",

nodedb/src/control/catalog_entry/post_apply/async_dispatch/dispatcher.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ pub fn spawn_post_apply_async_side_effects(
157157
// PutContinuousAggregate / DeleteContinuousAggregate have their
158158
// own async branches above; they do not appear here.
159159
| CatalogEntry::PutTenant(_)
160+
| CatalogEntry::PutTenantWithAdmin { .. }
160161
| CatalogEntry::DeleteTenant { .. }
161162
| CatalogEntry::PutRlsPolicy(_)
162163
| CatalogEntry::DeleteRlsPolicy { .. }

nodedb/src/control/catalog_entry/post_apply/gateway_invalidation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ pub(crate) fn invalidate_gateway_cache_for_entry(entry: &CatalogEntry, shared: &
164164
}
165165

166166
// ── Tenant: identity does not affect plan shape ───────────────────────
167-
CatalogEntry::PutTenant(_) => {
167+
CatalogEntry::PutTenant(_) | CatalogEntry::PutTenantWithAdmin { .. } => {
168168
// no-op: tenant identity used for quota enforcement at exec time.
169169
}
170170
CatalogEntry::DeleteTenant { .. } => {

nodedb/src/control/catalog_entry/post_apply/sync.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ pub fn apply_post_apply_side_effects_sync(entry: &CatalogEntry, shared: &Arc<Sha
147147
CatalogEntry::PutTenant(stored) => {
148148
tenant::put((**stored).clone(), Arc::clone(shared));
149149
}
150+
CatalogEntry::PutTenantWithAdmin { tenant, admin } => {
151+
tenant::put_with_admin((**tenant).clone(), (**admin).clone(), Arc::clone(shared));
152+
}
150153
CatalogEntry::DeleteTenant { tenant_id } => {
151154
tenant::delete(*tenant_id, Arc::clone(shared));
152155
}

nodedb/src/control/catalog_entry/post_apply/tenant.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
use std::sync::Arc;
1414

15-
use crate::control::security::catalog::{StoredCollection, StoredTenant};
15+
use crate::control::security::catalog::{StoredCollection, StoredTenant, StoredUser};
1616
use crate::control::security::tenant::TenantQuota;
1717
use crate::control::state::SharedState;
1818
use crate::types::TenantId;
@@ -35,6 +35,11 @@ pub fn put(stored: StoredTenant, shared: Arc<SharedState>) {
3535
);
3636
}
3737

38+
pub fn put_with_admin(tenant: StoredTenant, admin: StoredUser, shared: Arc<SharedState>) {
39+
shared.credentials.install_replicated_user(&admin, None);
40+
put(tenant, shared);
41+
}
42+
3843
pub fn delete(tenant_id: u64, shared: Arc<SharedState>) {
3944
let tid = TenantId::new(tenant_id);
4045
let mut tenants = match shared.tenants.lock() {

nodedb/src/control/cluster/metadata_applier/audit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ pub(super) fn describe_entry(e: &catalog_entry::CatalogEntry) -> (String, u64, S
190190
),
191191
E::DeleteContinuousAggregate { name, .. } => (name.clone(), 0, String::new()),
192192
E::PutTenant(t) => (t.name.clone(), 0, String::new()),
193+
E::PutTenantWithAdmin { tenant, admin } => (tenant.name.clone(), 0, admin.username.clone()),
193194
E::DeleteTenant { tenant_id, .. } => (tenant_id.to_string(), 0, String::new()),
194195
E::PutRlsPolicy(p) => (p.name.clone(), 0, String::new()),
195196
E::DeleteRlsPolicy { name, .. } => (name.clone(), 0, String::new()),

0 commit comments

Comments
 (0)