@feltdb/core 0.15.0 → 0.16.0
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/agent-state.d.ts +20 -0
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +36 -0
- package/dist/build-identity.json +12 -4
- package/dist/cli/commands.js +187 -4
- package/dist/cli/publish-engine.js +116 -16
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +3 -0
- package/dist/create/build-identity.json +12 -4
- package/dist/create/managed-account.js +93 -35
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +6 -509
- package/dist/create/server-source/Cargo.toml +2 -13
- package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +255 -12
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +1 -1
- package/dist/db.d.ts +11 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +15 -2
- package/dist/error-codes.d.ts +5 -0
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +9 -1
- package/dist/http-db.d.ts +16 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +36 -6
- package/dist/managed-recovery.d.ts +6 -0
- package/dist/managed-recovery.d.ts.map +1 -1
- package/dist/managed-recovery.js +9 -0
- package/dist/studio-app/assets/{feltdb_wasm-BjM1ylL3.js → feltdb_wasm-DtybUY0q.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-DsgIUwaB.wasm +0 -0
- package/dist/studio-app/assets/index-C4OffsZl.js +37 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/wasm/package.json +1 -1
- package/dist/workload.d.ts +55 -3
- package/dist/workload.d.ts.map +1 -1
- package/dist/workload.js +23 -0
- package/dist/workspace/workspace-connection.d.ts.map +1 -1
- package/dist/workspace/workspace-connection.js +14 -3
- package/package.json +1 -1
- package/dist/create/server-source/crates/feltdb/Cargo.lock +0 -175
- package/dist/create/server-source/crates/feltdb/Cargo.toml +0 -102
- package/dist/create/server-source/crates/feltdb/LICENSE +0 -21
- package/dist/create/server-source/crates/feltdb/README.md +0 -75
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +0 -370
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +0 -589
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +0 -247
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +0 -440
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +0 -275
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +0 -381
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +0 -467
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +0 -489
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +0 -281
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +0 -606
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +0 -531
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +0 -462
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +0 -505
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +0 -484
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +0 -758
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +0 -421
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +0 -329
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +0 -1705
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +0 -286
- package/dist/create/server-source/crates/feltdb/src/admission.rs +0 -185
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +0 -507
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +0 -539
- package/dist/create/server-source/crates/feltdb/src/agent_state.rs +0 -320
- package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +0 -1545
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +0 -521
- package/dist/create/server-source/crates/feltdb/src/application.rs +0 -2674
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +0 -1070
- package/dist/create/server-source/crates/feltdb/src/authority.rs +0 -479
- package/dist/create/server-source/crates/feltdb/src/authority_failover.rs +0 -847
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +0 -1030
- package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +0 -1122
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority-client.rs +0 -32
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority.rs +0 -19
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +0 -1474
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +0 -8
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +0 -418
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +0 -482
- package/dist/create/server-source/crates/feltdb/src/capability.rs +0 -903
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +0 -263
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -77
- package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +0 -496
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +0 -2574
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +0 -212
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +0 -422
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +0 -445
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +0 -465
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +0 -634
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +0 -427
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +0 -376
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +0 -365
- package/dist/create/server-source/crates/feltdb/src/cron.rs +0 -294
- package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +0 -483
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +0 -477
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +0 -1003
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +0 -1334
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +0 -368
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +0 -231
- package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +0 -482
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +0 -203
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +0 -317
- package/dist/create/server-source/crates/feltdb/src/equality_index.rs +0 -595
- package/dist/create/server-source/crates/feltdb/src/execution.rs +0 -426
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +0 -214
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +0 -776
- package/dist/create/server-source/crates/feltdb/src/lib.rs +0 -7365
- package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +0 -234
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +0 -184
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -266
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +0 -310
- package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +0 -736
- package/dist/create/server-source/crates/feltdb/src/observability.rs +0 -379
- package/dist/create/server-source/crates/feltdb/src/operation.rs +0 -290
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +0 -439
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +0 -349
- package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +0 -332
- package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +0 -718
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +0 -487
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +0 -166
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +0 -289
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +0 -566
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +0 -3391
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +0 -203
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +0 -261
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +0 -502
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +0 -216
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +0 -303
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +0 -323
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +0 -531
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +0 -406
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +0 -436
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +0 -387
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +0 -378
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +0 -359
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +0 -372
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +0 -404
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +0 -376
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +0 -461
- package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +0 -2125
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +0 -418
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +0 -207
- package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +0 -126
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +0 -218
- package/dist/create/server-source/crates/feltdb/src/read_basis.rs +0 -257
- package/dist/create/server-source/crates/feltdb/src/references.rs +0 -404
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +0 -401
- package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +0 -501
- package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +0 -680
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +0 -163
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +0 -133
- package/dist/create/server-source/crates/feltdb/src/routing.rs +0 -409
- package/dist/create/server-source/crates/feltdb/src/semantic_decision.rs +0 -2029
- package/dist/create/server-source/crates/feltdb/src/semantic_query.rs +0 -599
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +0 -549
- package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +0 -516
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +0 -6003
- package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +0 -222
- package/dist/create/server-source/crates/feltdb/src/state_facade.rs +0 -320
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +0 -291
- package/dist/create/server-source/crates/feltdb/src/state_model.rs +0 -4158
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +0 -379
- package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +0 -673
- package/dist/create/server-source/crates/feltdb/src/storage.rs +0 -273
- package/dist/create/server-source/crates/feltdb/src/submission.rs +0 -471
- package/dist/create/server-source/crates/feltdb/src/sync.rs +0 -495
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +0 -822
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +0 -433
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +0 -462
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +0 -965
- package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +0 -1120
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +0 -643
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +0 -390
- package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +0 -749
- package/dist/create/server-source/crates/feltdb/src/versioned_object_substrate.rs +0 -708
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +0 -1269
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +0 -713
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +0 -510
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +0 -354
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +0 -594
- package/dist/create/server-source/crates/feltdb/src/workload.rs +0 -4222
- package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +0 -456
- package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +0 -1188
- package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +0 -2884
- package/dist/create/server-source/crates/feltdb/tests/authority_process.rs +0 -297
- package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +0 -534
- package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +0 -132
- package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/common/mod.rs +0 -96
- package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +0 -272
- package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +0 -467
- package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +0 -309
- package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +0 -445
- package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +0 -518
- package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +0 -392
- package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +0 -850
- package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +0 -23340
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +0 -1916
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +0 -1878
- package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +0 -1862
- package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_evidence.rs +0 -123
- package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_substrate_completion.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/local_process_ownership.rs +0 -69
- package/dist/create/server-source/crates/feltdb/tests/managed_incident_regression.rs +0 -191
- package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +0 -278
- package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +0 -234
- package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +0 -947
- package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +0 -404
- package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +0 -916
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +0 -1045
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +0 -347
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +0 -361
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +0 -330
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +0 -93
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +0 -622
- package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +0 -517
- package/dist/create/server-source/crates/feltdb/tests/production_certification.rs +0 -1153
- package/dist/create/server-source/crates/feltdb/tests/production_contract.rs +0 -771
- package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +0 -1383
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +0 -868
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +0 -221
- package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +0 -417
- package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +0 -338
- package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +0 -1039
- package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +0 -739
- package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +0 -452
- package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +0 -81
- package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +0 -438
- package/dist/create/server-source/crates/feltdb/tests/semantic_decision.rs +0 -1165
- package/dist/create/server-source/crates/feltdb/tests/semantic_query.rs +0 -767
- package/dist/create/server-source/crates/feltdb/tests/semantic_query_contract.rs +0 -363
- package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +0 -1799
- package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +0 -1316
- package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +0 -358
- package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +0 -365
- package/dist/create/server-source/crates/feltdb/tests/state_ref_authority.rs +0 -918
- package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/storage_independent_versioned_object_substrate.rs +0 -328
- package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +0 -255
- package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +0 -249
- package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +0 -994
- package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +0 -484
- package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
- package/dist/studio-app/assets/index-1wd0uKua.js +0 -30
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
//! Operational health.
|
|
2
|
-
//!
|
|
3
|
-
//! Everything from the format work onward proved what FeltDB *does*. This file
|
|
4
|
-
//! asks a different question:
|
|
5
|
-
//!
|
|
6
|
-
//! > **Can an operator reliably tell what FeltDB knows about itself?**
|
|
7
|
-
//!
|
|
8
|
-
//! The rule the whole surface is built on:
|
|
9
|
-
//!
|
|
10
|
-
//! > **Health can expose a proven fact. It cannot create a stronger
|
|
11
|
-
//! > guarantee.**
|
|
12
|
-
//!
|
|
13
|
-
//! So `DatabaseHealth` reports the durable format an open accepted and whether
|
|
14
|
-
//! replay discarded an incomplete final append, and nothing else. There is no
|
|
15
|
-
//! replication health, no backup freshness and no durability claim, because
|
|
16
|
-
//! none of those has an operational contract yet and inventing one here would
|
|
17
|
-
//! reintroduce exactly the defect this replaces: a reassuring label that
|
|
18
|
-
//! observes nothing.
|
|
19
|
-
//!
|
|
20
|
-
//! See `docs/architecture/operational-health.md`.
|
|
21
|
-
|
|
22
|
-
use feltdb::{
|
|
23
|
-
inspect_durable_format, DatabaseHealth, DurableFormat, FeltDb, FlowError, LogRecovery,
|
|
24
|
-
StorageHealth, DURABLE_FORMAT_VERSION,
|
|
25
|
-
};
|
|
26
|
-
use serde_json::{json, Value};
|
|
27
|
-
use std::io::Write;
|
|
28
|
-
use std::path::Path;
|
|
29
|
-
use tempfile::TempDir;
|
|
30
|
-
|
|
31
|
-
fn three_writes(path: &Path) -> Vec<u8> {
|
|
32
|
-
let db = FeltDb::open(path).unwrap();
|
|
33
|
-
for n in 0..3 {
|
|
34
|
-
db.insert(&format!("tasks:{n}"), json!({ "n": n })).unwrap();
|
|
35
|
-
}
|
|
36
|
-
drop(db);
|
|
37
|
-
std::fs::read(path).unwrap()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
// The five questions health has to answer
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
|
|
44
|
-
/// **A clean startup reports clean.**
|
|
45
|
-
#[test]
|
|
46
|
-
fn a_clean_open_reports_clean_storage() {
|
|
47
|
-
let directory = TempDir::new().unwrap();
|
|
48
|
-
let path = directory.path().join("clean.log");
|
|
49
|
-
three_writes(&path);
|
|
50
|
-
|
|
51
|
-
let db = FeltDb::open(&path).unwrap();
|
|
52
|
-
let health = db.health();
|
|
53
|
-
|
|
54
|
-
assert_eq!(health.storage, StorageHealth::Clean);
|
|
55
|
-
assert_eq!(health.recovery, LogRecovery::Clean);
|
|
56
|
-
assert_eq!(
|
|
57
|
-
health.durable_format,
|
|
58
|
-
DurableFormat::Versioned(DURABLE_FORMAT_VERSION)
|
|
59
|
-
);
|
|
60
|
-
assert!(health.is_nominal());
|
|
61
|
-
assert_eq!(health.storage.label(), "clean");
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/// **The regression that matters.** A database that discarded a torn tail must
|
|
65
|
-
/// not report the same health as one that replayed cleanly.
|
|
66
|
-
///
|
|
67
|
-
/// This is the operational consequence of the corruption work: the distinction
|
|
68
|
-
/// between a clean open and a recovered one was established there, and it is
|
|
69
|
-
/// worth nothing to an operator unless it reaches them.
|
|
70
|
-
#[test]
|
|
71
|
-
fn a_recovered_open_does_not_report_the_same_health_as_a_clean_one() {
|
|
72
|
-
let directory = TempDir::new().unwrap();
|
|
73
|
-
let clean_path = directory.path().join("clean.log");
|
|
74
|
-
let torn_path = directory.path().join("torn.log");
|
|
75
|
-
let full = three_writes(&clean_path);
|
|
76
|
-
|
|
77
|
-
// The same database, with its final append cut short.
|
|
78
|
-
std::fs::write(&torn_path, &full[..full.len() - 30]).unwrap();
|
|
79
|
-
|
|
80
|
-
let clean = FeltDb::open(&clean_path).unwrap().health();
|
|
81
|
-
let torn = FeltDb::open(&torn_path).unwrap().health();
|
|
82
|
-
|
|
83
|
-
assert_ne!(
|
|
84
|
-
clean, torn,
|
|
85
|
-
"a database that lost its last write must not look identical to one that did not"
|
|
86
|
-
);
|
|
87
|
-
assert!(clean.is_nominal());
|
|
88
|
-
assert!(!torn.is_nominal(), "recovered is not nominal");
|
|
89
|
-
assert_ne!(clean.storage.label(), torn.storage.label());
|
|
90
|
-
|
|
91
|
-
match torn.storage {
|
|
92
|
-
StorageHealth::RecoveredIncompleteWrite {
|
|
93
|
-
byte_offset,
|
|
94
|
-
discarded_bytes,
|
|
95
|
-
} => {
|
|
96
|
-
assert!(byte_offset > 0, "the operator is told where");
|
|
97
|
-
assert!(discarded_bytes > 0, "and how much");
|
|
98
|
-
}
|
|
99
|
-
other => panic!("expected a reported recovery, got {other:?}"),
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// And it says so in words an operator can act on.
|
|
103
|
-
let described = torn.storage.to_string();
|
|
104
|
-
assert!(described.contains("incomplete append"));
|
|
105
|
-
assert!(described.contains("last write did not land"));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/// **A corrupt database does not become healthy.** It does not open at all.
|
|
109
|
-
///
|
|
110
|
-
/// The ambiguity being removed here is "healthy process, unhealthy database":
|
|
111
|
-
/// there is no state in which a server is serving a database whose durable log
|
|
112
|
-
/// failed to replay.
|
|
113
|
-
#[test]
|
|
114
|
-
fn a_corrupt_database_never_reaches_a_health_report() {
|
|
115
|
-
let directory = TempDir::new().unwrap();
|
|
116
|
-
let path = directory.path().join("corrupt.log");
|
|
117
|
-
three_writes(&path);
|
|
118
|
-
|
|
119
|
-
let mut file = std::fs::OpenOptions::new()
|
|
120
|
-
.append(true)
|
|
121
|
-
.open(&path)
|
|
122
|
-
.unwrap();
|
|
123
|
-
writeln!(file, "this is not json at all").unwrap();
|
|
124
|
-
drop(file);
|
|
125
|
-
|
|
126
|
-
match FeltDb::open(&path) {
|
|
127
|
-
Err(FlowError::CorruptLogLine(_)) => {}
|
|
128
|
-
Err(other) => panic!("wrong error: {other}"),
|
|
129
|
-
Ok(_) => panic!("a corrupt database opened and could have reported health"),
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/// **An incompatible database stays refused**, so a running server cannot be
|
|
134
|
-
/// advertising one.
|
|
135
|
-
#[test]
|
|
136
|
-
fn an_incompatible_database_never_reaches_a_health_report() {
|
|
137
|
-
let directory = TempDir::new().unwrap();
|
|
138
|
-
let path = directory.path().join("future.log");
|
|
139
|
-
std::fs::write(
|
|
140
|
-
&path,
|
|
141
|
-
format!(
|
|
142
|
-
"{}\n",
|
|
143
|
-
json!({
|
|
144
|
-
"record_type": "feltdb.format.v1",
|
|
145
|
-
"format_version": DURABLE_FORMAT_VERSION + 1
|
|
146
|
-
})
|
|
147
|
-
),
|
|
148
|
-
)
|
|
149
|
-
.unwrap();
|
|
150
|
-
|
|
151
|
-
assert!(!inspect_durable_format(&path).unwrap().is_compatible());
|
|
152
|
-
assert!(matches!(
|
|
153
|
-
FeltDb::open(&path),
|
|
154
|
-
Err(FlowError::IncompatibleFormat(_))
|
|
155
|
-
));
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/// Health survives the thing it describes: reopening a repaired log reports
|
|
159
|
-
/// clean again, because the condition is genuinely gone.
|
|
160
|
-
///
|
|
161
|
-
/// A status that stayed degraded forever would be as useless as one that never
|
|
162
|
-
/// was.
|
|
163
|
-
#[test]
|
|
164
|
-
fn health_reflects_the_current_open_not_the_database_s_past() {
|
|
165
|
-
let directory = TempDir::new().unwrap();
|
|
166
|
-
let path = directory.path().join("repaired.log");
|
|
167
|
-
let full = three_writes(&path);
|
|
168
|
-
std::fs::write(&path, &full[..full.len() - 30]).unwrap();
|
|
169
|
-
|
|
170
|
-
let recovered = FeltDb::open(&path).unwrap();
|
|
171
|
-
assert!(!recovered.health().is_nominal());
|
|
172
|
-
drop(recovered);
|
|
173
|
-
|
|
174
|
-
let reopened = FeltDb::open(&path).unwrap();
|
|
175
|
-
assert!(
|
|
176
|
-
reopened.health().is_nominal(),
|
|
177
|
-
"the incomplete append is gone, so the condition is too"
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/// A database with no torn tail but written before format versioning is
|
|
182
|
-
/// reported as what it is, rather than as an error or as current.
|
|
183
|
-
#[test]
|
|
184
|
-
fn an_unversioned_database_reports_its_actual_format() {
|
|
185
|
-
let directory = TempDir::new().unwrap();
|
|
186
|
-
let path = directory.path().join("unversioned.log");
|
|
187
|
-
std::fs::write(
|
|
188
|
-
&path,
|
|
189
|
-
format!(
|
|
190
|
-
"{}\n",
|
|
191
|
-
json!({
|
|
192
|
-
"capability": "tasks", "key": "tasks:1",
|
|
193
|
-
"rust_type": "serde_json::value::Value", "value": {"n": 1},
|
|
194
|
-
"unix_ms": 1, "content_hash": null, "flow_ref": null,
|
|
195
|
-
"deleted": false, "operation": null
|
|
196
|
-
})
|
|
197
|
-
),
|
|
198
|
-
)
|
|
199
|
-
.unwrap();
|
|
200
|
-
|
|
201
|
-
let health = FeltDb::open(&path).unwrap().health();
|
|
202
|
-
assert_eq!(health.durable_format, DurableFormat::Unversioned);
|
|
203
|
-
assert!(health.is_nominal(), "unversioned is not unhealthy");
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// ---------------------------------------------------------------------------
|
|
207
|
-
// What health deliberately does not say
|
|
208
|
-
// ---------------------------------------------------------------------------
|
|
209
|
-
|
|
210
|
-
/// **Health does not manufacture a guarantee the database does not have.**
|
|
211
|
-
///
|
|
212
|
-
/// The defect being replaced was `storage: "durable"` — a string constant that
|
|
213
|
-
/// inspected nothing and asserted the one property still unproven. The
|
|
214
|
-
/// replacement is a small closed set of observed conditions, and every label in
|
|
215
|
-
/// it names what was seen rather than what would be reassuring.
|
|
216
|
-
///
|
|
217
|
-
/// In particular nothing here claims durability against power loss, which
|
|
218
|
-
/// remains unproven; nothing claims the database is replicated, backed up, or
|
|
219
|
-
/// within any capacity; and there is no "probably fine".
|
|
220
|
-
#[test]
|
|
221
|
-
fn health_reports_only_conditions_that_were_observed() {
|
|
222
|
-
let directory = TempDir::new().unwrap();
|
|
223
|
-
let clean = directory.path().join("a.log");
|
|
224
|
-
let torn = directory.path().join("b.log");
|
|
225
|
-
let full = three_writes(&clean);
|
|
226
|
-
std::fs::write(&torn, &full[..full.len() - 30]).unwrap();
|
|
227
|
-
|
|
228
|
-
let labels: Vec<&str> = [&clean, &torn]
|
|
229
|
-
.iter()
|
|
230
|
-
.map(|path| FeltDb::open(path).unwrap().health().storage.label())
|
|
231
|
-
.collect();
|
|
232
|
-
|
|
233
|
-
// Exactly two conditions, both naming an observation.
|
|
234
|
-
assert_eq!(labels, vec!["clean", "recovered-incomplete-write"]);
|
|
235
|
-
for label in &labels {
|
|
236
|
-
assert!(
|
|
237
|
-
!label.contains("durable") && !label.contains("healthy"),
|
|
238
|
-
"'{label}' would assert more than was observed"
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/// The health value is derived from the recovery the open recorded, not from
|
|
244
|
-
/// anything a caller can set.
|
|
245
|
-
#[test]
|
|
246
|
-
fn health_is_derived_from_the_open_rather_than_configured() {
|
|
247
|
-
let directory = TempDir::new().unwrap();
|
|
248
|
-
let path = directory.path().join("derived.log");
|
|
249
|
-
let full = three_writes(&path);
|
|
250
|
-
std::fs::write(&path, &full[..full.len() - 30]).unwrap();
|
|
251
|
-
|
|
252
|
-
let db = FeltDb::open(&path).unwrap();
|
|
253
|
-
let health: DatabaseHealth = db.health();
|
|
254
|
-
|
|
255
|
-
// The two agree because one is computed from the other.
|
|
256
|
-
match (&health.recovery, &health.storage) {
|
|
257
|
-
(
|
|
258
|
-
LogRecovery::RecoveredTornTail {
|
|
259
|
-
byte_offset: recovered_at,
|
|
260
|
-
discarded_bytes: recovered_bytes,
|
|
261
|
-
},
|
|
262
|
-
StorageHealth::RecoveredIncompleteWrite {
|
|
263
|
-
byte_offset,
|
|
264
|
-
discarded_bytes,
|
|
265
|
-
},
|
|
266
|
-
) => {
|
|
267
|
-
assert_eq!(recovered_at, byte_offset);
|
|
268
|
-
assert_eq!(recovered_bytes, discarded_bytes);
|
|
269
|
-
}
|
|
270
|
-
other => panic!("recovery and storage disagree: {other:?}"),
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Writing more does not change what the open found.
|
|
274
|
-
db.insert("tasks:9", json!({"n": 9})).unwrap();
|
|
275
|
-
assert_eq!(db.health(), health);
|
|
276
|
-
let value: Value = db.get("tasks:9").unwrap().unwrap();
|
|
277
|
-
assert_eq!(value["n"], json!(9), "and the database is fully usable");
|
|
278
|
-
}
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
//! PR34 — bounded query execution without collection materialization.
|
|
2
|
-
//!
|
|
3
|
-
//! `FeltDb::query_collection` is the state-access primitive the bounded query
|
|
4
|
-
//! surface executes on. These tests pin the two properties the query path
|
|
5
|
-
//! depends on: it observes every live record of a collection in record-key
|
|
6
|
-
//! order, and it clones only the records its predicate retains.
|
|
7
|
-
|
|
8
|
-
use feltdb::{query_execution_diagnostics, FeltDb, StoredRow};
|
|
9
|
-
use serde_json::json;
|
|
10
|
-
use std::sync::{Mutex, MutexGuard, OnceLock};
|
|
11
|
-
use tempfile::TempDir;
|
|
12
|
-
|
|
13
|
-
/// The read counters are process-global, and the test binary runs its tests in
|
|
14
|
-
/// threads of one process, so a counter assertion is only meaningful while no
|
|
15
|
-
/// other test in this file is reading a collection.
|
|
16
|
-
fn exclusive() -> MutexGuard<'static, ()> {
|
|
17
|
-
static SERIAL: OnceLock<Mutex<()>> = OnceLock::new();
|
|
18
|
-
SERIAL
|
|
19
|
-
.get_or_init(|| Mutex::new(()))
|
|
20
|
-
.lock()
|
|
21
|
-
.unwrap_or_else(|poisoned| poisoned.into_inner())
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
fn seeded(records: usize) -> (TempDir, FeltDb) {
|
|
25
|
-
let directory = TempDir::new().expect("temp dir");
|
|
26
|
-
let db = FeltDb::open(directory.path().join("pr34.log")).expect("open db");
|
|
27
|
-
for index in 0..records {
|
|
28
|
-
db.insert(
|
|
29
|
-
&format!("items:record-{index:05}"),
|
|
30
|
-
json!({ "tenant": format!("tenant-{}", index % 4), "n": index }),
|
|
31
|
-
)
|
|
32
|
-
.expect("insert");
|
|
33
|
-
}
|
|
34
|
-
(directory, db)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
#[test]
|
|
38
|
-
fn scan_returns_only_matching_records() {
|
|
39
|
-
let _serial = exclusive();
|
|
40
|
-
let (_directory, db) = seeded(40);
|
|
41
|
-
|
|
42
|
-
let matches = db
|
|
43
|
-
.query_collection("items", None, |row| {
|
|
44
|
-
row.value.get("tenant") == Some(&json!("tenant-1"))
|
|
45
|
-
})
|
|
46
|
-
.expect("scan");
|
|
47
|
-
|
|
48
|
-
assert_eq!(matches.len(), 10, "one quarter of the collection matches");
|
|
49
|
-
assert!(matches
|
|
50
|
-
.iter()
|
|
51
|
-
.all(|row| row.value.get("tenant") == Some(&json!("tenant-1"))));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
#[test]
|
|
55
|
-
fn scan_of_an_empty_or_unknown_collection_is_empty() {
|
|
56
|
-
let _serial = exclusive();
|
|
57
|
-
let (_directory, db) = seeded(0);
|
|
58
|
-
|
|
59
|
-
assert!(db
|
|
60
|
-
.query_collection("items", None, |_| true)
|
|
61
|
-
.expect("scan")
|
|
62
|
-
.is_empty());
|
|
63
|
-
assert!(db
|
|
64
|
-
.query_collection("no-such-collection", None, |_| true)
|
|
65
|
-
.expect("scan")
|
|
66
|
-
.is_empty());
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
#[test]
|
|
70
|
-
fn scan_visits_records_in_record_key_order() {
|
|
71
|
-
let _serial = exclusive();
|
|
72
|
-
let (_directory, db) = seeded(16);
|
|
73
|
-
|
|
74
|
-
let keys: Vec<String> = db
|
|
75
|
-
.query_collection("items", None, |_| true)
|
|
76
|
-
.expect("scan")
|
|
77
|
-
.iter()
|
|
78
|
-
.map(|row: &StoredRow| row.key.clone())
|
|
79
|
-
.collect();
|
|
80
|
-
let mut sorted = keys.clone();
|
|
81
|
-
sorted.sort();
|
|
82
|
-
|
|
83
|
-
assert_eq!(keys, sorted, "traversal follows the collection's key order");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#[test]
|
|
87
|
-
fn a_limit_stops_the_traversal_once_it_is_satisfied() {
|
|
88
|
-
let _serial = exclusive();
|
|
89
|
-
let (_directory, db) = seeded(500);
|
|
90
|
-
|
|
91
|
-
let mut visited = 0usize;
|
|
92
|
-
let matches = db
|
|
93
|
-
.query_collection("items", Some(5), |_| {
|
|
94
|
-
visited += 1;
|
|
95
|
-
true
|
|
96
|
-
})
|
|
97
|
-
.expect("scan");
|
|
98
|
-
|
|
99
|
-
assert_eq!(matches.len(), 5, "the limit bounds the result");
|
|
100
|
-
assert_eq!(
|
|
101
|
-
visited, 5,
|
|
102
|
-
"a satisfied limit stops the traversal instead of walking the collection"
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
#[test]
|
|
107
|
-
fn a_scan_clones_only_the_records_it_retains() {
|
|
108
|
-
let _serial = exclusive();
|
|
109
|
-
let (_directory, db) = seeded(2_000);
|
|
110
|
-
|
|
111
|
-
let before = query_execution_diagnostics::counters();
|
|
112
|
-
let matches = db
|
|
113
|
-
.query_collection("items", None, |row| row.value.get("n") == Some(&json!(7)))
|
|
114
|
-
.expect("scan");
|
|
115
|
-
let after = query_execution_diagnostics::counters();
|
|
116
|
-
|
|
117
|
-
assert_eq!(matches.len(), 1);
|
|
118
|
-
assert_eq!(
|
|
119
|
-
after.full_collection_materializations, before.full_collection_materializations,
|
|
120
|
-
"a scan must not fall back to full collection materialization"
|
|
121
|
-
);
|
|
122
|
-
assert_eq!(
|
|
123
|
-
after.scan_records_visited - before.scan_records_visited,
|
|
124
|
-
2_000,
|
|
125
|
-
"the predicate observes every record, borrowed"
|
|
126
|
-
);
|
|
127
|
-
assert_eq!(
|
|
128
|
-
after.scan_records_materialized - before.scan_records_materialized,
|
|
129
|
-
1,
|
|
130
|
-
"only the matching record is cloned"
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
#[test]
|
|
135
|
-
fn full_materialization_is_still_counted_for_readers_that_ask_for_it() {
|
|
136
|
-
let _serial = exclusive();
|
|
137
|
-
let (_directory, db) = seeded(32);
|
|
138
|
-
|
|
139
|
-
let before = query_execution_diagnostics::counters();
|
|
140
|
-
let rows = db.list_collection("items").expect("list");
|
|
141
|
-
let after = query_execution_diagnostics::counters();
|
|
142
|
-
|
|
143
|
-
assert_eq!(rows.len(), 32);
|
|
144
|
-
assert_eq!(
|
|
145
|
-
after.full_collection_materializations - before.full_collection_materializations,
|
|
146
|
-
1
|
|
147
|
-
);
|
|
148
|
-
assert_eq!(
|
|
149
|
-
after.full_collection_records_cloned - before.full_collection_records_cloned,
|
|
150
|
-
32,
|
|
151
|
-
"listing a collection clones every record in it"
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
#[test]
|
|
156
|
-
fn a_scan_result_survives_concurrent_mutation() {
|
|
157
|
-
let _serial = exclusive();
|
|
158
|
-
let (_directory, db) = seeded(200);
|
|
159
|
-
|
|
160
|
-
let matches = db
|
|
161
|
-
.query_collection("items", None, |row| {
|
|
162
|
-
row.value.get("tenant") == Some(&json!("tenant-0"))
|
|
163
|
-
})
|
|
164
|
-
.expect("scan");
|
|
165
|
-
|
|
166
|
-
// The scan returns owned records, so mutation after the lock is released
|
|
167
|
-
// cannot invalidate or rewrite what the caller already holds.
|
|
168
|
-
for index in 0..200 {
|
|
169
|
-
db.delete(&format!("items:record-{index:05}"))
|
|
170
|
-
.expect("delete");
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
assert_eq!(matches.len(), 50);
|
|
174
|
-
assert!(matches
|
|
175
|
-
.iter()
|
|
176
|
-
.all(|row| row.value.get("tenant") == Some(&json!("tenant-0"))));
|
|
177
|
-
assert!(db
|
|
178
|
-
.query_collection("items", None, |_| true)
|
|
179
|
-
.expect("scan")
|
|
180
|
-
.is_empty());
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/// PR35 addition: the indexed execution must not reach the materializing path.
|
|
184
|
-
///
|
|
185
|
-
/// PR34's claim was that a bounded query never enters `list_collection`. PR35
|
|
186
|
-
/// adds a second execution, and an optimization that quietly fell back into a
|
|
187
|
-
/// whole-collection clone would satisfy every correctness test in this
|
|
188
|
-
/// repository while undoing the thing PR34 established. So the property is
|
|
189
|
-
/// re-asserted against the execution that did not exist when it was first
|
|
190
|
-
/// proved: indexed execution materializes nothing, and does not scan either.
|
|
191
|
-
#[test]
|
|
192
|
-
fn an_indexed_query_neither_materializes_nor_scans_the_collection() {
|
|
193
|
-
let _serial = exclusive();
|
|
194
|
-
let (_directory, db) = seeded(400);
|
|
195
|
-
db.create_equality_index("items", "tenant")
|
|
196
|
-
.expect("declare index");
|
|
197
|
-
|
|
198
|
-
let before = query_execution_diagnostics::counters();
|
|
199
|
-
let tenant = json!("tenant-1");
|
|
200
|
-
let matches = db
|
|
201
|
-
.query_collection_by_equality("items", &[("tenant", &tenant)], |row| {
|
|
202
|
-
row.value.get("tenant") == Some(&json!("tenant-1"))
|
|
203
|
-
})
|
|
204
|
-
.expect("indexed query")
|
|
205
|
-
.expect("the field is indexed");
|
|
206
|
-
let after = query_execution_diagnostics::counters();
|
|
207
|
-
|
|
208
|
-
assert_eq!(matches.len(), 100, "one quarter of the collection matches");
|
|
209
|
-
assert_eq!(
|
|
210
|
-
after.full_collection_materializations - before.full_collection_materializations,
|
|
211
|
-
0,
|
|
212
|
-
"indexed execution must not enter the full-collection materialization path",
|
|
213
|
-
);
|
|
214
|
-
assert_eq!(
|
|
215
|
-
after.collection_scans - before.collection_scans,
|
|
216
|
-
0,
|
|
217
|
-
"indexed execution is not a scan",
|
|
218
|
-
);
|
|
219
|
-
assert_eq!(
|
|
220
|
-
after.scan_records_visited - before.scan_records_visited,
|
|
221
|
-
0,
|
|
222
|
-
"and therefore visits no record by traversal",
|
|
223
|
-
);
|
|
224
|
-
assert_eq!(
|
|
225
|
-
after.queries_indexed - before.queries_indexed,
|
|
226
|
-
1,
|
|
227
|
-
"the query is attributed to the indexed execution",
|
|
228
|
-
);
|
|
229
|
-
assert_eq!(
|
|
230
|
-
after.records_predicate_evaluated - before.records_predicate_evaluated,
|
|
231
|
-
100,
|
|
232
|
-
"the predicate runs against the candidate set, not the collection",
|
|
233
|
-
);
|
|
234
|
-
}
|