Skip to content

Commit cc9e703

Browse files
committed
feature-gate embedding,autotune,external-indexing jobs in daemon, so no additional dependencies will be compiled if the code is not used. Review all dependencies for lantern-cli in Cargo.toml and mark optional based on features that needs them
1 parent 475d861 commit cc9e703

File tree

13 files changed

+330
-273
lines changed

13 files changed

+330
-273
lines changed

lantern_cli/Cargo.toml

+20-21
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ path = "src/main.rs"
1212
[dependencies]
1313
clap = { version = "4.5.20", features = ["derive"] }
1414
anyhow = "1.0.91"
15-
postgres = "0.19.9"
15+
postgres = { version = "0.19.9", optional = true }
1616
rand = "0.8.5"
1717
linfa-clustering = { version = "0.7.0", features = ["ndarray-linalg"], optional = true }
1818
linfa = {version = "0.7.0", optional = true}
19-
ndarray = { version = "0.15.6", features = ["rayon"] }
19+
ndarray = { version = "0.15.6", features = ["rayon"], optional = true }
2020
rayon = { version="1.10.0", optional = true }
2121
md5 = {version="0.7.0", optional = true }
2222
serde = { version = "1.0", features = ["derive"] }
@@ -27,19 +27,18 @@ futures = "0.3.31"
2727
tokio = { version = "1.41.0", features = ["full"] }
2828
lazy_static = "1.5.0"
2929
itertools = "0.13.0"
30-
csv = "1.3.0"
31-
sysinfo = "0.32.0"
32-
tiktoken-rs = "0.6.0"
33-
url = "2.5"
34-
num_cpus = "1.16.0"
35-
ort = { version = "1.16.3", features = ["load-dynamic", "cuda", "openvino"] }
36-
tokenizers = { version = "0.20.1", features = ["default"] }
37-
image = { version = "0.25.4", features = ["jpeg", "png", "webp" ]}
38-
nvml-wrapper = "0.10.0"
39-
strum = { version = "0.26", features = ["derive"] }
40-
regex = "1.11.1"
41-
postgres-types = { version = "0.2.8", features = ["derive"] }
42-
usearch = { git = "https://github.com/Ngalstyan4/usearch.git", rev = "aa4f91d21230fd611b6c7741fa06be8c20acc9a9" }
30+
sysinfo = { version = "0.32.0", optional = true }
31+
tiktoken-rs = { version = "0.6.0", optional = true }
32+
url = { version = "2.5", optional = true }
33+
num_cpus = { version = "1.16.0", optional = true }
34+
ort = { version = "1.16.3", features = ["load-dynamic", "cuda", "openvino"], optional = true }
35+
tokenizers = { version = "0.20.1", features = ["default"], optional = true }
36+
image = { version = "0.25.4", features = ["jpeg", "png", "webp" ], optional = true }
37+
nvml-wrapper = { version = "0.10.0", optional = true }
38+
strum = { version = "0.26", features = ["derive"], optional = true }
39+
regex = { version = "1.11.1", optional = true }
40+
postgres-types = { version = "0.2.8", features = ["derive"], optional = true }
41+
usearch = { git = "https://github.com/Ngalstyan4/usearch.git", rev = "aa4f91d21230fd611b6c7741fa06be8c20acc9a9", optional = true }
4342
actix-web = { version = "4.9.0", optional = true }
4443
env_logger = { version = "0.11.5", optional = true }
4544
deadpool-postgres = { version = "0.14.0", optional = true }
@@ -53,18 +52,18 @@ bitvec = { version="1.0.1", optional=true }
5352
rustls = { version="0.23.16", optional=true }
5453
rustls-pemfile = { version="2.2.0", optional=true }
5554
glob = { version="0.3.1", optional=true }
56-
reqwest = { version = "0.12.9", default-features = false, features = ["json", "blocking", "rustls-tls"] }
55+
reqwest = { version = "0.12.9", default-features = false, features = ["json", "blocking", "rustls-tls"], optional = true }
5756

