From 26080ee4c132f5a427e248aa14f1b9858d719f12 Mon Sep 17 00:00:00 2001 From: Weston Pace Date: Thu, 17 Apr 2025 17:14:36 -0500 Subject: [PATCH] feat: add prewarm_index function (#2342) ## Summary by CodeRabbit - **New Features** - Added the ability to prewarm (load into memory) table indexes via new methods in Python, Node.js, and Rust APIs, potentially reducing cold-start query latency. - **Bug Fixes** - Ensured prewarming an index does not interfere with subsequent search operations. - **Tests** - Introduced new test cases to verify full-text search index creation, prewarming, and search functionalities in both Python and Node.js. - **Chores** - Updated dependencies for improved compatibility and performance. --------- Co-authored-by: Lu Qiu --- Cargo.lock | 61 ++++++++++++++++--------------- Cargo.toml | 18 ++++----- docs/src/js/classes/Table.md | 22 +++++++++++ nodejs/__test__/table.test.ts | 22 +++++++++++ nodejs/lancedb/table.ts | 15 ++++++++ nodejs/src/query.rs | 8 ++-- nodejs/src/table.rs | 8 ++++ python/pyproject.toml | 4 +- python/python/lancedb/table.py | 41 +++++++++++++++++++++ python/python/tests/test_index.py | 14 ++++++- python/src/table.rs | 8 ++++ python/src/util.rs | 5 ++- rust/lancedb/src/remote/table.rs | 7 ++++ rust/lancedb/src/table.rs | 36 +++++++++++++++--- 14 files changed, 215 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26f8472c..d9d321b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2721,8 +2721,8 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fsst" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "rand 0.8.5", ] @@ -3711,8 +3711,8 @@ dependencies = [ [[package]] name = "lance" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-arith", @@ -3738,6 +3738,7 @@ dependencies = [ "deepsize", "futures", "half", + "humantime", "itertools 0.13.0", "lance-arrow", "lance-core", @@ -3771,8 +3772,8 @@ dependencies = [ [[package]] name = "lance-arrow" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow-array", "arrow-buffer", @@ -3789,8 +3790,8 @@ dependencies = [ [[package]] name = "lance-core" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow-array", "arrow-buffer", @@ -3826,8 +3827,8 @@ dependencies = [ [[package]] name = "lance-datafusion" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-array", @@ -3854,8 +3855,8 @@ dependencies = [ [[package]] name = "lance-datagen" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-array", @@ -3870,8 +3871,8 @@ dependencies = [ [[package]] name = "lance-encoding" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrayref", "arrow", @@ -3910,8 +3911,8 @@ dependencies = [ [[package]] name = "lance-file" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow-arith", "arrow-array", @@ -3945,8 +3946,8 @@ dependencies = [ [[package]] name = "lance-index" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-array", @@ -3999,8 +4000,8 @@ dependencies = [ [[package]] name = "lance-io" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-arith", @@ -4038,8 +4039,8 @@ dependencies = [ [[package]] name = "lance-linalg" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow-array", "arrow-ord", @@ -4062,8 +4063,8 @@ dependencies = [ [[package]] name = "lance-table" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow", "arrow-array", @@ -4102,8 +4103,8 @@ dependencies = [ [[package]] name = "lance-testing" -version = "0.25.3" -source = "git+https://github.com/lancedb/lance?tag=v0.25.3-beta.4#236c8f986ab9e2d478d0754fab6e8d2643c31247" +version = "0.26.0" +source = "git+https://github.com/lancedb/lance?tag=v0.26.0-beta.1#8e46047e2dcb171bec28e28b507a9b7858348773" dependencies = [ "arrow-array", "arrow-schema", @@ -4114,7 +4115,7 @@ dependencies = [ [[package]] name = "lancedb" -version = "0.19.0-beta.6" +version = "0.19.0-beta.7" dependencies = [ "arrow", "arrow-array", @@ -4201,7 +4202,7 @@ dependencies = [ [[package]] name = "lancedb-node" -version = "0.19.0-beta.6" +version = "0.19.0-beta.7" dependencies = [ "arrow-array", "arrow-ipc", @@ -4226,7 +4227,7 @@ dependencies = [ [[package]] name = "lancedb-nodejs" -version = "0.19.0-beta.6" +version = "0.19.0-beta.7" dependencies = [ "arrow-array", "arrow-ipc", @@ -4244,7 +4245,7 @@ dependencies = [ [[package]] name = "lancedb-python" -version = "0.22.0-beta.6" +version = "0.22.0-beta.7" dependencies = [ "arrow", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index 176c867b..277901c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,16 +21,16 @@ categories = ["database-implementations"] rust-version = "1.78.0" [workspace.dependencies] -lance = { "version" = "=0.25.3", "features" = [ +lance = { "version" = "=0.26.0", "features" = [ "dynamodb", -], tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-io = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-index = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-linalg = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-table = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-testing = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-datafusion = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } -lance-encoding = { version = "=0.25.3", tag = "v0.25.3-beta.4", git = "https://github.com/lancedb/lance" } +], tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-io = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-index = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-linalg = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-table = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-testing = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-datafusion = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } +lance-encoding = { version = "=0.26.0", tag = "v0.26.0-beta.1", git = "https://github.com/lancedb/lance" } # Note that this one does not include pyarrow arrow = { version = "54.1", optional = false } arrow-array = "54.1" diff --git a/docs/src/js/classes/Table.md b/docs/src/js/classes/Table.md index 26dfbb16..e771f27e 100644 --- a/docs/src/js/classes/Table.md +++ b/docs/src/js/classes/Table.md @@ -454,6 +454,28 @@ Modeled after ``VACUUM`` in PostgreSQL. *** +### prewarmIndex() + +```ts +abstract prewarmIndex(name): Promise +``` + +Prewarm an index in the table. + +#### Parameters + +* **name**: `string` + The name of the index. + This will load the index into memory. This may reduce the cold-start time for + future queries. If the index does not fit in the cache then this call may be + wasteful. + +#### Returns + +`Promise`<`void`> + +*** + ### query() ```ts diff --git a/nodejs/__test__/table.test.ts b/nodejs/__test__/table.test.ts index 0e977b46..ac56e98b 100644 --- a/nodejs/__test__/table.test.ts +++ b/nodejs/__test__/table.test.ts @@ -1312,6 +1312,28 @@ describe.each([arrow15, arrow16, arrow17, arrow18])( expect(results2[0].text).toBe(data[1].text); }); + test("prewarm full text search index", async () => { + const db = await connect(tmpDir.name); + const data = [ + { text: ["lance database", "the", "search"], vector: [0.1, 0.2, 0.3] }, + { text: ["lance database"], vector: [0.4, 0.5, 0.6] }, + { text: ["lance", "search"], vector: [0.7, 0.8, 0.9] }, + { text: ["database", "search"], vector: [1.0, 1.1, 1.2] }, + { text: ["unrelated", "doc"], vector: [1.3, 1.4, 1.5] }, + ]; + const table = await db.createTable("test", data); + await table.createIndex("text", { + config: Index.fts(), + }); + + // For the moment, we just confirm we can call prewarmIndex without error + // and still search it afterwards + await table.prewarmIndex("text_idx"); + + const results = await table.search("lance").toArray(); + expect(results.length).toBe(3); + }); + test("full text index on list", async () => { const db = await connect(tmpDir.name); const data = [ diff --git a/nodejs/lancedb/table.ts b/nodejs/lancedb/table.ts index 8fa456f2..5f8d4412 100644 --- a/nodejs/lancedb/table.ts +++ b/nodejs/lancedb/table.ts @@ -235,6 +235,17 @@ export abstract class Table { */ abstract dropIndex(name: string): Promise; + /** + * Prewarm an index in the table. + * + * @param name The name of the index. + * + * This will load the index into memory. This may reduce the cold-start time for + * future queries. If the index does not fit in the cache then this call may be + * wasteful. + */ + abstract prewarmIndex(name: string): Promise; + /** * Create a {@link Query} Builder. * @@ -565,6 +576,10 @@ export class LocalTable extends Table { await this.inner.dropIndex(name); } + async prewarmIndex(name: string): Promise { + await this.inner.prewarmIndex(name); + } + query(): Query { return new Query(this.inner); } diff --git a/nodejs/src/query.rs b/nodejs/src/query.rs index b5acece4..442ae79a 100644 --- a/nodejs/src/query.rs +++ b/nodejs/src/query.rs @@ -327,6 +327,7 @@ impl JsFullTextQuery { } #[napi(factory)] + #[allow(clippy::use_self)] // NAPI doesn't allow Self here but clippy reports it pub fn boost_query( positive: &JsFullTextQuery, negative: &JsFullTextQuery, @@ -349,11 +350,8 @@ impl JsFullTextQuery { boosts: Option>, ) -> napi::Result { let q = match boosts { - Some(boosts) => MultiMatchQuery::try_new_with_boosts( - query, - columns, - boosts.into_iter().map(|v| v as f32).collect(), - ), + Some(boosts) => MultiMatchQuery::try_new(query, columns) + .and_then(|q| q.try_with_boosts(boosts.into_iter().map(|v| v as f32).collect())), None => MultiMatchQuery::try_new(query, columns), } .map_err(|e| { diff --git a/nodejs/src/table.rs b/nodejs/src/table.rs index abaccb36..6b38c621 100644 --- a/nodejs/src/table.rs +++ b/nodejs/src/table.rs @@ -132,6 +132,14 @@ impl Table { .default_error() } + #[napi(catch_unwind)] + pub async fn prewarm_index(&self, index_name: String) -> napi::Result<()> { + self.inner_ref()? + .prewarm_index(&index_name) + .await + .default_error() + } + #[napi(catch_unwind)] pub async fn update( &self, diff --git a/python/pyproject.toml b/python/pyproject.toml index d36417f6..28d378fc 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -44,7 +44,7 @@ repository = "https://github.com/lancedb/lancedb" [project.optional-dependencies] pylance = [ - "pylance>=0.23.2", + "pylance>=0.25", ] tests = [ "aiohttp", @@ -58,7 +58,7 @@ tests = [ "polars>=0.19, <=1.3.0", "tantivy", "pyarrow-stubs", - "pylance>=0.23.2", + "pylance>=0.25", "requests", ] dev = [ diff --git a/python/python/lancedb/table.py b/python/python/lancedb/table.py index d940b46c..f3edf8e5 100644 --- a/python/python/lancedb/table.py +++ b/python/python/lancedb/table.py @@ -1745,8 +1745,32 @@ class LanceTable(Table): ) def drop_index(self, name: str) -> None: + """ + Drops an index from the table + + Parameters + ---------- + name: str + The name of the index to drop + """ return LOOP.run(self._table.drop_index(name)) + def prewarm_index(self, name: str) -> None: + """ + Prewarms an index in the table + + This loads the entire index into memory + + If the index does not fit into the available cache this call + may be wasteful + + Parameters + ---------- + name: str + The name of the index to prewarm + """ + return LOOP.run(self._table.prewarm_index(name)) + def create_scalar_index( self, column: str, @@ -3002,6 +3026,23 @@ class AsyncTable: """ await self._inner.drop_index(name) + async def prewarm_index(self, name: str) -> None: + """ + Prewarm an index in the table. + + Parameters + ---------- + name: str + The name of the index to prewarm + + Notes + ----- + This will load the index into memory. This may reduce the cold-start time for + future queries. If the index does not fit in the cache then this call may be + wasteful. + """ + await self._inner.prewarm_index(name) + async def add( self, data: DATA, diff --git a/python/python/tests/test_index.py b/python/python/tests/test_index.py index 59611264..781fb710 100644 --- a/python/python/tests/test_index.py +++ b/python/python/tests/test_index.py @@ -8,7 +8,7 @@ import pyarrow as pa import pytest import pytest_asyncio from lancedb import AsyncConnection, AsyncTable, connect_async -from lancedb.index import BTree, IvfFlat, IvfPq, Bitmap, LabelList, HnswPq, HnswSq +from lancedb.index import BTree, IvfFlat, IvfPq, Bitmap, LabelList, HnswPq, HnswSq, FTS @pytest_asyncio.fixture @@ -119,6 +119,18 @@ async def test_create_label_list_index(some_table: AsyncTable): assert str(indices) == '[Index(LabelList, columns=["tags"], name="tags_idx")]' +@pytest.mark.asyncio +async def test_full_text_search_index(some_table: AsyncTable): + await some_table.create_index("tags", config=FTS(with_position=False)) + indices = await some_table.list_indices() + assert str(indices) == '[Index(FTS, columns=["tags"], name="tags_idx")]' + + await some_table.prewarm_index("tags_idx") + + res = await (await some_table.search("tag0")).to_arrow() + assert res.num_rows > 0 + + @pytest.mark.asyncio async def test_create_vector_index(some_table: AsyncTable): # Can create diff --git a/python/src/table.rs b/python/src/table.rs index 60d88a1f..0b0d4671 100644 --- a/python/src/table.rs +++ b/python/src/table.rs @@ -204,6 +204,14 @@ impl Table { }) } + pub fn prewarm_index(self_: PyRef<'_, Self>, index_name: String) -> PyResult> { + let inner = self_.inner_ref()?.clone(); + future_into_py(self_.py(), async move { + inner.prewarm_index(&index_name).await.infer_error()?; + Ok(()) + }) + } + pub fn list_indices(self_: PyRef<'_, Self>) -> PyResult> { let inner = self_.inner_ref()?.clone(); future_into_py(self_.py(), async move { diff --git a/python/src/util.rs b/python/src/util.rs index 225827b3..e438cd6a 100644 --- a/python/src/util.rs +++ b/python/src/util.rs @@ -163,8 +163,9 @@ pub fn parse_fts_query(query: &Bound<'_, PyDict>) -> PyResult { .ok_or(PyValueError::new_err("boost not found"))? .extract::>()?; - let query = - MultiMatchQuery::try_new_with_boosts(query, columns, boost).map_err(|e| { + let query = MultiMatchQuery::try_new(query, columns) + .and_then(|q| q.try_with_boosts(boost)) + .map_err(|e| { PyValueError::new_err(format!("Error creating MultiMatchQuery: {}", e)) })?; Ok(query.into()) diff --git a/rust/lancedb/src/remote/table.rs b/rust/lancedb/src/remote/table.rs index d6817d89..73f909e9 100644 --- a/rust/lancedb/src/remote/table.rs +++ b/rust/lancedb/src/remote/table.rs @@ -1003,6 +1003,12 @@ impl BaseTable for RemoteTable { Ok(()) } + async fn prewarm_index(&self, _index_name: &str) -> Result<()> { + Err(Error::NotSupported { + message: "prewarm_index is not yet supported on LanceDB cloud.".into(), + }) + } + async fn table_definition(&self) -> Result { Err(Error::NotSupported { message: "table_definition is not supported on LanceDB cloud.".into(), @@ -1769,6 +1775,7 @@ mod tests { "boost": 1.0, "fuzziness": 0, "max_expansions": 50, + "operator": "Or", }, } }, diff --git a/rust/lancedb/src/table.rs b/rust/lancedb/src/table.rs index 38d5990f..36151dc7 100644 --- a/rust/lancedb/src/table.rs +++ b/rust/lancedb/src/table.rs @@ -455,6 +455,8 @@ pub trait BaseTable: std::fmt::Display + std::fmt::Debug + Send + Sync { async fn list_indices(&self) -> Result>; /// Drop an index from the table. async fn drop_index(&self, name: &str) -> Result<()>; + /// Prewarm an index in the table + async fn prewarm_index(&self, name: &str) -> Result<()>; /// Get statistics about the index. async fn index_stats(&self, index_name: &str) -> Result>; /// Merge insert new records into the table. @@ -1086,6 +1088,22 @@ impl Table { self.inner.drop_index(name).await } + /// Prewarm an index in the table + /// + /// This is a hint to fully load the index into memory. It can be used to + /// avoid cold starts + /// + /// It is generally wasteful to call this if the index does not fit into the + /// available cache. + /// + /// Note: This function is not yet supported on all indices, in which case it + /// may do nothing. + /// + /// Use [`Self::list_indices()`] to find the names of the indices. + pub async fn prewarm_index(&self, name: &str) -> Result<()> { + self.inner.prewarm_index(name).await + } + // Take many execution plans and map them into a single plan that adds // a query_index column and unions them. pub(crate) fn multi_vector_plan( @@ -2006,6 +2024,11 @@ impl BaseTable for NativeTable { Ok(()) } + async fn prewarm_index(&self, index_name: &str) -> Result<()> { + let dataset = self.dataset.get().await?; + Ok(dataset.prewarm_index(index_name).await?) + } + async fn update(&self, update: UpdateBuilder) -> Result { let dataset = self.dataset.get().await?.clone(); let mut builder = LanceUpdateBuilder::new(Arc::new(dataset)); @@ -3455,6 +3478,9 @@ mod tests { assert_eq!(stats.num_unindexed_rows, 0); assert_eq!(stats.index_type, crate::index::IndexType::FTS); assert_eq!(stats.distance_type, None); + + // Make sure we can call prewarm without error + table.prewarm_index("text_idx").await.unwrap(); } #[tokio::test] @@ -3550,7 +3576,7 @@ mod tests { let native_tbl = table.as_native().unwrap(); let manifest = native_tbl.manifest().await.unwrap(); - assert_eq!(manifest.config.len(), 0); + let base_config_len = manifest.config.len(); native_tbl .update_config(vec![("test_key1".to_string(), "test_val1".to_string())]) @@ -3558,7 +3584,7 @@ mod tests { .unwrap(); let manifest = native_tbl.manifest().await.unwrap(); - assert_eq!(manifest.config.len(), 1); + assert_eq!(manifest.config.len(), 1 + base_config_len); assert_eq!( manifest.config.get("test_key1"), Some(&"test_val1".to_string()) @@ -3569,7 +3595,7 @@ mod tests { .await .unwrap(); let manifest = native_tbl.manifest().await.unwrap(); - assert_eq!(manifest.config.len(), 2); + assert_eq!(manifest.config.len(), 2 + base_config_len); assert_eq!( manifest.config.get("test_key1"), Some(&"test_val1".to_string()) @@ -3587,7 +3613,7 @@ mod tests { .await .unwrap(); let manifest = native_tbl.manifest().await.unwrap(); - assert_eq!(manifest.config.len(), 2); + assert_eq!(manifest.config.len(), 2 + base_config_len); assert_eq!( manifest.config.get("test_key1"), Some(&"test_val1".to_string()) @@ -3599,7 +3625,7 @@ mod tests { native_tbl.delete_config_keys(&["test_key1"]).await.unwrap(); let manifest = native_tbl.manifest().await.unwrap(); - assert_eq!(manifest.config.len(), 1); + assert_eq!(manifest.config.len(), 1 + base_config_len); assert_eq!( manifest.config.get("test_key2"), Some(&"test_val2_update".to_string())