@feltdb/core 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/// Diagnostic utilities for investigating cardinality reconstruction issues.
|
|
2
|
+
///
|
|
3
|
+
/// This module provides tools to understand how collection cardinality is reconstructed
|
|
4
|
+
/// during startup and how it compares to query-time lookups.
|
|
5
|
+
|
|
6
|
+
use crate::{AtomicMutation, FeltDb};
|
|
7
|
+
use std::collections::HashMap;
|
|
8
|
+
|
|
9
|
+
/// Diagnostic information about a single collection's cardinality.
|
|
10
|
+
#[derive(Debug, Clone)]
|
|
11
|
+
pub struct CardinalityDiagnostic {
|
|
12
|
+
/// Collection name (e.g., "github_webhook_deliveries")
|
|
13
|
+
pub collection: String,
|
|
14
|
+
|
|
15
|
+
/// Capability keys actually found in persisted rows during replay_log
|
|
16
|
+
pub persisted_capabilities: Vec<String>,
|
|
17
|
+
|
|
18
|
+
/// Count of non-deleted rows found under each capability
|
|
19
|
+
pub persisted_row_counts: HashMap<String, u64>,
|
|
20
|
+
|
|
21
|
+
/// Total rows for this collection across all capability variants
|
|
22
|
+
pub total_persisted_rows: u64,
|
|
23
|
+
|
|
24
|
+
/// Maintained cardinality value stored in collection_cardinality HashMap
|
|
25
|
+
pub maintained_count: u64,
|
|
26
|
+
|
|
27
|
+
/// What capability string query execution looks for
|
|
28
|
+
pub query_capability: String,
|
|
29
|
+
|
|
30
|
+
/// Whether query_capability matches any persisted capability
|
|
31
|
+
pub match_status: String,
|
|
32
|
+
|
|
33
|
+
/// Delta between total persisted and maintained cardinality
|
|
34
|
+
pub delta: i64,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Analyze the cardinality mismatch between persisted state and query-time lookups.
|
|
38
|
+
///
|
|
39
|
+
/// Returns diagnostic information for collections with mismatches.
|
|
40
|
+
///
|
|
41
|
+
/// # Arguments
|
|
42
|
+
/// * `db` - The FeltDb instance
|
|
43
|
+
/// * `state_namespace` - The state namespace from query context
|
|
44
|
+
/// * `application_id` - The application ID
|
|
45
|
+
/// * `collection_name` - The collection to diagnose (without namespace)
|
|
46
|
+
pub fn diagnose_cardinality(
|
|
47
|
+
db: &FeltDb,
|
|
48
|
+
state_namespace: &str,
|
|
49
|
+
application_id: &str,
|
|
50
|
+
collection_name: &str,
|
|
51
|
+
) -> CardinalityDiagnostic {
|
|
52
|
+
// What the query executor will look for
|
|
53
|
+
let query_capability = format!("{}:{}", state_namespace, collection_name);
|
|
54
|
+
|
|
55
|
+
// What the maintained cardinality HashMap contains
|
|
56
|
+
let maintained_count = db.collection_cardinality(&query_capability).unwrap_or(0);
|
|
57
|
+
|
|
58
|
+
// We can't directly inspect inner.rows from outside, but we can reason about it:
|
|
59
|
+
// During replay_log, rows are loaded with whatever capability was in the persisted log.
|
|
60
|
+
// If there's a mismatch, the query_capability won't find anything.
|
|
61
|
+
|
|
62
|
+
CardinalityDiagnostic {
|
|
63
|
+
collection: collection_name.to_string(),
|
|
64
|
+
persisted_capabilities: vec![], // Would need access to inner.rows to populate
|
|
65
|
+
persisted_row_counts: HashMap::new(),
|
|
66
|
+
total_persisted_rows: 0, // Would need to scan inner.rows
|
|
67
|
+
maintained_count,
|
|
68
|
+
query_capability,
|
|
69
|
+
match_status: if maintained_count == 0 {
|
|
70
|
+
"MISMATCH: maintained_count is 0".to_string()
|
|
71
|
+
} else {
|
|
72
|
+
"OK".to_string()
|
|
73
|
+
},
|
|
74
|
+
delta: 0, // Can't compute without authoritative row count
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Create a test scenario with mixed capability formats to reproduce the issue.
|
|
79
|
+
#[cfg(test)]
|
|
80
|
+
mod tests {
|
|
81
|
+
use super::*;
|
|
82
|
+
use crate::{open, AtomicMutation};
|
|
83
|
+
use std::fs;
|
|
84
|
+
use std::path::PathBuf;
|
|
85
|
+
use std::sync::atomic::{AtomicU64, Ordering};
|
|
86
|
+
use std::time::SystemTime;
|
|
87
|
+
use std::time::UNIX_EPOCH;
|
|
88
|
+
|
|
89
|
+
static TEMP_FILE_SEQUENCE: AtomicU64 = AtomicU64::new(0);
|
|
90
|
+
|
|
91
|
+
fn temp_file() -> PathBuf {
|
|
92
|
+
let nanos = SystemTime::now()
|
|
93
|
+
.duration_since(UNIX_EPOCH)
|
|
94
|
+
.expect("time")
|
|
95
|
+
.as_nanos();
|
|
96
|
+
let sequence = TEMP_FILE_SEQUENCE.fetch_add(1, Ordering::Relaxed);
|
|
97
|
+
std::env::temp_dir().join(format!(
|
|
98
|
+
"feltdb-diag-{}-{nanos}-{sequence}.data",
|
|
99
|
+
std::process::id()
|
|
100
|
+
))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
#[test]
|
|
104
|
+
fn test_capability_mismatch_scenario() {
|
|
105
|
+
// This test demonstrates the hypothesis:
|
|
106
|
+
// If rows are persisted under "collection_name" but queried as "namespace:collection_name",
|
|
107
|
+
// cardinality will be 0 on restart.
|
|
108
|
+
|
|
109
|
+
let path = temp_file();
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
let db = open(&path).unwrap();
|
|
113
|
+
let capability = "github_webhook_deliveries"; // Just collection name, no namespace
|
|
114
|
+
|
|
115
|
+
let mutations = vec![
|
|
116
|
+
AtomicMutation {
|
|
117
|
+
capability: capability.to_string(),
|
|
118
|
+
key: "webhook-1".to_string(),
|
|
119
|
+
value: Some(serde_json::json!({"id": 1})),
|
|
120
|
+
},
|
|
121
|
+
AtomicMutation {
|
|
122
|
+
capability: capability.to_string(),
|
|
123
|
+
key: "webhook-2".to_string(),
|
|
124
|
+
value: Some(serde_json::json!({"id": 2})),
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
db.apply_atomic_transaction("txn-1", None, &[], &mutations, None).unwrap();
|
|
129
|
+
|
|
130
|
+
// At this point, cardinality should be 2 for the key "github_webhook_deliveries"
|
|
131
|
+
let count = db.collection_cardinality(capability).unwrap();
|
|
132
|
+
assert_eq!(count, 2, "Cardinality before restart");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// After restart, cardinality is recomputed
|
|
136
|
+
let reopened = open(&path).unwrap();
|
|
137
|
+
let capability = "github_webhook_deliveries";
|
|
138
|
+
let count_after = reopened.collection_cardinality(capability).unwrap();
|
|
139
|
+
assert_eq!(count_after, 2, "Cardinality after restart should match");
|
|
140
|
+
|
|
141
|
+
// But if query looks for a DIFFERENT capability:
|
|
142
|
+
let namespaced_capability = "default:github_webhook_deliveries";
|
|
143
|
+
let count_namespaced = reopened.collection_cardinality(namespaced_capability).unwrap();
|
|
144
|
+
|
|
145
|
+
// If the persisted rows were stored under the non-namespaced key,
|
|
146
|
+
// this will return 0 - demonstrating the mismatch
|
|
147
|
+
println!(
|
|
148
|
+
"Rows under '{}': {}",
|
|
149
|
+
capability, count_after
|
|
150
|
+
);
|
|
151
|
+
println!(
|
|
152
|
+
"Rows under '{}': {}",
|
|
153
|
+
namespaced_capability, count_namespaced
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// This is the mismatch that causes Gate A to fail
|
|
157
|
+
if count_namespaced != count_after {
|
|
158
|
+
println!(
|
|
159
|
+
"CAPABILITY MISMATCH DETECTED: {} != {}",
|
|
160
|
+
count_after, count_namespaced
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let _ = fs::remove_file(path);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#[test]
|
|
168
|
+
fn test_mixed_capability_formats_in_single_db() {
|
|
169
|
+
// This test shows the exact problem:
|
|
170
|
+
// Some rows use "app:collection", others use "namespace:collection"
|
|
171
|
+
// Cardinality is recomputed based on what's in the persisted log
|
|
172
|
+
// But queries might look for a different format
|
|
173
|
+
|
|
174
|
+
let path = temp_file();
|
|
175
|
+
|
|
176
|
+
{
|
|
177
|
+
let db = open(&path).unwrap();
|
|
178
|
+
|
|
179
|
+
// Simulate old rows stored under application_id format
|
|
180
|
+
let app_id = "my-app";
|
|
181
|
+
let namespace = "default";
|
|
182
|
+
let collection = "github_webhook_deliveries";
|
|
183
|
+
|
|
184
|
+
// Write rows with one format
|
|
185
|
+
let old_format_capability = format!("{}:{}", app_id, collection);
|
|
186
|
+
let mutations_old = vec![
|
|
187
|
+
AtomicMutation {
|
|
188
|
+
capability: old_format_capability.clone(),
|
|
189
|
+
key: "old-webhook-1".to_string(),
|
|
190
|
+
value: Some(serde_json::json!({"id": 1})),
|
|
191
|
+
},
|
|
192
|
+
AtomicMutation {
|
|
193
|
+
capability: old_format_capability.clone(),
|
|
194
|
+
key: "old-webhook-2".to_string(),
|
|
195
|
+
value: Some(serde_json::json!({"id": 2})),
|
|
196
|
+
},
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
db.apply_atomic_transaction("txn-old", None, &[], &mutations_old, None)
|
|
200
|
+
.unwrap();
|
|
201
|
+
|
|
202
|
+
// Write rows with new format (namespace-based)
|
|
203
|
+
let new_format_capability = format!("{}:{}", namespace, collection);
|
|
204
|
+
let mutations_new = vec![
|
|
205
|
+
AtomicMutation {
|
|
206
|
+
capability: new_format_capability.clone(),
|
|
207
|
+
key: "new-webhook-3".to_string(),
|
|
208
|
+
value: Some(serde_json::json!({"id": 3})),
|
|
209
|
+
},
|
|
210
|
+
AtomicMutation {
|
|
211
|
+
capability: new_format_capability.clone(),
|
|
212
|
+
key: "new-webhook-4".to_string(),
|
|
213
|
+
value: Some(serde_json::json!({"id": 4})),
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
db.apply_atomic_transaction("txn-new", None, &[], &mutations_new, None)
|
|
218
|
+
.unwrap();
|
|
219
|
+
|
|
220
|
+
// Before restart, both formats should be queryable
|
|
221
|
+
assert_eq!(db.collection_cardinality(&old_format_capability).unwrap(), 2);
|
|
222
|
+
assert_eq!(db.collection_cardinality(&new_format_capability).unwrap(), 2);
|
|
223
|
+
println!(
|
|
224
|
+
"Before restart: old_format={}, new_format={}",
|
|
225
|
+
2, 2
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// After restart, cardinality is recomputed from persisted log
|
|
230
|
+
let reopened = open(&path).unwrap();
|
|
231
|
+
let old_format = format!("{}:{}", "my-app", "github_webhook_deliveries");
|
|
232
|
+
let new_format = format!("{}:{}", "default", "github_webhook_deliveries");
|
|
233
|
+
|
|
234
|
+
let old_count = reopened.collection_cardinality(&old_format).unwrap();
|
|
235
|
+
let new_count = reopened.collection_cardinality(&new_format).unwrap();
|
|
236
|
+
|
|
237
|
+
println!(
|
|
238
|
+
"After restart: old_format={}, new_format={}",
|
|
239
|
+
old_count, new_count
|
|
240
|
+
);
|
|
241
|
+
println!(
|
|
242
|
+
"Cardinalities after restart: {}",
|
|
243
|
+
reopened
|
|
244
|
+
.list_cardinalities()
|
|
245
|
+
.unwrap()
|
|
246
|
+
.iter()
|
|
247
|
+
.map(|(k, v)| format!("'{}': {}", k, v))
|
|
248
|
+
.collect::<Vec<_>>()
|
|
249
|
+
.join(", ")
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
// Both should still exist with their own counts
|
|
253
|
+
assert_eq!(old_count, 2, "Old format rows should be reconstructed");
|
|
254
|
+
assert_eq!(new_count, 2, "New format rows should be reconstructed");
|
|
255
|
+
|
|
256
|
+
// But if query only looks for new_format and old data was migrated incorrectly,
|
|
257
|
+
// the query would see 0 instead of the total.
|
|
258
|
+
|
|
259
|
+
let _ = fs::remove_file(path);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/// HTTP diagnostic endpoint for cardinality state inspection
|
|
2
|
+
///
|
|
3
|
+
/// This module provides a debug/diagnostic HTTP endpoint that exposes cardinality
|
|
4
|
+
/// reconstruction state without returning actual row data.
|
|
5
|
+
|
|
6
|
+
use serde::{Deserialize, Serialize};
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
9
|
+
pub struct CardinalityDiagnosticResponse {
|
|
10
|
+
/// Name of the collection being diagnosed
|
|
11
|
+
pub collection_pattern: String,
|
|
12
|
+
|
|
13
|
+
/// Actual row count for collections matching the pattern
|
|
14
|
+
pub actual_row_count: usize,
|
|
15
|
+
|
|
16
|
+
/// Maintained cardinality value stored in HashMap
|
|
17
|
+
pub maintained_cardinality: u64,
|
|
18
|
+
|
|
19
|
+
/// Mismatch indicator
|
|
20
|
+
pub mismatch: bool,
|
|
21
|
+
|
|
22
|
+
/// All capability keys found in HashMap that contain this pattern
|
|
23
|
+
pub cardinality_keys: Vec<(String, u64)>,
|
|
24
|
+
|
|
25
|
+
/// Context information for debugging
|
|
26
|
+
pub context: CardinalityContext,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
30
|
+
pub struct CardinalityContext {
|
|
31
|
+
/// List of all non-zero cardinalities (collection_name = count)
|
|
32
|
+
/// Sorted by count descending
|
|
33
|
+
pub all_cardinalities: Vec<(String, u64)>,
|
|
34
|
+
|
|
35
|
+
/// Actual persisted capability strings matching pattern from inner.rows
|
|
36
|
+
pub persisted_capability_keys: Vec<String>,
|
|
37
|
+
|
|
38
|
+
/// Capability keys in cardinality HashMap matching pattern
|
|
39
|
+
pub cardinality_map_keys: Vec<String>,
|
|
40
|
+
|
|
41
|
+
/// Timestamp of diagnostic
|
|
42
|
+
pub timestamp_ms: u64,
|
|
43
|
+
|
|
44
|
+
/// Total collections with data
|
|
45
|
+
pub total_collections: usize,
|
|
46
|
+
|
|
47
|
+
/// Collections with cardinality 0
|
|
48
|
+
pub zero_cardinality_count: usize,
|
|
49
|
+
|
|
50
|
+
/// Total persisted rows across all collections
|
|
51
|
+
pub total_rows: usize,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl CardinalityDiagnosticResponse {
|
|
55
|
+
pub fn new(
|
|
56
|
+
collection_pattern: String,
|
|
57
|
+
actual_row_count: usize,
|
|
58
|
+
maintained_cardinality: u64,
|
|
59
|
+
cardinality_keys: Vec<(String, u64)>,
|
|
60
|
+
) -> Self {
|
|
61
|
+
Self {
|
|
62
|
+
collection_pattern,
|
|
63
|
+
actual_row_count,
|
|
64
|
+
maintained_cardinality,
|
|
65
|
+
mismatch: actual_row_count > 0 && maintained_cardinality == 0,
|
|
66
|
+
cardinality_keys,
|
|
67
|
+
context: CardinalityContext {
|
|
68
|
+
all_cardinalities: vec![],
|
|
69
|
+
persisted_capability_keys: vec![],
|
|
70
|
+
cardinality_map_keys: vec![],
|
|
71
|
+
timestamp_ms: 0,
|
|
72
|
+
total_collections: 0,
|
|
73
|
+
zero_cardinality_count: 0,
|
|
74
|
+
total_rows: 0,
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|