5857
[features]
5958
default = ["cli", "daemon", "http-server", "autotune", "pq", "external-index", "external-index-server", "embeddings"]
6059
daemon = ["dep:tokio-postgres"]
61-
http-server = ["dep:deadpool-postgres", "dep:deadpool", "dep:bytes", "dep:utoipa", "dep:utoipa-swagger-ui", "dep:actix-web", "dep:tokio-postgres", "dep:env_logger", "dep:actix-web-httpauth"]
60+
http-server = ["dep:deadpool-postgres", "dep:deadpool", "dep:bytes", "dep:utoipa", "dep:utoipa-swagger-ui", "dep:actix-web", "dep:tokio-postgres", "dep:env_logger", "dep:actix-web-httpauth", "dep:regex"]
6261
autotune = []
63-
pq = ["dep:gcp_auth", "dep:linfa", "dep:linfa-clustering", "dep:md5", "dep:rayon"]
62+
pq = ["dep:gcp_auth", "dep:linfa", "dep:linfa-clustering", "dep:md5", "dep:rayon", "dep:reqwest", "dep:postgres", "dep:ndarray"]
6463
cli = []
65-
external-index = []
66-
external-index-server = ["dep:bitvec", "dep:rustls", "dep:rustls-pemfile", "dep:glob"]
67-
embeddings = ["dep:bytes"]
64+
external-index = ["dep:postgres-types", "dep:usearch", "dep:postgres"]
65+
external-index-server = ["dep:bitvec", "dep:rustls", "dep:rustls-pemfile", "dep:glob", "dep:usearch"]
66+
embeddings = ["dep:bytes", "dep:sysinfo", "dep:tiktoken-rs", "dep:url", "dep:num_cpus", "dep:ort", "dep:tokenizers", "dep:image", "dep:nvml-wrapper", "dep:strum", "dep:regex", "dep:reqwest", "dep:ndarray"]
6867

6968
[lib]
7069
doctest = false

lantern_cli/src/cli.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use super::daemon::cli::DaemonArgs;
2-
use super::embeddings::cli::{EmbeddingArgs, MeasureModelSpeedArgs, ShowModelsArgs};
3-
use super::external_index::cli::CreateIndexArgs;
4-
use super::http_server::cli::HttpServerArgs;
5-
use super::index_autotune::cli::IndexAutotuneArgs;
6-
use super::pq::cli::PQArgs;
71
use clap::{Parser, Subcommand};
2+
use lantern_cli::daemon::cli::DaemonArgs;
3+
use lantern_cli::embeddings::cli::{EmbeddingArgs, MeasureModelSpeedArgs, ShowModelsArgs};
4+
use lantern_cli::external_index::cli::CreateIndexArgs;
85
use lantern_cli::external_index::cli::IndexServerArgs;
6+
use lantern_cli::http_server::cli::HttpServerArgs;
7+
use lantern_cli::index_autotune::cli::IndexAutotuneArgs;
8+
use lantern_cli::pq::cli::PQArgs;
99

