mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-07-10 01:38:44 +00:00
fix: add patches README and fix rust formatting
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
1f7d8e6001
commit
b1ff59da22
9 changed files with 363 additions and 189 deletions
|
|
@ -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<i32>),
|
||||
name!(child_ids, Vec<i32>),
|
||||
)> {
|
||||
) -> 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<i32>),
|
||||
name!(child_ids, Vec<i32>),
|
||||
),
|
||||
> {
|
||||
// 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<i32>),
|
||||
name!(sink_nodes, Vec<i32>),
|
||||
name!(cut_capacity, f64),
|
||||
name!(parallelization_opportunity, bool),
|
||||
)> {
|
||||
) -> TableIterator<
|
||||
'static,
|
||||
(
|
||||
name!(cut_id, i32),
|
||||
name!(source_nodes, Vec<i32>),
|
||||
name!(sink_nodes, Vec<i32>),
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Vec<f64>> {
|
||||
fn dag_attention_matrix(query_text: &str, mechanism: default!(&str, "auto")) -> Vec<Vec<f64>> {
|
||||
// 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();
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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<DagState> = 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);
|
||||
}
|
||||
|
|
|
|||
47
patches/README.md
Normal file
47
patches/README.md
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue