(&self, req: ExecuteRequest)
| 64 | |
| 65 | impl LocalPlanExecutor { |
| 66 | async fn execute_plan_inner(&self, req: ExecuteRequest) -> ExecuteResponse { |
| 67 | // ── 1. Deadline check ───────────────────────────────────────────────── |
| 68 | if req.deadline_remaining_ms == 0 { |
| 69 | return ExecuteResponse::err(TypedClusterError::DeadlineExceeded { elapsed_ms: 0 }); |
| 70 | } |
| 71 | |
| 72 | let deadline = Duration::from_millis(req.deadline_remaining_ms).min(Duration::from_secs( |
| 73 | self.state.tuning.network.default_deadline_secs, |
| 74 | )); |
| 75 | |
| 76 | // ── 2. Descriptor version validation ────────────────────────────────── |
| 77 | // |
| 78 | // For each (collection, version) pair the caller sent, look up the local |
| 79 | // descriptor version from SystemCatalog. If any version differs, the |
| 80 | // caller's plan was built against a stale schema — reject with a typed |
| 81 | // error so they re-plan against fresh leases. |
| 82 | let catalog_ref = self.state.credentials.catalog(); |
| 83 | if let Some(catalog) = catalog_ref.as_ref() { |
| 84 | for entry in &req.descriptor_versions { |
| 85 | match catalog.get_collection(DatabaseId::DEFAULT, req.tenant_id, &entry.collection) |
| 86 | { |
| 87 | Ok(Some(stored)) => { |
| 88 | // Version 0 is the pre-B.1 sentinel; treat as 1 (same |
| 89 | // floor the drain gate uses). |
| 90 | let actual = if stored.descriptor_version == 0 { |
| 91 | 1 |
| 92 | } else { |
| 93 | stored.descriptor_version |
| 94 | }; |
| 95 | if actual != entry.version { |
| 96 | return ExecuteResponse::err(TypedClusterError::DescriptorMismatch { |
| 97 | collection: entry.collection.clone(), |
| 98 | expected_version: entry.version, |
| 99 | actual_version: actual, |
| 100 | }); |
| 101 | } |
| 102 | } |
| 103 | Ok(None) => { |
| 104 | // Collection not found locally — could be a new collection |
| 105 | // the follower saw but we haven't applied yet, or a race. |
| 106 | // Treat as DescriptorMismatch so the caller re-plans. |
| 107 | if entry.version != 0 { |
| 108 | return ExecuteResponse::err(TypedClusterError::DescriptorMismatch { |
| 109 | collection: entry.collection.clone(), |
| 110 | expected_version: entry.version, |
| 111 | actual_version: 0, |
| 112 | }); |
| 113 | } |
| 114 | } |
| 115 | Err(e) => { |
| 116 | return ExecuteResponse::err(TypedClusterError::Internal { |
| 117 | code: PLAN_DECODE_FAILED, |
| 118 | message: format!("catalog lookup failed: {e}"), |
| 119 | }); |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | } |
no test coverage detected