Compare commits

...

5 Commits

Author SHA1 Message Date
Daniel Rammer
fd9dd390fc update to lance 5.0.0-beta.2 2026-04-01 23:51:14 -05:00
Daniel Rammer
931f19b737 Merge branch 'main' into feature/wal 2026-03-31 23:10:49 -05:00
Daniel Rammer
cde0814bbc feat(rust): add WAL host routing for merge_insert operations
Add support for routing merge_insert requests to a separate WAL/ingest
host. The WAL host is auto-derived as {db}.{region}.wal.lancedb.com or
can be explicitly overridden via ConnectBuilder::wal_host_override().
Callers opt in per-operation with MergeInsertBuilder::use_wal(true).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 23:09:15 -05:00
Lance Release
3ba46135a5 Bump version: 0.27.2-beta.2 → 0.27.2 2026-03-31 21:26:04 +00:00
Lance Release
f903d07887 Bump version: 0.27.2-beta.1 → 0.27.2-beta.2 2026-03-31 21:25:36 +00:00
24 changed files with 200 additions and 90 deletions

View File

@@ -1,5 +1,5 @@
[tool.bumpversion] [tool.bumpversion]
current_version = "0.27.2-beta.1" current_version = "0.27.2"
parse = """(?x) parse = """(?x)
(?P<major>0|[1-9]\\d*)\\. (?P<major>0|[1-9]\\d*)\\.
(?P<minor>0|[1-9]\\d*)\\. (?P<minor>0|[1-9]\\d*)\\.

87
Cargo.lock generated
View File