1010
#[derive(Subcommand, Debug)]
1111
pub enum Commands {

lantern_cli/src/daemon/autotune_jobs.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use super::helpers::{
33
index_job_update_processor, remove_job_handle, set_job_handle, startup_hook,
44
};
55
use super::types::{
6-
AutotuneJob, AutotuneProcessorArgs, JobEvent, JobEventHandlersMap, JobInsertNotification,
7-
JobRunArgs, JobUpdateNotification,
6+
AutotuneProcessorArgs, JobEvent, JobEventHandlersMap, JobInsertNotification, JobRunArgs,
7+
JobUpdateNotification,
88
};
99
use crate::daemon::helpers::anyhow_wrap_connection;
1010
use crate::external_index::cli::UMetricKind;
@@ -20,7 +20,7 @@ use tokio::sync::{
2020
mpsc,
2121
mpsc::{Receiver, Sender, UnboundedReceiver, UnboundedSender},
2222
};
23-
use tokio_postgres::{Client, NoTls};
23+
use tokio_postgres::{Client, NoTls, Row};
2424
use tokio_util::sync::CancellationToken;
2525

2626
pub const JOB_TABLE_DEFINITION: &'static str = r#"
@@ -55,6 +55,41 @@ latency DOUBLE PRECISION NOT NULL,
5555
build_time DOUBLE PRECISION NULL
5656
"#;
5757

58+
#[derive(Debug)]
59+
pub struct AutotuneJob {
60+
pub id: i32,
61+
pub is_init: bool,
62+
pub db_uri: String,
63+
pub schema: String,
64+
pub table: String,
65+
pub column: String,
66+
pub metric_kind: String,
67+
pub model_name: Option<String>,
68+
pub recall: f64,
69+
pub k: u16,
70+
pub sample_size: usize,
71+
pub create_index: bool,
72+
}
73+
74+
impl AutotuneJob {
75+
pub fn new(row: Row, db_uri: &str) -> AutotuneJob {
76+
Self {
77+
id: row.get::<&str, i32>("id"),
78+
db_uri: db_uri.to_owned(),
79+
schema: row.get::<&str, String>("schema"),
80+
table: row.get::<&str, String>("table"),
81+
column: row.get::<&str, String>("column"),
82+
metric_kind: row.get::<&str, String>("metric_kind"),
83+
model_name: row.get::<&str, Option<String>>("model"),
84+
recall: row.get::<&str, f64>("target_recall"),
85+
k: row.get::<&str, i32>("k") as u16,
86+
sample_size: row.get::<&str, i32>("sample_size") as usize,
87+
create_index: row.get::<&str, bool>("create_index"),
88+
is_init: true,
89+
}
90+
}
91+
}
92+
5893
pub async fn autotune_job_processor(
5994
mut rx: Receiver<AutotuneProcessorArgs>,
6095
cancel_token: CancellationToken,

lantern_cli/src/daemon/embedding_jobs.rs

+107-6
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ use super::helpers::{
44
remove_job_handle, schedule_job_retry, set_job_handle, startup_hook,
55
};
66
use super::types::{
7-
ClientJobsMap, EmbeddingJob, EmbeddingProcessorArgs, JobBatchingHashMap, JobEvent,
8-
JobEventHandlersMap, JobInsertNotification, JobRunArgs, JobUpdateNotification,
7+
ClientJobsMap, EmbeddingProcessorArgs, JobBatchingHashMap, JobEvent, JobEventHandlersMap,
8+
JobInsertNotification, JobRunArgs, JobUpdateNotification,
99
};
1010
use crate::daemon::helpers::anyhow_wrap_connection;
11-
use crate::embeddings::cli::{EmbeddingArgs, EmbeddingJobType};
11+
use crate::embeddings::cli::{EmbeddingArgs, EmbeddingJobType, Runtime};
12+
use crate::embeddings::core::utils::get_clean_model_name;
1213
use crate::embeddings::get_default_batch_size;
1314
use crate::logger::Logger;
14-
use crate::utils::{get_common_embedding_ignore_filters, get_full_table_name, quote_ident};
15+
use crate::utils::{
16+
get_common_embedding_ignore_filters, get_full_table_name, quote_ident, quote_literal,
17+
};
1518
use crate::{embeddings, types::*};
19+
use itertools::Itertools;
1620
use std::collections::HashMap;
1721
use std::ops::Deref;
1822
use std::path::Path;
@@ -22,8 +26,7 @@ use std::time::SystemTime;
2226
use tokio::fs;
2327
use tokio::sync::mpsc::{Receiver, Sender, UnboundedReceiver, UnboundedSender};
2428
use tokio::sync::{mpsc, Mutex, RwLock};
25-
use tokio_postgres::types::ToSql;
26-
use tokio_postgres::{Client, NoTls};
29+
use tokio_postgres::{types::ToSql, Client, NoTls, Row};
2730
use tokio_util::sync::CancellationToken;
2831

2932
pub const JOB_TABLE_DEFINITION: &'static str = r#"
@@ -71,6 +74,104 @@ const EMB_USAGE_TABLE_NAME: &'static str = "embedding_usage_info";
7174
const EMB_FAILURE_TABLE_NAME: &'static str = "embedding_failure_info";
7275
const EMB_LOCK_TABLE_NAME: &'static str = "_lantern_emb_job_locks";
7376

77+
#[derive(Debug, Clone)]
78+
pub struct EmbeddingJob {
79+
pub id: i32,
80+
pub is_init: bool,
81+
pub db_uri: String,
82+
pub schema: String,
83+
pub table: String,
84+
pub column: String,
85+
pub pk: String,
86+
pub filter: Option<String>,
87+
pub label: Option<String>,
88+
pub job_type: EmbeddingJobType,
89+
pub column_type: String,
90+
pub out_column: String,
91+
pub model: String,
92+
pub runtime_params: String,
93+
pub runtime: Runtime,
94+
pub batch_size: Option<usize>,
95+
pub row_ids: Option<Vec<String>>,
96+
}
97+
98+
impl EmbeddingJob {
99+
pub fn new(row: Row, data_path: &str, db_uri: &str) -> Result<EmbeddingJob, anyhow::Error> {
100+
let runtime = Runtime::try_from(row.get::<&str, Option<&str>>("runtime").unwrap_or("ort"))?;
101+
let runtime_params = if runtime == Runtime::Ort {
102+
format!(r#"{{ "data_path": "{data_path}" }}"#)
103+
} else {
104+
row.get::<&str, Option<String>>("runtime_params")
105+
.unwrap_or("{}".to_owned())
106+
};
107+
108+
let batch_size = if let Some(batch_size) = row.get::<&str, Option<i32>>("batch_size") {
109+
Some(batch_size as usize)
110+
} else {
111+
None
112+
};
113+
114+
Ok(Self {
115+
id: row.get::<&str, i32>("id"),
116+
pk: row.get::<&str, String>("pk"),
117+
label: row.get::<&str, Option<String>>("label"),
118+
db_uri: db_uri.to_owned(),
119+
schema: row.get::<&str, String>("schema"),
120+
table: row.get::<&str, String>("table"),
121+
column: row.get::<&str, String>("column"),
122+
out_column: row.get::<&str, String>("dst_column"),
123+
model: get_clean_model_name(row.get::<&str, &str>("model"), runtime),
124+
runtime,
125+
runtime_params,
126+
filter: None,
127+
row_ids: None,
128+
is_init: true,
129+
batch_size,
130+
job_type: EmbeddingJobType::try_from(
131+
row.get::<&str, Option<&str>>("job_type")
132+
.unwrap_or("embedding"),
133+
)?,
134+
column_type: row
135+
.get::<&str, Option<String>>("column_type")
136+
.unwrap_or("REAL[]".to_owned()),
137+
})
138+
}
139+
140+
pub fn set_filter(&mut self, filter: &str) {
141+
self.filter = Some(filter.to_owned());
142+
}
143+
144+
pub fn set_is_init(&mut self, is_init: bool) {
145+
self.is_init = is_init;
146+
}
147+
148+
pub fn set_row_ids(&mut self, row_ids: Vec<String>) {
149+
self.row_ids = Some(row_ids);
150+
}
151+
152+
#[allow(dead_code)]
153+
pub fn set_ctid_filter(&mut self, row_ids: &Vec<String>) {
154+
let row_ctids_str = row_ids
155+
.iter()
156+
.map(|r| {
157+
format!(
158+
"currtid2('{table_name}','{r}'::tid)",
159+
table_name = &self.table
160+
)
161+
})
162+
.join(",");
163+
self.set_filter(&format!("ctid IN ({row_ctids_str})"));
164+
}
165+
166+
pub fn set_id_filter(&mut self, row_ids: &Vec<String>) {
167+
let row_ctids_str = row_ids.iter().map(|s| quote_literal(s)).join(",");
168+
self.set_filter(&format!(
169+
"id IN ({row_ctids_str}) AND {common_filter}",
170+
common_filter = get_common_embedding_ignore_filters(&self.column)
171+
));
172+
}
173+
}
174+
74175
async fn lock_row(
75176
client: Arc<Client>,
76177
lock_table_name: &str,

lantern_cli/src/daemon/external_index_jobs.rs

+34-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use super::helpers::{
33
index_job_update_processor, startup_hook,
44
};
55
use super::types::{
6-
ExternalIndexJob, ExternalIndexProcessorArgs, JobEvent, JobEventHandlersMap,
7-
JobInsertNotification, JobRunArgs, JobTaskEventTx, JobUpdateNotification,
6+
ExternalIndexProcessorArgs, JobEvent, JobEventHandlersMap, JobInsertNotification, JobRunArgs,
7+
JobTaskEventTx, JobUpdateNotification,
88
};
99
use crate::daemon::helpers::anyhow_wrap_connection;
1010
use crate::external_index::cli::{CreateIndexArgs, UMetricKind};
@@ -16,7 +16,7 @@ use std::sync::Arc;
1616
use std::time::SystemTime;
1717
use tokio::sync::mpsc::{self, Receiver, Sender, UnboundedReceiver, UnboundedSender};
1818
use tokio::sync::RwLock;
19-
use tokio_postgres::{Client, NoTls};
19+
use tokio_postgres::{Client, NoTls, Row};
2020
use tokio_util::sync::CancellationToken;
2121

2222
pub const JOB_TABLE_DEFINITION: &'static str = r#"
@@ -39,6 +39,37 @@ pub const JOB_TABLE_DEFINITION: &'static str = r#"
3939
"progress" INT2 DEFAULT 0
4040
"#;
4141

42+
#[derive(Debug)]
43+
pub struct ExternalIndexJob {
44+
pub id: i32,
45+
pub db_uri: String,
46+
pub schema: String,
47+
pub table: String,
48+
pub column: String,
49+
pub operator_class: String,
50+
pub index_name: Option<String>,
51+
pub ef: usize,
52+
pub efc: usize,
53+
pub m: usize,
54+
}
55+
56+
impl ExternalIndexJob {
57+
pub fn new(row: Row, db_uri: &str) -> ExternalIndexJob {
58+
Self {
59+
id: row.get::<&str, i32>("id"),
60+
db_uri: db_uri.to_owned(),
61+
schema: row.get::<&str, String>("schema"),
62+
table: row.get::<&str, String>("table"),
63+
column: row.get::<&str, String>("column"),
64+
operator_class: row.get::<&str, String>("operator"),
65+
index_name: row.get::<&str, Option<String>>("index"),
66+
ef: row.get::<&str, i32>("ef") as usize,
67+
efc: row.get::<&str, i32>("efc") as usize,
68+
m: row.get::<&str, i32>("m") as usize,
69+
}
70+
}
71+
}
72+
4273
async fn set_job_handle(
4374
jobs_map: Arc<JobEventHandlersMap>,
4475
job_id: i32,

0 commit comments

Comments
 (0)