From b1ff59da222b573c18e11644c588d5a73ac1a8a3 Mon Sep 17 00:00:00 2001 From: rUv Date: Tue, 30 Dec 2025 15:41:45 +0000 Subject: [PATCH] fix: add patches README and fix rust formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add README.md to patches/ explaining the critical hnsw_rs patch - Run cargo fmt on ruvector-postgres to fix formatting issues The patches/hnsw_rs directory is REQUIRED for builds as it provides a WASM-compatible version of hnsw_rs (using rand 0.8 instead of 0.9). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../src/dag/functions/analysis.rs | 181 +++++++++++------- .../src/dag/functions/attention.rs | 119 ++++++------ .../src/dag/functions/config.rs | 34 +++- .../src/dag/functions/mod.rs | 8 +- .../src/dag/functions/qudag.rs | 6 +- .../src/dag/functions/status.rs | 138 ++++++++----- crates/ruvector-postgres/src/dag/mod.rs | 4 +- crates/ruvector-postgres/src/dag/state.rs | 15 +- patches/README.md | 47 +++++ 9 files changed, 363 insertions(+), 189 deletions(-) create mode 100644 patches/README.md diff --git a/crates/ruvector-postgres/src/dag/functions/analysis.rs b/crates/ruvector-postgres/src/dag/functions/analysis.rs index 0fc22215f..c03abefdc 100644 --- a/crates/ruvector-postgres/src/dag/functions/analysis.rs +++ b/crates/ruvector-postgres/src/dag/functions/analysis.rs @@ -6,15 +6,18 @@ use pgrx::prelude::*; #[pg_extern] fn dag_analyze_plan( query_text: &str, -) -> TableIterator<'static, ( - name!(node_id, i32), - name!(operator_type, String), - name!(criticality, f64), - name!(bottleneck_score, f64), - name!(estimated_cost, f64), - name!(parent_ids, Vec), - name!(child_ids, Vec), -)> { +) -> TableIterator< + 'static, + ( + name!(node_id, i32), + name!(operator_type, String), + name!(criticality, f64), + name!(bottleneck_score, f64), + name!(estimated_cost, f64), + name!(parent_ids, Vec), + name!(child_ids, Vec), + ), +> { // Parse and plan the query using PostgreSQL's EXPLAIN let plan_json = Spi::connect(|client| { let query = format!("EXPLAIN (FORMAT JSON) {}", query_text); @@ -47,13 +50,16 @@ fn dag_analyze_plan( #[pg_extern] fn dag_critical_path( query_text: &str, -) -> TableIterator<'static, ( - name!(path_position, i32), - name!(node_id, i32), - name!(operator_type, String), - name!(accumulated_cost, f64), - name!(attention_weight, f64), -)> { +) -> TableIterator< + 'static, + ( + name!(path_position, i32), + name!(node_id, i32), + name!(operator_type, String), + name!(accumulated_cost, f64), + name!(attention_weight, f64), + ), +> { // Analyze query and compute critical path // This would use topological attention mechanism let results = vec![ @@ -70,23 +76,45 @@ fn dag_critical_path( fn dag_bottlenecks( query_text: &str, threshold: default!(f64, 0.7), -) -> TableIterator<'static, ( - name!(node_id, i32), - name!(operator_type, String), - name!(bottleneck_score, f64), - name!(impact_estimate, f64), - name!(suggested_action, String), -)> { +) -> TableIterator< + 'static, + ( + name!(node_id, i32), + name!(operator_type, String), + name!(bottleneck_score, f64), + name!(impact_estimate, f64), + name!(suggested_action, String), + ), +> { // Analyze query for bottlenecks // This would identify nodes with high cost relative to their position let all_results = vec![ - (0, "SeqScan".to_string(), 0.85, 85.0, "Consider adding index on scanned column".to_string()), - (1, "HashJoin".to_string(), 0.65, 45.0, "Check join selectivity".to_string()), - (3, "Sort".to_string(), 0.72, 60.0, "Increase work_mem or add index".to_string()), + ( + 0, + "SeqScan".to_string(), + 0.85, + 85.0, + "Consider adding index on scanned column".to_string(), + ), + ( + 1, + "HashJoin".to_string(), + 0.65, + 45.0, + "Check join selectivity".to_string(), + ), + ( + 3, + "Sort".to_string(), + 0.72, + 60.0, + "Increase work_mem or add index".to_string(), + ), ]; // Filter by threshold - let filtered: Vec<_> = all_results.into_iter() + let filtered: Vec<_> = all_results + .into_iter() .filter(|r| r.2 >= threshold) .collect(); @@ -97,13 +125,16 @@ fn dag_bottlenecks( #[pg_extern] fn dag_mincut_analysis( query_text: &str, -) -> TableIterator<'static, ( - name!(cut_id, i32), - name!(source_nodes, Vec), - name!(sink_nodes, Vec), - name!(cut_capacity, f64), - name!(parallelization_opportunity, bool), -)> { +) -> TableIterator< + 'static, + ( + name!(cut_id, i32), + name!(source_nodes, Vec), + name!(sink_nodes, Vec), + name!(cut_capacity, f64), + name!(parallelization_opportunity, bool), + ), +> { // Compute min-cut analysis to identify parallelization opportunities // This would use the mincut-gated attention mechanism let results = vec![ @@ -118,28 +149,47 @@ fn dag_mincut_analysis( #[pg_extern] fn dag_suggest_optimizations( query_text: &str, -) -> TableIterator<'static, ( - name!(suggestion_id, i32), - name!(category, String), - name!(description, String), - name!(expected_improvement, f64), - name!(confidence, f64), -)> { +) -> TableIterator< + 'static, + ( + name!(suggestion_id, i32), + name!(category, String), + name!(description, String), + name!(expected_improvement, f64), + name!(confidence, f64), + ), +> { // Generate optimization suggestions using learned patterns // This would query the SONA engine's learned patterns let results = vec![ - (0, "index".to_string(), - "Add B-tree index on users(created_at) for time-range queries".to_string(), - 0.35, 0.85), - (1, "join_order".to_string(), - "Reorder joins: filter users first, then join with orders".to_string(), - 0.25, 0.78), - (2, "statistics".to_string(), - "Run ANALYZE on 'orders' table - statistics are 7 days old".to_string(), - 0.15, 0.92), - (3, "work_mem".to_string(), - "Increase work_mem to 16MB for this session to avoid disk sorts".to_string(), - 0.18, 0.70), + ( + 0, + "index".to_string(), + "Add B-tree index on users(created_at) for time-range queries".to_string(), + 0.35, + 0.85, + ), + ( + 1, + "join_order".to_string(), + "Reorder joins: filter users first, then join with orders".to_string(), + 0.25, + 0.78, + ), + ( + 2, + "statistics".to_string(), + "Run ANALYZE on 'orders' table - statistics are 7 days old".to_string(), + 0.15, + 0.92, + ), + ( + 3, + "work_mem".to_string(), + "Increase work_mem to 16MB for this session to avoid disk sorts".to_string(), + 0.18, + 0.70, + ), ]; TableIterator::new(results) @@ -149,12 +199,15 @@ fn dag_suggest_optimizations( #[pg_extern] fn dag_estimate( query_text: &str, -) -> TableIterator<'static, ( - name!(metric, String), - name!(postgres_estimate, f64), - name!(neural_estimate, f64), - name!(confidence, f64), -)> { +) -> TableIterator< + 'static, + ( + name!(metric, String), + name!(postgres_estimate, f64), + name!(neural_estimate, f64), + name!(confidence, f64), + ), +> { // Compare PostgreSQL's estimates with neural predictions // This would use the SONA engine to predict actual runtime let results = vec![ @@ -169,11 +222,7 @@ fn dag_estimate( /// Compare actual execution with predictions and update learning #[pg_extern] -fn dag_learn_from_execution( - query_text: &str, - actual_time_ms: f64, - actual_rows: i64, -) -> String { +fn dag_learn_from_execution(query_text: &str, actual_time_ms: f64, actual_rows: i64) -> String { // Record actual execution metrics for learning // This would update the SONA engine's patterns @@ -185,7 +234,9 @@ fn dag_learn_from_execution( format!( "Recorded execution: {}ms, {} rows. Pattern updated. Estimated improvement: {:.1}%", - actual_time_ms, actual_rows, improvement * 100.0 + actual_time_ms, + actual_rows, + improvement * 100.0 ) } diff --git a/crates/ruvector-postgres/src/dag/functions/attention.rs b/crates/ruvector-postgres/src/dag/functions/attention.rs index 8a063ed62..e0a807ea5 100644 --- a/crates/ruvector-postgres/src/dag/functions/attention.rs +++ b/crates/ruvector-postgres/src/dag/functions/attention.rs @@ -7,44 +7,34 @@ use pgrx::prelude::*; fn dag_attention_scores( query_text: &str, mechanism: default!(&str, "auto"), -) -> TableIterator<'static, ( - name!(node_id, i32), - name!(attention_weight, f64), -)> { +) -> TableIterator<'static, (name!(node_id, i32), name!(attention_weight, f64))> { // Validate mechanism let valid = [ - "topological", "causal_cone", "critical_path", - "mincut_gated", "hierarchical_lorentz", - "parallel_branch", "temporal_btsp", "auto" + "topological", + "causal_cone", + "critical_path", + "mincut_gated", + "hierarchical_lorentz", + "parallel_branch", + "temporal_btsp", + "auto", ]; if !valid.contains(&mechanism) { - pgrx::error!("Invalid attention mechanism: '{}'. Valid: {:?}", mechanism, valid); + pgrx::error!( + "Invalid attention mechanism: '{}'. Valid: {:?}", + mechanism, + valid + ); } // Compute attention scores based on the selected mechanism // This would integrate with ruvector-attention crate let results = match mechanism { - "topological" => vec![ - (0, 0.45), - (1, 0.35), - (2, 0.20), - ], - "causal_cone" => vec![ - (0, 0.50), - (1, 0.30), - (2, 0.20), - ], - "critical_path" => vec![ - (0, 0.60), - (1, 0.25), - (2, 0.15), - ], - _ => vec![ - (0, 0.40), - (1, 0.35), - (2, 0.25), - ], + "topological" => vec![(0, 0.45), (1, 0.35), (2, 0.20)], + "causal_cone" => vec![(0, 0.50), (1, 0.30), (2, 0.20)], + "critical_path" => vec![(0, 0.60), (1, 0.25), (2, 0.15)], + _ => vec![(0, 0.40), (1, 0.35), (2, 0.25)], }; TableIterator::new(results) @@ -52,10 +42,7 @@ fn dag_attention_scores( /// Get attention matrix for visualization (node-to-node attention) #[pg_extern] -fn dag_attention_matrix( - query_text: &str, - mechanism: default!(&str, "auto"), -) -> Vec> { +fn dag_attention_matrix(query_text: &str, mechanism: default!(&str, "auto")) -> Vec> { // Compute full attention matrix (NxN where N is number of nodes) // Each entry [i,j] represents attention from node i to node j @@ -109,7 +96,8 @@ fn dag_attention_visualize( ], "mechanism": mechanism, "critical_path": [0, 1, 2, 3] - }).to_string() + }) + .to_string() } "ascii" => { // ASCII art for terminal display @@ -133,7 +121,8 @@ Query Plan with Attention Weights (topological) (users) (High Attention) Legend: Higher numbers = More critical to optimize -"#.to_string() +"# + .to_string() } "mermaid" => { // Mermaid syntax for markdown rendering @@ -147,20 +136,21 @@ graph BT style B fill:#feca57,stroke:#333,stroke-width:2px style C fill:#48dbfb,stroke:#333,stroke-width:1.5px style D fill:#1dd1a1,stroke:#333,stroke-width:1px -```"#.to_string() +```"# + .to_string() } _ => { - pgrx::error!("Invalid format: '{}'. Use 'dot', 'json', 'ascii', or 'mermaid'", format); + pgrx::error!( + "Invalid format: '{}'. Use 'dot', 'json', 'ascii', or 'mermaid'", + format + ); } } } /// Configure attention hyperparameters for a specific mechanism #[pg_extern] -fn dag_attention_configure( - mechanism: &str, - params: pgrx::JsonB, -) { +fn dag_attention_configure(mechanism: &str, params: pgrx::JsonB) { let params_value = params.0; // Validate and extract parameters based on mechanism @@ -205,18 +195,24 @@ fn dag_attention_configure( // Store configuration crate::dag::state::DAG_STATE.set_attention_params(mechanism, params_value); - pgrx::notice!("Configured attention mechanism '{}' with provided parameters", mechanism); + pgrx::notice!( + "Configured attention mechanism '{}' with provided parameters", + mechanism + ); } /// Get attention mechanism statistics #[pg_extern] -fn dag_attention_stats() -> TableIterator<'static, ( - name!(mechanism, String), - name!(invocations, i64), - name!(avg_latency_us, f64), - name!(hit_rate, f64), - name!(improvement_ratio, f64), -)> { +fn dag_attention_stats() -> TableIterator< + 'static, + ( + name!(mechanism, String), + name!(invocations, i64), + name!(avg_latency_us, f64), + name!(hit_rate, f64), + name!(improvement_ratio, f64), + ), +> { // Get statistics from state // This would track performance of different attention mechanisms let results = vec![ @@ -235,18 +231,25 @@ fn dag_attention_stats() -> TableIterator<'static, ( fn dag_attention_benchmark( query_text: &str, iterations: default!(i32, 100), -) -> TableIterator<'static, ( - name!(mechanism, String), - name!(avg_time_us, f64), - name!(min_time_us, f64), - name!(max_time_us, f64), - name!(std_dev_us, f64), -)> { +) -> TableIterator< + 'static, + ( + name!(mechanism, String), + name!(avg_time_us, f64), + name!(min_time_us, f64), + name!(max_time_us, f64), + name!(std_dev_us, f64), + ), +> { // Benchmark each attention mechanism let mechanisms = [ - "topological", "causal_cone", "critical_path", - "mincut_gated", "hierarchical_lorentz", - "parallel_branch", "temporal_btsp" + "topological", + "causal_cone", + "critical_path", + "mincut_gated", + "hierarchical_lorentz", + "parallel_branch", + "temporal_btsp", ]; let mut results = Vec::new(); diff --git a/crates/ruvector-postgres/src/dag/functions/config.rs b/crates/ruvector-postgres/src/dag/functions/config.rs index 336009fa4..f13577c55 100644 --- a/crates/ruvector-postgres/src/dag/functions/config.rs +++ b/crates/ruvector-postgres/src/dag/functions/config.rs @@ -28,15 +28,21 @@ fn dag_set_learning_rate(rate: f64) { #[pg_extern] fn dag_set_attention(mechanism: &str) { let valid_mechanisms = [ - "topological", "causal_cone", "critical_path", - "mincut_gated", "hierarchical_lorentz", - "parallel_branch", "temporal_btsp", "auto" + "topological", + "causal_cone", + "critical_path", + "mincut_gated", + "hierarchical_lorentz", + "parallel_branch", + "temporal_btsp", + "auto", ]; if !valid_mechanisms.contains(&mechanism) { pgrx::error!( "Invalid attention mechanism '{}'. Valid options: {:?}", - mechanism, valid_mechanisms + mechanism, + valid_mechanisms ); } @@ -54,16 +60,25 @@ fn dag_configure_sona( ) { // Validation if !(1..=4).contains(µ_lora_rank) { - pgrx::error!("micro_lora_rank must be between 1 and 4, got {}", micro_lora_rank); + pgrx::error!( + "micro_lora_rank must be between 1 and 4, got {}", + micro_lora_rank + ); } if !(4..=16).contains(&base_lora_rank) { - pgrx::error!("base_lora_rank must be between 4 and 16, got {}", base_lora_rank); + pgrx::error!( + "base_lora_rank must be between 4 and 16, got {}", + base_lora_rank + ); } if ewc_lambda < 0.0 { pgrx::error!("ewc_lambda must be non-negative, got {}", ewc_lambda); } if !(10..=1000).contains(&pattern_clusters) { - pgrx::error!("pattern_clusters must be between 10 and 1000, got {}", pattern_clusters); + pgrx::error!( + "pattern_clusters must be between 10 and 1000, got {}", + pattern_clusters + ); } // Store in state @@ -129,7 +144,10 @@ mod tests { #[pg_test] fn test_dag_set_attention() { dag_set_attention("topological"); - assert_eq!(crate::dag::state::DAG_STATE.get_attention_mechanism(), "topological"); + assert_eq!( + crate::dag::state::DAG_STATE.get_attention_mechanism(), + "topological" + ); } #[pg_test] diff --git a/crates/ruvector-postgres/src/dag/functions/mod.rs b/crates/ruvector-postgres/src/dag/functions/mod.rs index ecb5ac43f..915ef9219 100644 --- a/crates/ruvector-postgres/src/dag/functions/mod.rs +++ b/crates/ruvector-postgres/src/dag/functions/mod.rs @@ -1,13 +1,13 @@ //! SQL function implementations for neural DAG learning -pub mod config; pub mod analysis; pub mod attention; -pub mod status; +pub mod config; pub mod qudag; +pub mod status; -pub use config::*; pub use analysis::*; pub use attention::*; -pub use status::*; +pub use config::*; pub use qudag::*; +pub use status::*; diff --git a/crates/ruvector-postgres/src/dag/functions/qudag.rs b/crates/ruvector-postgres/src/dag/functions/qudag.rs index ed48e8e23..76275ca54 100644 --- a/crates/ruvector-postgres/src/dag/functions/qudag.rs +++ b/crates/ruvector-postgres/src/dag/functions/qudag.rs @@ -182,11 +182,7 @@ fn qudag_create_proposal( /// Vote on proposal #[pg_extern] -fn qudag_vote( - proposal_id: &str, - vote_choice: &str, - stake_weight: f64, -) -> pgrx::JsonB { +fn qudag_vote(proposal_id: &str, vote_choice: &str, stake_weight: f64) -> pgrx::JsonB { let choice = match vote_choice.to_lowercase().as_str() { "for" | "yes" => "for", "against" | "no" => "against", diff --git a/crates/ruvector-postgres/src/dag/functions/status.rs b/crates/ruvector-postgres/src/dag/functions/status.rs index b0caf448d..b900c6c9f 100644 --- a/crates/ruvector-postgres/src/dag/functions/status.rs +++ b/crates/ruvector-postgres/src/dag/functions/status.rs @@ -24,12 +24,15 @@ fn dag_status() -> pgrx::JsonB { /// Run comprehensive health check on all components #[pg_extern] -fn dag_health_check() -> TableIterator<'static, ( - name!(component, String), - name!(status, String), - name!(last_check, pgrx::TimestampWithTimeZone), - name!(message, String), -)> { +fn dag_health_check() -> TableIterator< + 'static, + ( + name!(component, String), + name!(status, String), + name!(last_check, pgrx::TimestampWithTimeZone), + name!(message, String), + ), +> { let now = pgrx::TimestampWithTimeZone::now(); let state = &crate::dag::state::DAG_STATE; @@ -40,25 +43,30 @@ fn dag_health_check() -> TableIterator<'static, ( "sona_engine".to_string(), "healthy".to_string(), now, - "Operating normally with 1024 learned patterns".to_string() + "Operating normally with 1024 learned patterns".to_string(), ), ( "attention_cache".to_string(), - if cache_hit_rate > 0.7 { "healthy" } else { "degraded" }.to_string(), + if cache_hit_rate > 0.7 { + "healthy" + } else { + "degraded" + } + .to_string(), now, - format!("{:.1}% hit rate", cache_hit_rate * 100.0) + format!("{:.1}% hit rate", cache_hit_rate * 100.0), ), ( "trajectory_buffer".to_string(), "healthy".to_string(), now, - format!("{} trajectories stored", state.get_trajectory_count()) + format!("{} trajectories stored", state.get_trajectory_count()), ), ( "pattern_store".to_string(), "healthy".to_string(), now, - format!("{} patterns in memory", state.get_pattern_count()) + format!("{} patterns in memory", state.get_pattern_count()), ), ]; @@ -67,13 +75,16 @@ fn dag_health_check() -> TableIterator<'static, ( /// Get latency breakdown by component #[pg_extern] -fn dag_latency_breakdown() -> TableIterator<'static, ( - name!(component, String), - name!(p50_us, f64), - name!(p95_us, f64), - name!(p99_us, f64), - name!(max_us, f64), -)> { +fn dag_latency_breakdown() -> TableIterator< + 'static, + ( + name!(component, String), + name!(p50_us, f64), + name!(p95_us, f64), + name!(p99_us, f64), + name!(max_us, f64), + ), +> { // Return latency percentiles for each component // In a real implementation, this would track actual measurements let results = vec![ @@ -81,7 +92,13 @@ fn dag_latency_breakdown() -> TableIterator<'static, ( ("pattern_lookup".to_string(), 1450.0, 2850.0, 4800.0, 9500.0), ("micro_lora".to_string(), 48.0, 78.0, 92.0, 98.0), ("embedding".to_string(), 125.0, 280.0, 450.0, 750.0), - ("total_overhead".to_string(), 1580.0, 3100.0, 5200.0, 10500.0), + ( + "total_overhead".to_string(), + 1580.0, + 3100.0, + 5200.0, + 10500.0, + ), ]; TableIterator::new(results) @@ -89,17 +106,30 @@ fn dag_latency_breakdown() -> TableIterator<'static, ( /// Get memory usage by component #[pg_extern] -fn dag_memory_usage() -> TableIterator<'static, ( - name!(component, String), - name!(allocated_bytes, i64), - name!(used_bytes, i64), - name!(peak_bytes, i64), -)> { +fn dag_memory_usage() -> TableIterator< + 'static, + ( + name!(component, String), + name!(allocated_bytes, i64), + name!(used_bytes, i64), + name!(peak_bytes, i64), + ), +> { // Return memory usage statistics // In a real implementation, this would track actual allocations let results = vec![ - ("attention_cache".to_string(), 10_485_760, 8_912_384, 10_223_616), - ("pattern_store".to_string(), 52_428_800, 44_040_192, 50_331_648), + ( + "attention_cache".to_string(), + 10_485_760, + 8_912_384, + 10_223_616, + ), + ( + "pattern_store".to_string(), + 52_428_800, + 44_040_192, + 50_331_648, + ), ("trajectory_buffer".to_string(), 1_048_576, 439_296, 996_147), ("embeddings".to_string(), 26_214_400, 23_068_672, 25_690_112), ("sona_weights".to_string(), 4_194_304, 4_194_304, 4_194_304), @@ -110,19 +140,38 @@ fn dag_memory_usage() -> TableIterator<'static, ( /// Get general statistics #[pg_extern] -fn dag_statistics() -> TableIterator<'static, ( - name!(metric, String), - name!(value, f64), - name!(unit, String), -)> { +fn dag_statistics() -> TableIterator< + 'static, + ( + name!(metric, String), + name!(value, f64), + name!(unit, String), + ), +> { let state = &crate::dag::state::DAG_STATE; let results = vec![ ("queries_analyzed".to_string(), 12847.0, "count".to_string()), - ("patterns_learned".to_string(), state.get_pattern_count() as f64, "count".to_string()), - ("trajectories_recorded".to_string(), state.get_trajectory_count() as f64, "count".to_string()), - ("avg_improvement".to_string(), state.get_avg_improvement(), "ratio".to_string()), - ("cache_hit_rate".to_string(), state.get_cache_hit_rate(), "ratio".to_string()), + ( + "patterns_learned".to_string(), + state.get_pattern_count() as f64, + "count".to_string(), + ), + ( + "trajectories_recorded".to_string(), + state.get_trajectory_count() as f64, + "count".to_string(), + ), + ( + "avg_improvement".to_string(), + state.get_avg_improvement(), + "ratio".to_string(), + ), + ( + "cache_hit_rate".to_string(), + state.get_cache_hit_rate(), + "ratio".to_string(), + ), ("learning_cycles".to_string(), 58.0, "count".to_string()), ("avg_query_speedup".to_string(), 1.15, "ratio".to_string()), ]; @@ -142,13 +191,16 @@ fn dag_reset_stats() -> String { #[pg_extern] fn dag_performance_history( time_window_minutes: default!(i32, 60), -) -> TableIterator<'static, ( - name!(timestamp, pgrx::TimestampWithTimeZone), - name!(queries_per_minute, f64), - name!(avg_improvement, f64), - name!(cache_hit_rate, f64), - name!(patterns_learned, i32), -)> { +) -> TableIterator< + 'static, + ( + name!(timestamp, pgrx::TimestampWithTimeZone), + name!(queries_per_minute, f64), + name!(avg_improvement, f64), + name!(cache_hit_rate, f64), + name!(patterns_learned, i32), + ), +> { // Return historical performance data // In a real implementation, this would query a time-series buffer let now = pgrx::TimestampWithTimeZone::now(); diff --git a/crates/ruvector-postgres/src/dag/mod.rs b/crates/ruvector-postgres/src/dag/mod.rs index d5cddf2e0..b4b8b11b9 100644 --- a/crates/ruvector-postgres/src/dag/mod.rs +++ b/crates/ruvector-postgres/src/dag/mod.rs @@ -3,7 +3,7 @@ //! This module integrates the SONA (Scalable On-device Neural Adaptation) engine //! with PostgreSQL's query planner to provide learned query optimization. -pub mod state; pub mod functions; +pub mod state; -pub use state::{DAG_STATE, DagState, DagConfig}; +pub use state::{DagConfig, DagState, DAG_STATE}; diff --git a/crates/ruvector-postgres/src/dag/state.rs b/crates/ruvector-postgres/src/dag/state.rs index b9be08d2a..382a8ed89 100644 --- a/crates/ruvector-postgres/src/dag/state.rs +++ b/crates/ruvector-postgres/src/dag/state.rs @@ -3,9 +3,9 @@ //! This module manages the global state for the neural DAG learning system, //! including configuration, metrics, and statistics. -use std::sync::{Arc, Mutex}; use once_cell::sync::Lazy; use serde_json::Value; +use std::sync::{Arc, Mutex}; /// Global DAG state singleton pub static DAG_STATE: Lazy = Lazy::new(DagState::default); @@ -91,8 +91,13 @@ impl DagState { } /// Configure SONA parameters - pub fn configure_sona(&self, micro_lora_rank: i32, base_lora_rank: i32, - ewc_lambda: f64, pattern_clusters: i32) { + pub fn configure_sona( + &self, + micro_lora_rank: i32, + base_lora_rank: i32, + ewc_lambda: f64, + pattern_clusters: i32, + ) { let mut inner = self.inner.lock().unwrap(); inner.micro_lora_rank = micro_lora_rank; inner.base_lora_rank = base_lora_rank; @@ -133,7 +138,9 @@ impl DagState { /// Set attention parameters for a mechanism pub fn set_attention_params(&self, mechanism: &str, params: Value) { - self.inner.lock().unwrap() + self.inner + .lock() + .unwrap() .attention_params .insert(mechanism.to_string(), params); } diff --git a/patches/README.md b/patches/README.md new file mode 100644 index 000000000..ab0bed43c --- /dev/null +++ b/patches/README.md @@ -0,0 +1,47 @@ +# Patches Directory + +**CRITICAL: Do not delete this directory or its contents!** + +This directory contains patched versions of external crates that are necessary for building RuVector. + +## hnsw_rs + +The `hnsw_rs` directory contains a patched version of the [hnsw_rs](https://crates.io/crates/hnsw_rs) crate. + +### Why this patch exists + +The official hnsw_rs crate uses `rand 0.9` which is **incompatible with WebAssembly (WASM)** builds. This patched version: + +1. Uses `rand 0.8` instead of `rand 0.9` for WASM compatibility +2. Uses Rust edition 2021 (not 2024) for stable Rust toolchain compatibility + +### How it's used + +The patch is applied via `Cargo.toml` at the workspace root: + +```toml +[patch.crates-io] +hnsw_rs = { path = "./patches/hnsw_rs" } +``` + +This ensures all workspace crates that depend on `hnsw_rs` use this patched version. + +### What depends on it + +- `ruvector-core` (with `hnsw` feature enabled by default) +- `ruvector-graph` (with `hnsw_rs` feature) +- All native builds (Node.js bindings, CLI tools) + +### Consequences of deletion + +If this directory is deleted: +- **All CI builds will fail** (Build Native Modules, PostgreSQL Extension CI, etc.) +- `cargo build` will fail with "failed to load source for dependency `hnsw_rs`" +- The project cannot be compiled + +### Updating the patch + +If you need to update hnsw_rs: +1. Download the new version from crates.io +2. Apply the rand 0.8 compatibility changes from the current patch +3. Test WASM and native builds before committing