@@ -3072,9 +3072,8 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]] [[package]]
name = "fsst" name = "fsst"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "2195cc7f87e84bd695586137de99605e7e9579b26ec5e01b82960ddb4d0922f2"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"rand 0.9.2", "rand 0.9.2",
@@ -4124,9 +4123,8 @@ dependencies = [
[[package]] [[package]]
name = "lance" name = "lance"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "efe6c3ddd79cdfd2b7e1c23cafae52806906bc40fbd97de9e8cf2f8c7a75fc04"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-arith", "arrow-arith",
@@ -4192,9 +4190,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-arrow" name = "lance-arrow"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "5d9f5d95bdda2a2b790f1fb8028b5b6dcf661abeb3133a8bca0f3d24b054af87"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"arrow-buffer", "arrow-buffer",
@@ -4214,9 +4211,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-bitpacking" name = "lance-bitpacking"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "f827d6ab9f8f337a9509d5ad66a12f3314db8713868260521c344ef6135eb4e4"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"paste", "paste",
@@ -4225,9 +4221,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-core" name = "lance-core"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "0f1e25df6a79bf72ee6bcde0851f19b1cd36c5848c1b7db83340882d3c9fdecb"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"arrow-buffer", "arrow-buffer",
@@ -4264,9 +4259,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-datafusion" name = "lance-datafusion"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "93146de8ae720cb90edef81c2f2d0a1b065fc2f23ecff2419546f389b0fa70a4"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-array", "arrow-array",
@@ -4296,9 +4290,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-datagen" name = "lance-datagen"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "ccec8ce4d8e0a87a99c431dab2364398029f2ffb649c1a693c60c79e05ed30dd"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-array", "arrow-array",
@@ -4316,9 +4309,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-encoding" name = "lance-encoding"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "5c1aec0bbbac6bce829bc10f1ba066258126100596c375fb71908ecf11c2c2a5"
dependencies = [ dependencies = [
"arrow-arith", "arrow-arith",
"arrow-array", "arrow-array",
@@ -4355,9 +4347,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-file" name = "lance-file"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "14a8c548804f5b17486dc2d3282356ed1957095a852780283bc401fdd69e9075"
dependencies = [ dependencies = [
"arrow-arith", "arrow-arith",
"arrow-array", "arrow-array",
@@ -4389,9 +4380,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-index" name = "lance-index"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "2da212f0090ea59f79ac3686660f596520c167fe1cb5f408900cf71d215f0e03"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-arith", "arrow-arith",
@@ -4455,9 +4445,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-io" name = "lance-io"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "41d958eb4b56f03bbe0f5f85eb2b4e9657882812297b6f711f201ffc995f259f"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-arith", "arrow-arith",
@@ -4498,9 +4487,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-linalg" name = "lance-linalg"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "0285b70da35def7ed95e150fae1d5308089554e1290470403ed3c50cb235bc5e"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"arrow-buffer", "arrow-buffer",
@@ -4516,9 +4504,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-namespace" name = "lance-namespace"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "5f78e2a828b654e062a495462c6e3eb4fcf0e7e907d761b8f217fc09ccd3ceac"
dependencies = [ dependencies = [
"arrow", "arrow",
"async-trait", "async-trait",
@@ -4531,9 +4518,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-namespace-impls" name = "lance-namespace-impls"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "a2392314f3da38f00d166295e44244208a65ccfc256e274fa8631849fc3f4d94"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-ipc", "arrow-ipc",
@@ -4547,6 +4533,7 @@ dependencies = [
"lance-core", "lance-core",
"lance-index", "lance-index",
"lance-io", "lance-io",
"lance-linalg",
"lance-namespace", "lance-namespace",
"lance-table", "lance-table",
"log", "log",
@@ -4577,9 +4564,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-table" name = "lance-table"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "3df9c4adca3eb2074b3850432a9fb34248a3d90c3d6427d158b13ff9355664ee"
dependencies = [ dependencies = [
"arrow", "arrow",
"arrow-array", "arrow-array",
@@ -4618,9 +4604,8 @@ dependencies = [
[[package]] [[package]]
name = "lance-testing" name = "lance-testing"
version = "4.0.0" version = "5.0.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/lance-format/lance.git?tag=v5.0.0-beta.2#34e311c7632f62d8e4ff3a6e8bd124f84f0b70dc"
checksum = "7ed7119bdd6983718387b4ac44af873a165262ca94f181b104cd6f97912eb3bf"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"arrow-schema", "arrow-schema",
@@ -4631,7 +4616,7 @@ dependencies = [
[[package]] [[package]]
name = "lancedb" name = "lancedb"
version = "0.27.2-beta.1" version = "0.27.2"
dependencies = [ dependencies = [
"ahash", "ahash",
"anyhow", "anyhow",
@@ -4713,7 +4698,7 @@ dependencies = [
[[package]] [[package]]
name = "lancedb-nodejs" name = "lancedb-nodejs"
version = "0.27.2-beta.1" version = "0.27.2"
dependencies = [ dependencies = [
"arrow-array", "arrow-array",
"arrow-buffer", "arrow-buffer",
@@ -4735,7 +4720,7 @@ dependencies = [
[[package]] [[package]]
name = "lancedb-python" name = "lancedb-python"
version = "0.30.2-beta.1" version = "0.30.2"
dependencies = [ dependencies = [
"arrow", "arrow",
"async-trait", "async-trait",

View File

@@ -15,20 +15,20 @@ categories = ["database-implementations"]
rust-version = "1.91.0" rust-version = "1.91.0"
[workspace.dependencies] [workspace.dependencies]
lance = { version = "=4.0.0", default-features = false } lance = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2", default-features = false }
lance-core = { version = "=4.0.0" } lance-core = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-datagen = { version = "=4.0.0" } lance-datagen = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-file = { version = "=4.0.0" } lance-file = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-io = { version = "=4.0.0", default-features = false } lance-io = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2", default-features = false }
lance-index = { version = "=4.0.0" } lance-index = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-linalg = { version = "=4.0.0" } lance-linalg = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-namespace = { version = "=4.0.0" } lance-namespace = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-namespace-impls = { version = "=4.0.0", default-features = false } lance-namespace-impls = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2", default-features = false }
lance-table = { version = "=4.0.0" } lance-table = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-testing = { version = "=4.0.0" } lance-testing = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-datafusion = { version = "=4.0.0" } lance-datafusion = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-encoding = { version = "=4.0.0" } lance-encoding = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
lance-arrow = { version = "=4.0.0" } lance-arrow = { git = "https://github.com/lance-format/lance.git", tag = "v5.0.0-beta.2" }
ahash = "0.8" ahash = "0.8"
# Note that this one does not include pyarrow # Note that this one does not include pyarrow
arrow = { version = "57.2", optional = false } arrow = { version = "57.2", optional = false }

View File

@@ -14,7 +14,7 @@ Add the following dependency to your `pom.xml`:
<dependency> <dependency>
<groupId>com.lancedb</groupId> <groupId>com.lancedb</groupId>
<artifactId>lancedb-core</artifactId> <artifactId>lancedb-core</artifactId>
<version>0.27.2-beta.1</version> <version>0.27.2</version>
</dependency> </dependency>
``` ```

View File

@@ -8,7 +8,7 @@
<parent> <parent>
<groupId>com.lancedb</groupId> <groupId>com.lancedb</groupId>
<artifactId>lancedb-parent</artifactId> <artifactId>lancedb-parent</artifactId>
<version>0.27.2-beta.1</version> <version>0.27.2-final.0</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@@ -6,7 +6,7 @@
<groupId>com.lancedb</groupId> <groupId>com.lancedb</groupId>
<artifactId>lancedb-parent</artifactId> <artifactId>lancedb-parent</artifactId>
<version>0.27.2-beta.1</version> <version>0.27.2-final.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<description>LanceDB Java SDK Parent POM</description> <description>LanceDB Java SDK Parent POM</description>

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "lancedb-nodejs" name = "lancedb-nodejs"
edition.workspace = true edition.workspace = true
version = "0.27.2-beta.1" version = "0.27.2"
license.workspace = true license.workspace = true
description.workspace = true description.workspace = true
repository.workspace = true repository.workspace = true

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-darwin-arm64", "name": "@lancedb/lancedb-darwin-arm64",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["darwin"], "os": ["darwin"],
"cpu": ["arm64"], "cpu": ["arm64"],
"main": "lancedb.darwin-arm64.node", "main": "lancedb.darwin-arm64.node",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-linux-arm64-gnu", "name": "@lancedb/lancedb-linux-arm64-gnu",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["linux"], "os": ["linux"],
"cpu": ["arm64"], "cpu": ["arm64"],
"main": "lancedb.linux-arm64-gnu.node", "main": "lancedb.linux-arm64-gnu.node",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-linux-arm64-musl", "name": "@lancedb/lancedb-linux-arm64-musl",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["linux"], "os": ["linux"],
"cpu": ["arm64"], "cpu": ["arm64"],
"main": "lancedb.linux-arm64-musl.node", "main": "lancedb.linux-arm64-musl.node",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-linux-x64-gnu", "name": "@lancedb/lancedb-linux-x64-gnu",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["linux"], "os": ["linux"],
"cpu": ["x64"], "cpu": ["x64"],
"main": "lancedb.linux-x64-gnu.node", "main": "lancedb.linux-x64-gnu.node",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-linux-x64-musl", "name": "@lancedb/lancedb-linux-x64-musl",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["linux"], "os": ["linux"],
"cpu": ["x64"], "cpu": ["x64"],
"main": "lancedb.linux-x64-musl.node", "main": "lancedb.linux-x64-musl.node",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-win32-arm64-msvc", "name": "@lancedb/lancedb-win32-arm64-msvc",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": [ "os": [
"win32" "win32"
], ],

View File

@@ -1,6 +1,6 @@
{ {
"name": "@lancedb/lancedb-win32-x64-msvc", "name": "@lancedb/lancedb-win32-x64-msvc",
"version": "0.27.2-beta.1", "version": "0.27.2",
"os": ["win32"], "os": ["win32"],
"cpu": ["x64"], "cpu": ["x64"],
"main": "lancedb.win32-x64-msvc.node", "main": "lancedb.win32-x64-msvc.node",

View File

@@ -1,12 +1,12 @@
{ {
"name": "@lancedb/lancedb", "name": "@lancedb/lancedb",
"version": "0.27.2-beta.1", "version": "0.27.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@lancedb/lancedb", "name": "@lancedb/lancedb",
"version": "0.27.2-beta.1", "version": "0.27.2",
"cpu": [ "cpu": [
"x64", "x64",
"arm64" "arm64"

View File

@@ -11,7 +11,7 @@
"ann" "ann"
], ],
"private": false, "private": false,
"version": "0.27.2-beta.1", "version": "0.27.2",
"main": "dist/index.js", "main": "dist/index.js",
"exports": { "exports": {
".": "./dist/index.js", ".": "./dist/index.js",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "lancedb" name = "lancedb"
version = "0.27.2-beta.1" version = "0.27.2"
edition.workspace = true edition.workspace = true
description = "LanceDB: A serverless, low-latency vector database for AI applications" description = "LanceDB: A serverless, low-latency vector database for AI applications"
license.workspace = true license.workspace = true

View File

@@ -30,7 +30,10 @@ use crate::error::{Error, Result};
#[cfg(feature = "remote")] #[cfg(feature = "remote")]
use crate::remote::{ use crate::remote::{
client::ClientConfig, client::ClientConfig,
db::{OPT_REMOTE_API_KEY, OPT_REMOTE_HOST_OVERRIDE, OPT_REMOTE_REGION}, db::{
OPT_REMOTE_API_KEY, OPT_REMOTE_HOST_OVERRIDE, OPT_REMOTE_REGION,
OPT_REMOTE_WAL_HOST_OVERRIDE,
},
}; };
use lance::io::ObjectStoreParams; use lance::io::ObjectStoreParams;
pub use lance_encoding::version::LanceFileVersion; pub use lance_encoding::version::LanceFileVersion;
@@ -664,6 +667,24 @@ impl ConnectBuilder {
self self
} }
/// Set the WAL host override for routing merge_insert requests
/// to a separate WAL/ingest service.
///
/// This option is only used when connecting to LanceDB Cloud (db:// URIs)
/// and will be ignored for other URIs.
///
/// # Arguments
///
/// * `wal_host_override` - The WAL host override to use for the connection
#[cfg(feature = "remote")]
pub fn wal_host_override(mut self, wal_host_override: &str) -> Self {
self.request.options.insert(
OPT_REMOTE_WAL_HOST_OVERRIDE.to_string(),
wal_host_override.to_string(),
);
self
}
/// Set the database specific options /// Set the database specific options
/// ///
/// See [crate::database::listing::ListingDatabaseOptions] for the options available for /// See [crate::database::listing::ListingDatabaseOptions] for the options available for
@@ -817,6 +838,7 @@ impl ConnectBuilder {
&api_key, &api_key,
&region, &region,
options.host_override, options.host_override,
options.wal_host_override,
self.request.client_config, self.request.client_config,
storage_options.into(), storage_options.into(),
)?); )?);

View File

@@ -190,6 +190,7 @@ pub struct RetryConfig {
pub struct RestfulLanceDbClient<S: HttpSend = Sender> { pub struct RestfulLanceDbClient<S: HttpSend = Sender> {
client: reqwest::Client, client: reqwest::Client,
host: String, host: String,
wal_host: String,
pub(crate) retry_config: ResolvedRetryConfig, pub(crate) retry_config: ResolvedRetryConfig,
pub(crate) sender: S, pub(crate) sender: S,
pub(crate) id_delimiter: String, pub(crate) id_delimiter: String,
@@ -200,6 +201,7 @@ impl<S: HttpSend> std::fmt::Debug for RestfulLanceDbClient<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RestfulLanceDbClient") f.debug_struct("RestfulLanceDbClient")
.field("host", &self.host) .field("host", &self.host)
.field("wal_host", &self.wal_host)
.field("retry_config", &self.retry_config) .field("retry_config", &self.retry_config)
.field("sender", &self.sender) .field("sender", &self.sender)
.field("id_delimiter", &self.id_delimiter) .field("id_delimiter", &self.id_delimiter)
@@ -285,6 +287,7 @@ impl RestfulLanceDbClient<Sender> {
parsed_url: &ParsedDbUrl, parsed_url: &ParsedDbUrl,
region: &str, region: &str,
host_override: Option<String>, host_override: Option<String>,
wal_host_override: Option<String>,
default_headers: HeaderMap, default_headers: HeaderMap,
client_config: ClientConfig, client_config: ClientConfig,
) -> Result<Self> { ) -> Result<Self> {
@@ -372,11 +375,16 @@ impl RestfulLanceDbClient<Sender> {
Some(host_override) => host_override, Some(host_override) => host_override,
None => format!("https://{}.{}.api.lancedb.com", parsed_url.db_name, region), None => format!("https://{}.{}.api.lancedb.com", parsed_url.db_name, region),
}; };
debug!("Created client for host: {}", host); let wal_host = match wal_host_override {
Some(wal_host_override) => wal_host_override,
None => format!("https://{}.{}.wal.lancedb.com", parsed_url.db_name, region),
};
debug!("Created client for host: {}, wal_host: {}", host, wal_host);
let retry_config = client_config.retry_config.clone().try_into()?; let retry_config = client_config.retry_config.clone().try_into()?;
Ok(Self { Ok(Self {
client, client,
host, host,
wal_host,
retry_config, retry_config,
sender: Sender, sender: Sender,
id_delimiter: client_config id_delimiter: client_config
@@ -479,6 +487,12 @@ impl<S: HttpSend> RestfulLanceDbClient<S> {
self.add_id_delimiter_query_param(builder) self.add_id_delimiter_query_param(builder)
} }
pub fn post_wal(&self, uri: &str) -> RequestBuilder {
let full_uri = format!("{}{}", self.wal_host, uri);
let builder = self.client.post(full_uri);
self.add_id_delimiter_query_param(builder)
}
fn add_id_delimiter_query_param(&self, req: RequestBuilder) -> RequestBuilder { fn add_id_delimiter_query_param(&self, req: RequestBuilder) -> RequestBuilder {
if self.id_delimiter != "$" { if self.id_delimiter != "$" {
req.query(&[("delimiter", self.id_delimiter.clone())]) req.query(&[("delimiter", self.id_delimiter.clone())])
@@ -791,6 +805,7 @@ pub mod test_utils {
RestfulLanceDbClient { RestfulLanceDbClient {
client: reqwest::Client::new(), client: reqwest::Client::new(),
host: "http://localhost".to_string(), host: "http://localhost".to_string(),
wal_host: "http://localhost-wal".to_string(),
retry_config: RetryConfig::default().try_into().unwrap(), retry_config: RetryConfig::default().try_into().unwrap(),
sender: MockSender { sender: MockSender {
f: Arc::new(wrapper), f: Arc::new(wrapper),
@@ -815,6 +830,7 @@ pub mod test_utils {
RestfulLanceDbClient { RestfulLanceDbClient {
client: reqwest::Client::new(), client: reqwest::Client::new(),
host: "http://localhost".to_string(), host: "http://localhost".to_string(),
wal_host: "http://localhost-wal".to_string(),
retry_config: config.retry_config.try_into().unwrap(), retry_config: config.retry_config.try_into().unwrap(),
sender: MockSender { sender: MockSender {
f: Arc::new(wrapper), f: Arc::new(wrapper),
@@ -982,6 +998,7 @@ mod tests {
let client = RestfulLanceDbClient { let client = RestfulLanceDbClient {
client: reqwest::Client::new(), client: reqwest::Client::new(),
host: "https://example.com".to_string(), host: "https://example.com".to_string(),
wal_host: "https://example.com".to_string(),
retry_config: RetryConfig::default().try_into().unwrap(), retry_config: RetryConfig::default().try_into().unwrap(),
sender: Sender, sender: Sender,
id_delimiter: "+".to_string(), id_delimiter: "+".to_string(),
@@ -1017,6 +1034,7 @@ mod tests {
let client = RestfulLanceDbClient { let client = RestfulLanceDbClient {
client: reqwest::Client::new(), client: reqwest::Client::new(),
host: "https://example.com".to_string(), host: "https://example.com".to_string(),
wal_host: "https://example.com".to_string(),
retry_config: RetryConfig::default().try_into().unwrap(), retry_config: RetryConfig::default().try_into().unwrap(),
sender: Sender, sender: Sender,
id_delimiter: "+".to_string(), id_delimiter: "+".to_string(),
@@ -1054,6 +1072,7 @@ mod tests {
let client = RestfulLanceDbClient { let client = RestfulLanceDbClient {
client: reqwest::Client::new(), client: reqwest::Client::new(),
host: "https://example.com".to_string(), host: "https://example.com".to_string(),
wal_host: "https://example.com".to_string(),
retry_config: RetryConfig::default().try_into().unwrap(), retry_config: RetryConfig::default().try_into().unwrap(),
sender: Sender, sender: Sender,
id_delimiter: "+".to_string(), id_delimiter: "+".to_string(),

View File

@@ -82,6 +82,7 @@ pub const OPT_REMOTE_PREFIX: &str = "remote_database_";
pub const OPT_REMOTE_API_KEY: &str = "remote_database_api_key"; pub const OPT_REMOTE_API_KEY: &str = "remote_database_api_key";
pub const OPT_REMOTE_REGION: &str = "remote_database_region"; pub const OPT_REMOTE_REGION: &str = "remote_database_region";
pub const OPT_REMOTE_HOST_OVERRIDE: &str = "remote_database_host_override"; pub const OPT_REMOTE_HOST_OVERRIDE: &str = "remote_database_host_override";
pub const OPT_REMOTE_WAL_HOST_OVERRIDE: &str = "remote_database_wal_host_override";
// TODO: add support for configuring client config via key/value options // TODO: add support for configuring client config via key/value options
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@@ -95,6 +96,11 @@ pub struct RemoteDatabaseOptions {
/// This is required when connecting to LanceDB Enterprise and should be /// This is required when connecting to LanceDB Enterprise and should be
/// provided if using an on-premises LanceDB Enterprise instance. /// provided if using an on-premises LanceDB Enterprise instance.
pub host_override: Option<String>, pub host_override: Option<String>,
/// The WAL host override
///
/// When set, merge_insert operations using WAL routing will be sent to
/// this host instead of the auto-derived WAL host.
pub wal_host_override: Option<String>,
/// Storage options configure the storage layer (e.g. S3, GCS, Azure, etc.) /// Storage options configure the storage layer (e.g. S3, GCS, Azure, etc.)
/// ///
/// See available options at <https://lancedb.com/docs/storage/> /// See available options at <https://lancedb.com/docs/storage/>
@@ -113,6 +119,7 @@ impl RemoteDatabaseOptions {
let api_key = map.get(OPT_REMOTE_API_KEY).cloned(); let api_key = map.get(OPT_REMOTE_API_KEY).cloned();
let region = map.get(OPT_REMOTE_REGION).cloned(); let region = map.get(OPT_REMOTE_REGION).cloned();
let host_override = map.get(OPT_REMOTE_HOST_OVERRIDE).cloned(); let host_override = map.get(OPT_REMOTE_HOST_OVERRIDE).cloned();
let wal_host_override = map.get(OPT_REMOTE_WAL_HOST_OVERRIDE).cloned();
let storage_options = map let storage_options = map
.iter() .iter()
.filter(|(key, _)| !key.starts_with(OPT_REMOTE_PREFIX)) .filter(|(key, _)| !key.starts_with(OPT_REMOTE_PREFIX))
@@ -122,6 +129,7 @@ impl RemoteDatabaseOptions {
api_key, api_key,
region, region,
host_override, host_override,
wal_host_override,
storage_options, storage_options,
}) })
} }
@@ -141,6 +149,12 @@ impl DatabaseOptions for RemoteDatabaseOptions {
if let Some(host_override) = &self.host_override { if let Some(host_override) = &self.host_override {
map.insert(OPT_REMOTE_HOST_OVERRIDE.to_string(), host_override.clone()); map.insert(OPT_REMOTE_HOST_OVERRIDE.to_string(), host_override.clone());
} }
if let Some(wal_host_override) = &self.wal_host_override {
map.insert(
OPT_REMOTE_WAL_HOST_OVERRIDE.to_string(),
wal_host_override.clone(),
);
}
} }
} }
@@ -185,6 +199,19 @@ impl RemoteDatabaseOptionsBuilder {
self.options.host_override = Some(host_override); self.options.host_override = Some(host_override);
self self
} }
/// Set the WAL host override
///
/// When set, merge_insert operations using WAL routing will be sent to
/// this host instead of the auto-derived WAL host.
///
/// # Arguments
///
/// * `wal_host_override` - The WAL host override
pub fn wal_host_override(mut self, wal_host_override: String) -> Self {
self.options.wal_host_override = Some(wal_host_override);
self
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -204,6 +231,7 @@ impl RemoteDatabase {
api_key: &str, api_key: &str,
region: &str, region: &str,
host_override: Option<String>, host_override: Option<String>,
wal_host_override: Option<String>,
client_config: ClientConfig, client_config: ClientConfig,
options: RemoteOptions, options: RemoteOptions,
) -> Result<Self> { ) -> Result<Self> {
@@ -231,6 +259,7 @@ impl RemoteDatabase {
&parsed, &parsed,
region, region,
host_override, host_override,
wal_host_override,
header_map, header_map,
client_config.clone(), client_config.clone(),
)?; )?;

View File

@@ -1610,13 +1610,17 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
self.check_mutable().await?; self.check_mutable().await?;
let timeout = params.timeout; let timeout = params.timeout;
let use_wal = params.use_wal;
let query = MergeInsertRequest::try_from(params)?; let query = MergeInsertRequest::try_from(params)?;
let mut request = self let path = format!("/v1/table/{}/merge_insert/", self.identifier);
.client let mut request = if use_wal {
.post(&format!("/v1/table/{}/merge_insert/", self.identifier)) self.client.post_wal(&path)
.query(&query) } else {
.header(CONTENT_TYPE, ARROW_STREAM_CONTENT_TYPE); self.client.post(&path)
}
.query(&query)
.header(CONTENT_TYPE, ARROW_STREAM_CONTENT_TYPE);
if let Some(timeout) = timeout { if let Some(timeout) = timeout {
// (If it doesn't fit into u64, it's not worth sending anyways.) // (If it doesn't fit into u64, it's not worth sending anyways.)
@@ -2705,6 +2709,43 @@ mod tests {
} }
} }
#[tokio::test]
async fn test_merge_insert_use_wal() {
let batch = RecordBatch::try_new(
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
)
.unwrap();
let data: Box<dyn RecordBatchReader + Send> = Box::new(RecordBatchIterator::new(
[Ok(batch.clone())],
batch.schema(),
));
let table = Table::new_with_handler("my_table", move |request| {
if request.url().path() == "/v1/table/my_table/merge_insert/" {
// Verify the request was sent to the WAL host
assert_eq!(
request.url().host_str().unwrap(),
"localhost-wal",
"merge_insert with use_wal should route to WAL host"
);
http::Response::builder()
.status(200)
.body(r#"{"version": 1, "num_deleted_rows": 0, "num_inserted_rows": 3, "num_updated_rows": 0}"#)
.unwrap()
} else {
panic!("Unexpected request path: {}", request.url().path());
}
});
let mut builder = table.merge_insert(&["some_col"]);
builder.use_wal(true);
let result = builder.execute(data).await.unwrap();
assert_eq!(result.num_inserted_rows, 3);
}
#[tokio::test] #[tokio::test]
async fn test_merge_insert_retries_on_409() { async fn test_merge_insert_retries_on_409() {
let batch = RecordBatch::try_new( let batch = RecordBatch::try_new(

View File

@@ -23,7 +23,7 @@ use lance::index::vector::VectorIndexParams;
use lance::index::vector::utils::infer_vector_dim; use lance::index::vector::utils::infer_vector_dim;
use lance::io::{ObjectStoreParams, WrappingObjectStore}; use lance::io::{ObjectStoreParams, WrappingObjectStore};
use lance_datafusion::utils::StreamingWriteSource; use lance_datafusion::utils::StreamingWriteSource;
use lance_index::DatasetIndexExt; use lance::index::DatasetIndexExt;
use lance_index::IndexType; use lance_index::IndexType;
use lance_index::scalar::{BuiltinIndexType, ScalarIndexParams}; use lance_index::scalar::{BuiltinIndexType, ScalarIndexParams};
use lance_index::vector::bq::RQBuildParams; use lance_index::vector::bq::RQBuildParams;

View File

@@ -55,6 +55,7 @@ pub struct MergeInsertBuilder {
pub(crate) when_not_matched_by_source_delete_filt: Option<String>, pub(crate) when_not_matched_by_source_delete_filt: Option<String>,
pub(crate) timeout: Option<Duration>, pub(crate) timeout: Option<Duration>,
pub(crate) use_index: bool, pub(crate) use_index: bool,
pub(crate) use_wal: bool,
} }
impl MergeInsertBuilder { impl MergeInsertBuilder {
@@ -69,6 +70,7 @@ impl MergeInsertBuilder {
when_not_matched_by_source_delete_filt: None, when_not_matched_by_source_delete_filt: None,
timeout: None, timeout: None,
use_index: true, use_index: true,
use_wal: false,
} }
} }
@@ -148,6 +150,18 @@ impl MergeInsertBuilder {
self self
} }
/// Controls whether to route the merge insert operation through the WAL host.
///
/// When set to `true`, the operation will be sent to the WAL host instead of
/// the main API host. The WAL host is auto-derived from the database connection
/// or can be explicitly set via [`crate::connection::ConnectBuilder::wal_host_override`].
///
/// Defaults to `false`.
pub fn use_wal(&mut self, use_wal: bool) -> &mut Self {
self.use_wal = use_wal;
self
}
/// Executes the merge insert operation /// Executes the merge insert operation
/// ///
/// Returns version and statistics about the merge operation including the number of rows /// Returns version and statistics about the merge operation including the number of rows

View File

@@ -10,7 +10,7 @@ use std::sync::Arc;
use lance::dataset::cleanup::RemovalStats; use lance::dataset::cleanup::RemovalStats;
use lance::dataset::optimize::{CompactionMetrics, IndexRemapperOptions, compact_files}; use lance::dataset::optimize::{CompactionMetrics, IndexRemapperOptions, compact_files};
use lance_index::DatasetIndexExt; use lance::index::DatasetIndexExt;
use lance_index::optimize::OptimizeOptions; use lance_index::optimize::OptimizeOptions;
use log::info; use log::info;