This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch branch-lance-namepspace-dev
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-lance-namepspace-dev by 
this push:
     new f6d49d95e5 [#8891] feat(lance-rest-server): Add standalone and 
auxiliary mode support for Lance REST service (#8903)
f6d49d95e5 is described below

commit f6d49d95e58947ec27fef0ea5bc14850637421ee
Author: Junda Yang <[email protected]>
AuthorDate: Thu Oct 23 23:54:43 2025 -0700

    [#8891] feat(lance-rest-server): Add standalone and auxiliary mode support 
for Lance REST service (#8903)
    
    ### What changes were proposed in this pull request?
    
    1. Created service discovery file
    (META-INF/services/org.apache.gravitino.auxiliary.GravitinoAuxiliaryService)
    2. Added unit tests (TestLanceConfig.java)
    
    ### Why are the changes needed?
    Fix: #8891
    
    To enable flexible deployment of Lance REST service:
    
    Standalone mode (independent JVM):
    - Lance needs to connect to Gravitino server via HTTP to access
    catalog/schema/table metadata
    - GRAVITINO_URI and GRAVITINO_METALAKE configs specify the connection
    parameters
    - Use case: Deploy Lance REST separately for isolation or scaling
    
    Auxiliary mode (embedded in Gravitino server):
    - Lance runs in the same JVM as Gravitino, enabling direct memory access
    (zero overhead)
    - META-INF/services file enables automatic service discovery via Java
    ServiceLoader
    - Use case: Simplified deployment with shared resources and unified
    monitoring
    
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes - New configuration properties
    
    For Standalone Mode:
    ```
    # Required: Gravitino server URI
    gravitino.lance-rest.gravitino-uri=http://gravitino-server:8090
    
    # Required: Metalake name
    gravitino.lance-rest.gravitino-metalake=production
    ```
    
    For Auxiliary Mode:
    ```
    # Enable Lance REST as auxiliary service
    gravitino.auxService.names=iceberg-rest,lance-rest
    
    # Classpath for Lance REST JAR
    gravitino.lance-rest.classpath=lance/lance-rest-server/build/libs
    ```
    
    Deployment modes supported:
    Standalone: Lance REST runs independently, connects to Gravitino via
    HTTP
    Auxiliary: Lance REST runs embedded in Gravitino, uses direct memory
    access
    No breaking changes - all changes are additive and backward compatible.
    
    ### How was this patch tested?
    
    1. unit test
    2. manual test
    
    **Standalone mode test:**
    ```
    junda@java(junda.devpod-us-or) ~/gravitino/distribution/package/bin
     % ./gravitino.sh start
    Gravitino Server is running[PID:3907790]
    junda@java(junda.devpod-us-or) ~
     % curl http://localhost:8090/api/version
    {"code":0,"version":{"version":"1.1.0-SNAPSHOT","compileDate":"23/10/2025 
21:03:17","gitCommit":"35bd819975badea2493b4dbd9d0de68425229945"}}%
    
    junda@java(junda.devpod-us-or) ~/gravitino/distribution/package/bin
     % ./gravitino-lance-rest-server.sh start
    GravitinoLanceRESTServer is running[PID:3930096]
    junda@java(junda.devpod-us-or) ~
     % curl "http://localhost:9101/lance/v1/namespace/root/list";
    {"id":"root","delimiter":"$","namespaces":["default"]}%
    ```
    
    **Auxiliary mode test:**
    ```
    junda@java(junda.devpod-us-or) ~/gravitino/distribution/package
     % cd /home/user/gravitino && cat >> 
distribution/package/conf/gravitino.conf << 'EOF'
    
    # ===== Lance REST Auxiliary Service =====
    gravitino.auxService.names = iceberg-rest,lance-rest
    gravitino.lance-rest.classpath = 
/home/user/gravitino/lance/lance-rest-server/build/libs
    gravitino.lance-rest.catalog-name = lance_catalog
    EOF
    
    junda@java(junda.devpod-us-or) ~/gravitino/distribution/package
     % ./bin/gravitino.sh start
    Gravitino Server is running[PID:274396]
    
    junda@java(junda.devpod-us-or) ~/gravitino/distribution/package
     % tail -50 logs/gravitino-server.log | grep -i lance | grep -i started
    2025-10-23 21:34:41.495 INFO [main] 
[org.apache.gravitino.server.web.JettyServer.start(JettyServer.java:202)] - 
lance-rest web server started on host 0.0.0.0 port 9101.
    2025-10-23 21:34:41.495 INFO [main] 
[org.apache.gravitino.lance.LanceRESTService.serviceStart(LanceRESTService.java:77)]
 - Lance REST service started
    ```
---
 lance/lance-common/build.gradle.kts                |   1 +
 .../gravitino/lance/common/config/LanceConfig.java |   8 ++
 .../lance/common/config/TestLanceConfig.java       | 114 +++++++++++++++++++++
 ...e.gravitino.auxiliary.GravitinoAuxiliaryService |  19 ++++
 4 files changed, 142 insertions(+)

diff --git a/lance/lance-common/build.gradle.kts 
b/lance/lance-common/build.gradle.kts
index 4e91dd6c5c..27057950f3 100644
--- a/lance/lance-common/build.gradle.kts
+++ b/lance/lance-common/build.gradle.kts
@@ -42,6 +42,7 @@ dependencies {
   implementation(libs.lance.namespace.core)
   implementation(libs.slf4j.api)
 
+  testImplementation(project(":server-common"))
   testImplementation(libs.junit.jupiter.api)
   testRuntimeOnly(libs.junit.jupiter.engine)
 }
diff --git 
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/config/LanceConfig.java
 
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/config/LanceConfig.java
index dfe863953e..b6614c87ee 100644
--- 
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/config/LanceConfig.java
+++ 
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/config/LanceConfig.java
@@ -80,6 +80,14 @@ public class LanceConfig extends Config implements 
OverwriteDefaultConfig {
     return get(CATALOG_NAME);
   }
 
+  public String getNamespaceUri() {
+    return get(NAMESPACE_URI);
+  }
+
+  public String getGravitinoMetalake() {
+    return get(METALAKE_NAME);
+  }
+
   @Override
   public Map<String, String> getOverwriteDefaultConfig() {
     return ImmutableMap.of(
diff --git 
a/lance/lance-common/src/test/java/org/apache/gravitino/lance/common/config/TestLanceConfig.java
 
b/lance/lance-common/src/test/java/org/apache/gravitino/lance/common/config/TestLanceConfig.java
new file mode 100644
index 0000000000..176634f309
--- /dev/null
+++ 
b/lance/lance-common/src/test/java/org/apache/gravitino/lance/common/config/TestLanceConfig.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.lance.common.config;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.apache.gravitino.server.web.JettyServerConfig;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestLanceConfig {
+  @Test
+  public void testLoadLanceConfig() {
+    Map<String, String> properties =
+        ImmutableMap.of("gravitino.lance-rest.catalog-name", "test_catalog");
+
+    LanceConfig lanceConfig = new LanceConfig();
+    lanceConfig.loadFromMap(properties, k -> 
k.startsWith("gravitino.lance-rest."));
+    Assertions.assertEquals("test_catalog", lanceConfig.getCatalogName());
+
+    LanceConfig lanceConfig2 = new LanceConfig(properties);
+    Assertions.assertEquals("test_catalog", lanceConfig2.getCatalogName());
+  }
+
+  @Test
+  public void testDefaultCatalogName() {
+    // Test default catalog name when not specified
+    Map<String, String> properties = ImmutableMap.of();
+    LanceConfig lanceConfig = new LanceConfig(properties);
+    Assertions.assertEquals("default", lanceConfig.getCatalogName());
+  }
+
+  @Test
+  public void testLanceHttpPort() {
+    Map<String, String> properties = ImmutableMap.of();
+    LanceConfig lanceConfig = new LanceConfig(properties);
+    JettyServerConfig jettyServerConfig = 
JettyServerConfig.fromConfig(lanceConfig);
+    Assertions.assertEquals(
+        LanceConfig.DEFAULT_LANCE_REST_SERVICE_HTTP_PORT, 
jettyServerConfig.getHttpPort());
+    Assertions.assertEquals(
+        LanceConfig.DEFAULT_LANCE_REST_SERVICE_HTTPS_PORT, 
jettyServerConfig.getHttpsPort());
+
+    properties =
+        ImmutableMap.of(
+            JettyServerConfig.WEBSERVER_HTTP_PORT.getKey(),
+            "9101",
+            JettyServerConfig.WEBSERVER_HTTPS_PORT.getKey(),
+            "9533");
+    lanceConfig = new LanceConfig(properties);
+    jettyServerConfig = JettyServerConfig.fromConfig(lanceConfig);
+    Assertions.assertEquals(9101, jettyServerConfig.getHttpPort());
+    Assertions.assertEquals(9533, jettyServerConfig.getHttpsPort());
+  }
+
+  @Test
+  public void testGravitinoUriAndMetalake() {
+    // Test default values
+    Map<String, String> properties = ImmutableMap.of();
+    LanceConfig lanceConfig = new LanceConfig(properties);
+    Assertions.assertEquals("http://localhost:8090";, 
lanceConfig.getNamespaceUri());
+    Assertions.assertNull(lanceConfig.getGravitinoMetalake()); // No default, 
must be configured
+
+    // Test custom values
+    properties =
+        ImmutableMap.of(
+            LanceConfig.NAMESPACE_URI.getKey(),
+            "http://gravitino-server:8090";,
+            LanceConfig.METALAKE_NAME.getKey(),
+            "production");
+    lanceConfig = new LanceConfig(properties);
+    Assertions.assertEquals("http://gravitino-server:8090";, 
lanceConfig.getNamespaceUri());
+    Assertions.assertEquals("production", lanceConfig.getGravitinoMetalake());
+  }
+
+  @Test
+  public void testCompleteConfiguration() {
+    // Test all configurations together for auxiliary mode
+    Map<String, String> properties =
+        ImmutableMap.<String, String>builder()
+            .put(LanceConfig.CATALOG_NAME.getKey(), "lance_catalog")
+            .put(LanceConfig.NAMESPACE_URI.getKey(), 
"http://gravitino-prod:8090";)
+            .put(LanceConfig.METALAKE_NAME.getKey(), "production")
+            .put(LanceConfig.NAMESPACE_BACKEND.getKey(), "gravitino")
+            .put(JettyServerConfig.WEBSERVER_HTTP_PORT.getKey(), "9101")
+            .build();
+
+    LanceConfig lanceConfig = new LanceConfig(properties);
+
+    // Verify all config values
+    Assertions.assertEquals("lance_catalog", lanceConfig.getCatalogName());
+    Assertions.assertEquals("http://gravitino-prod:8090";, 
lanceConfig.getNamespaceUri());
+    Assertions.assertEquals("production", lanceConfig.getGravitinoMetalake());
+
+    JettyServerConfig jettyConfig = JettyServerConfig.fromConfig(lanceConfig);
+    Assertions.assertEquals(9101, jettyConfig.getHttpPort());
+  }
+}
diff --git 
a/lance/lance-rest-server/src/main/resources/META-INF/services/org.apache.gravitino.auxiliary.GravitinoAuxiliaryService
 
b/lance/lance-rest-server/src/main/resources/META-INF/services/org.apache.gravitino.auxiliary.GravitinoAuxiliaryService
new file mode 100644
index 0000000000..97c3f356df
--- /dev/null
+++ 
b/lance/lance-rest-server/src/main/resources/META-INF/services/org.apache.gravitino.auxiliary.GravitinoAuxiliaryService
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.gravitino.lance.LanceRESTService

Reply via email to