This is an automated email from the ASF dual-hosted git repository.
yuqi4733 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 48342acd5c [#8955] feat(lance-rest): Support register and deregister
table in Lance REST server. (#8964)
48342acd5c is described below
commit 48342acd5c6acb2296aa185a55500f8021f894c0
Author: Mini Yu <[email protected]>
AuthorDate: Fri Oct 31 22:52:44 2025 +0800
[#8955] feat(lance-rest): Support register and deregister table in Lance
REST server. (#8964)
### What changes were proposed in this pull request?
Support API `registerTable` and `deregisterTable` in Lance REST server.
### Why are the changes needed?
It's from user requirement.
Fix: #8955
### Does this PR introduce _any_ user-facing change?
N/A
### How was this patch tested?
Test locally.
---
.../GenericLakehouseCatalogOperations.java | 49 ++++++++++++--
.../GenericLakehouseTablePropertiesMetadata.java | 12 +++-
.../catalog/TableOperationDispatcher.java | 4 ++
lance/lance-common/build.gradle.kts | 3 +-
.../lance/common/ops/LanceTableOperations.java | 8 ++-
.../gravitino/GravitinoLanceNamespaceWrapper.java | 79 +++++++++++++++++++---
.../apache/gravitino/lance/LanceRESTService.java | 1 +
.../gravitino/lance/service/ServiceConstants.java} | 22 ++----
.../lance/service/rest/LanceTableOperations.java | 79 +++++++++++++++++++---
9 files changed, 214 insertions(+), 43 deletions(-)
diff --git
a/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseCatalogOperations.java
b/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseCatalogOperations.java
index 89a0ef58ef..60c0958c14 100644
---
a/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseCatalogOperations.java
+++
b/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseCatalogOperations.java
@@ -210,6 +210,8 @@ public class GenericLakehouseCatalogOperations
.withName(tableEntity.name())
.withComment(tableEntity.getComment())
.build();
+ } catch (NoSuchEntityException e) {
+ throw new NoSuchTableException(e, "Table %s does not exist", ident);
} catch (IOException e) {
throw new RuntimeException("Failed to list tables under schema " +
ident.namespace(), e);
}
@@ -270,6 +272,34 @@ public class GenericLakehouseCatalogOperations
.withAuditInfo(auditInfo)
.build();
store.put(entityToStore);
+
+ // Get the value of register in table properties
+ boolean register =
+ Boolean.parseBoolean(
+ properties.getOrDefault(
+ GenericLakehouseTablePropertiesMetadata.LAKEHOUSE_REGISTER,
"false"));
+ if (register) {
+ // Do not need to create the physical table if this is a registration
operation.
+ // Whether we need to check the existence of the physical table?
+ GenericLakehouseTable.Builder builder =
GenericLakehouseTable.builder();
+ return builder
+ .withName(ident.name())
+ .withColumns(columns)
+ .withComment(comment)
+ .withProperties(properties)
+ .withDistribution(distribution)
+ .withIndexes(indexes)
+ .withAuditInfo(
+ AuditInfo.builder()
+ .withCreator(PrincipalUtils.getCurrentUserName())
+ .withCreateTime(Instant.now())
+ .build())
+ .withPartitioning(partitions)
+ .withSortOrders(sortOrders)
+ .withFormat(LakehouseTableFormat.LANCE.lowerName())
+ .build();
+ }
+
LakehouseCatalogOperations lanceCatalogOperations =
getLakehouseCatalogOperations(newProperties);
return lanceCatalogOperations.createTable(
@@ -324,7 +354,6 @@ public class GenericLakehouseCatalogOperations
@Override
public Table alterTable(NameIdentifier ident, TableChange... changes)
throws NoSuchTableException, IllegalArgumentException {
- Namespace namespace = ident.namespace();
try {
TableEntity tableEntity = store.get(ident, Entity.EntityType.TABLE,
TableEntity.class);
Map<String, String> tableProperties = tableEntity.getProperties();
@@ -332,13 +361,12 @@ public class GenericLakehouseCatalogOperations
getLakehouseCatalogOperations(tableProperties);
return lakehouseCatalogOperations.alterTable(ident, changes);
} catch (IOException e) {
- throw new RuntimeException("Failed to list tables under schema " +
namespace, e);
+ throw new RuntimeException("Failed to alter table " + ident, e);
}
}
@Override
public boolean dropTable(NameIdentifier ident) {
- Namespace namespace = ident.namespace();
try {
TableEntity tableEntity = store.get(ident, Entity.EntityType.TABLE,
TableEntity.class);
LakehouseCatalogOperations lakehouseCatalogOperations =
@@ -348,7 +376,20 @@ public class GenericLakehouseCatalogOperations
LOG.warn("Table {} does not exist, skip dropping it.", ident);
return false;
} catch (IOException e) {
- throw new RuntimeException("Failed to list tables under schema " +
namespace, e);
+ throw new RuntimeException("Failed to drop table: " + ident, e);
+ }
+ }
+
+ @Override
+ public boolean purgeTable(NameIdentifier ident) throws
UnsupportedOperationException {
+ try {
+ // Only delete the metadata entry here. The physical data will not be
deleted.
+ if (!tableExists(ident)) {
+ return false;
+ }
+ return store.delete(ident, Entity.EntityType.TABLE);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to purge table " + ident, e);
}
}
diff --git
a/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseTablePropertiesMetadata.java
b/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseTablePropertiesMetadata.java
index f8ca11b0a0..72c1e5bc57 100644
---
a/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseTablePropertiesMetadata.java
+++
b/catalogs/catalog-generic-lakehouse/src/main/java/org/apache/gravitino/catalog/lakehouse/GenericLakehouseTablePropertiesMetadata.java
@@ -18,6 +18,7 @@
*/
package org.apache.gravitino.catalog.lakehouse;
+import static
org.apache.gravitino.connector.PropertyEntry.booleanPropertyEntry;
import static org.apache.gravitino.connector.PropertyEntry.enumPropertyEntry;
import static
org.apache.gravitino.connector.PropertyEntry.stringOptionalPropertyEntry;
@@ -32,6 +33,7 @@ public class GenericLakehouseTablePropertiesMetadata extends
BasePropertiesMetad
public static final String LAKEHOUSE_LOCATION = "location";
public static final String LAKEHOUSE_FORMAT = "format";
public static final String LANCE_TABLE_STORAGE_OPTION_PREFIX =
"lance.storage.";
+ public static final String LAKEHOUSE_REGISTER = "register";
private static final Map<String, PropertyEntry<?>> PROPERTIES_METADATA;
@@ -59,7 +61,15 @@ public class GenericLakehouseTablePropertiesMetadata extends
BasePropertiesMetad
false /* immutable */,
null /* default value*/,
false /* hidden */,
- false /* reserved */));
+ false /* reserved */),
+ booleanPropertyEntry(
+ LAKEHOUSE_REGISTER,
+ "Whether this is a table registration operation.",
+ false,
+ true /* immutable */,
+ false /* defaultValue */,
+ false /* hidden */,
+ false));
PROPERTIES_METADATA = Maps.uniqueIndex(propertyEntries,
PropertyEntry::getName);
}
diff --git
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
index e549b806d8..6289bd3404 100644
---
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
+++
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
@@ -408,6 +408,10 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
RuntimeException.class,
UnsupportedOperationException.class);
+ if (isManagedTable(catalogIdent)) {
+ return droppedFromCatalog;
+ }
+
// For unmanaged table, it could happen that the table:
// 1. Is not found in the catalog (dropped directly from underlying
sources)
// 2. Is found in the catalog but not in the store (not managed by
Gravitino)
diff --git a/lance/lance-common/build.gradle.kts
b/lance/lance-common/build.gradle.kts
index 6e18f3981f..5be0eae4bf 100644
--- a/lance/lance-common/build.gradle.kts
+++ b/lance/lance-common/build.gradle.kts
@@ -25,7 +25,8 @@ plugins {
}
dependencies {
- implementation(project(":clients:client-java-runtime", configuration =
"shadow"))
+ implementation(project(":clients:client-java"))
+ implementation(project(":api"))
implementation(project(":common")) {
exclude("*")
}
diff --git
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
index b8a967cd30..8a356fb135 100644
---
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
+++
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
@@ -19,7 +19,9 @@
package org.apache.gravitino.lance.common.ops;
import com.lancedb.lance.namespace.model.CreateTableResponse;
+import com.lancedb.lance.namespace.model.DeregisterTableResponse;
import com.lancedb.lance.namespace.model.DescribeTableResponse;
+import com.lancedb.lance.namespace.model.RegisterTableResponse;
import java.util.Map;
public interface LanceTableOperations {
@@ -32,6 +34,10 @@ public interface LanceTableOperations {
String delimiter,
String tableLocation,
Map<String, String> tableProperties,
- String rootCatalog,
byte[] arrowStreamBody);
+
+ RegisterTableResponse registerTable(
+ String tableId, String mode, String delimiter, Map<String, String>
tableProperties);
+
+ DeregisterTableResponse deregisterTable(String tableId, String delimiter);
}
diff --git
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/gravitino/GravitinoLanceNamespaceWrapper.java
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/gravitino/GravitinoLanceNamespaceWrapper.java
index d3ddbb0ede..865313b31c 100644
---
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/gravitino/GravitinoLanceNamespaceWrapper.java
+++
b/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/gravitino/GravitinoLanceNamespaceWrapper.java
@@ -35,6 +35,7 @@ import
com.lancedb.lance.namespace.model.CreateNamespaceRequest;
import com.lancedb.lance.namespace.model.CreateNamespaceRequest.ModeEnum;
import com.lancedb.lance.namespace.model.CreateNamespaceResponse;
import com.lancedb.lance.namespace.model.CreateTableResponse;
+import com.lancedb.lance.namespace.model.DeregisterTableResponse;
import com.lancedb.lance.namespace.model.DescribeNamespaceResponse;
import com.lancedb.lance.namespace.model.DescribeTableResponse;
import com.lancedb.lance.namespace.model.DropNamespaceRequest;
@@ -42,6 +43,8 @@ import
com.lancedb.lance.namespace.model.DropNamespaceResponse;
import com.lancedb.lance.namespace.model.JsonArrowSchema;
import com.lancedb.lance.namespace.model.ListNamespacesResponse;
import com.lancedb.lance.namespace.model.ListTablesResponse;
+import com.lancedb.lance.namespace.model.RegisterTableRequest;
+import com.lancedb.lance.namespace.model.RegisterTableResponse;
import com.lancedb.lance.namespace.util.CommonUtil;
import com.lancedb.lance.namespace.util.JsonArrowSchemaConverter;
import com.lancedb.lance.namespace.util.PageUtil;
@@ -492,7 +495,7 @@ public class GravitinoLanceNamespaceWrapper extends
NamespaceWrapper
String namespaceId, String delimiter, String pageToken, Integer limit) {
ObjectIdentifier nsId = ObjectIdentifier.of(namespaceId,
Pattern.quote(delimiter));
Preconditions.checkArgument(
- nsId.levels() <= 2, "Expected at most 2-level namespace but got: %s",
nsId.levels());
+ nsId.levels() == 2, "Expected 2-level namespace but got: %s",
nsId.levels());
String catalogName = nsId.levelAtListPos(0);
Catalog catalog = loadAndValidateLakehouseCatalog(catalogName);
String schemaName = nsId.levelAtListPos(1);
@@ -516,7 +519,7 @@ public class GravitinoLanceNamespaceWrapper extends
NamespaceWrapper
public DescribeTableResponse describeTable(String tableId, String delimiter)
{
ObjectIdentifier nsId = ObjectIdentifier.of(tableId,
Pattern.quote(delimiter));
Preconditions.checkArgument(
- nsId.levels() <= 3, "Expected at most 3-level namespace but got: %s",
nsId.levels());
+ nsId.levels() == 3, "Expected at 3-level namespace but got: %s",
nsId.levels());
String catalogName = nsId.levelAtListPos(0);
Catalog catalog = loadAndValidateLakehouseCatalog(catalogName);
@@ -538,17 +541,10 @@ public class GravitinoLanceNamespaceWrapper extends
NamespaceWrapper
String delimiter,
String tableLocation,
Map<String, String> tableProperties,
- String rootCatalog,
byte[] arrowStreamBody) {
ObjectIdentifier nsId = ObjectIdentifier.of(tableId,
Pattern.quote(delimiter));
Preconditions.checkArgument(
- nsId.levels() <= 3, "Expected at most 3-level namespace but got: %s",
nsId.levels());
- if (rootCatalog != null) {
- List<String> levels = nsId.listStyleId();
- List<String> newLevels = Lists.newArrayList(rootCatalog);
- newLevels.addAll(levels);
- nsId = ObjectIdentifier.of(newLevels);
- }
+ nsId.levels() == 3, "Expected at 3-level namespace but got: %s",
nsId.levels());
// Parser column information.
List<Column> columns = Lists.newArrayList();
@@ -614,6 +610,68 @@ public class GravitinoLanceNamespaceWrapper extends
NamespaceWrapper
return response;
}
+ @Override
+ public RegisterTableResponse registerTable(
+ String tableId, String mode, String delimiter, Map<String, String>
tableProperties) {
+ ObjectIdentifier nsId = ObjectIdentifier.of(tableId,
Pattern.quote(delimiter));
+ Preconditions.checkArgument(
+ nsId.levels() == 3, "Expected at 3-level namespace but got: %s",
nsId.levels());
+
+ String catalogName = nsId.levelAtListPos(0);
+ Catalog catalog = loadAndValidateLakehouseCatalog(catalogName);
+ NameIdentifier tableIdentifier =
+ NameIdentifier.of(nsId.levelAtListPos(1), nsId.levelAtListPos(2));
+
+ // TODO Support real register API
+ RegisterTableRequest.ModeEnum createMode =
+ RegisterTableRequest.ModeEnum.fromValue(mode.toUpperCase());
+ if (createMode == RegisterTableRequest.ModeEnum.CREATE
+ && catalog.asTableCatalog().tableExists(tableIdentifier)) {
+ throw LanceNamespaceException.conflict(
+ "Table already exists: " + tableId,
+ SchemaAlreadyExistsException.class.getSimpleName(),
+ tableId,
+ CommonUtil.formatCurrentStackTrace());
+ }
+
+ if (createMode == RegisterTableRequest.ModeEnum.OVERWRITE
+ && catalog.asTableCatalog().tableExists(tableIdentifier)) {
+ LOG.info("Overwriting existing table: {}", tableId);
+ catalog.asTableCatalog().dropTable(tableIdentifier);
+ }
+
+ Table t =
+ catalog.asTableCatalog().createTable(tableIdentifier, new Column[] {},
"", tableProperties);
+
+ RegisterTableResponse response = new RegisterTableResponse();
+ response.setProperties(t.properties());
+ response.setLocation(t.properties().get("location"));
+ return response;
+ }
+
+ @Override
+ public DeregisterTableResponse deregisterTable(String tableId, String
delimiter) {
+
+ ObjectIdentifier nsId = ObjectIdentifier.of(tableId,
Pattern.quote(delimiter));
+ Preconditions.checkArgument(
+ nsId.levels() == 3, "Expected at 3-level namespace but got: %s",
nsId.levels());
+
+ String catalogName = nsId.levelAtListPos(0);
+ Catalog catalog = loadAndValidateLakehouseCatalog(catalogName);
+
+ NameIdentifier tableIdentifier =
+ NameIdentifier.of(nsId.levelAtListPos(1), nsId.levelAtListPos(2));
+ Table t = catalog.asTableCatalog().loadTable(tableIdentifier);
+ Map<String, String> properties = t.properties();
+ // TODO Support real deregister API.
+ catalog.asTableCatalog().purgeTable(tableIdentifier);
+
+ DeregisterTableResponse response = new DeregisterTableResponse();
+ response.setProperties(properties);
+ response.setLocation(properties.get("location"));
+ return response;
+ }
+
private JsonArrowSchema toJsonArrowSchema(Column[] columns) {
List<Field> fields =
Arrays.stream(columns)
@@ -627,7 +685,6 @@ public class GravitinoLanceNamespaceWrapper extends
NamespaceWrapper
@VisibleForTesting
org.apache.arrow.vector.types.pojo.Schema parseArrowIpcStream(byte[] stream)
{
org.apache.arrow.vector.types.pojo.Schema schema;
-
try (BufferAllocator allocator = new RootAllocator();
ByteArrayInputStream bais = new ByteArrayInputStream(stream);
ArrowStreamReader reader = new ArrowStreamReader(bais, allocator)) {
diff --git
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/LanceRESTService.java
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/LanceRESTService.java
index 8c800e49d6..afab3ab2a7 100644
---
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/LanceRESTService.java
+++
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/LanceRESTService.java
@@ -127,6 +127,7 @@ public class LanceRESTService implements
GravitinoAuxiliaryService {
try {
Constructor<? extends NamespaceWrapper> constructor =
lanceNamespaceBackend.getWrapperClass().getConstructor(LanceConfig.class);
+
return constructor.newInstance(lanceConfig);
} catch (Exception e) {
LOG.error("Error loading namespace implementation for backend type: {}",
backendType, e);
diff --git
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/ServiceConstants.java
similarity index 60%
copy from
lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
copy to
lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/ServiceConstants.java
index b8a967cd30..f39ea2e684 100644
---
a/lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/LanceTableOperations.java
+++
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/ServiceConstants.java
@@ -16,22 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.lance.common.ops;
-import com.lancedb.lance.namespace.model.CreateTableResponse;
-import com.lancedb.lance.namespace.model.DescribeTableResponse;
-import java.util.Map;
+package org.apache.gravitino.lance.service;
-public interface LanceTableOperations {
+public class ServiceConstants {
+ public static final String LANCE_HTTP_HEADER_PREFIX = "x-lance-";
- DescribeTableResponse describeTable(String tableId, String delimiter);
-
- CreateTableResponse createTable(
- String tableId,
- String mode,
- String delimiter,
- String tableLocation,
- Map<String, String> tableProperties,
- String rootCatalog,
- byte[] arrowStreamBody);
+ public static final String LANCE_TABLE_LOCATION_HEADER =
+ LANCE_HTTP_HEADER_PREFIX + "table-location";
+ public static final String LANCE_TABLE_PROPERTIES_PREFIX_HEADER =
+ LANCE_HTTP_HEADER_PREFIX + "table-properties";
}
diff --git
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/rest/LanceTableOperations.java
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/rest/LanceTableOperations.java
index 690cb8759e..5590eef9bd 100644
---
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/rest/LanceTableOperations.java
+++
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/rest/LanceTableOperations.java
@@ -19,24 +19,33 @@
package org.apache.gravitino.lance.service.rest;
import static
org.apache.gravitino.lance.common.ops.NamespaceWrapper.NAMESPACE_DELIMITER_DEFAULT;
+import static
org.apache.gravitino.lance.service.ServiceConstants.LANCE_TABLE_LOCATION_HEADER;
+import static
org.apache.gravitino.lance.service.ServiceConstants.LANCE_TABLE_PROPERTIES_PREFIX_HEADER;
import com.codahale.metrics.annotation.ResponseMetered;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.collect.Maps;
import com.lancedb.lance.namespace.model.CreateTableResponse;
+import com.lancedb.lance.namespace.model.DeregisterTableRequest;
+import com.lancedb.lance.namespace.model.DeregisterTableResponse;
import com.lancedb.lance.namespace.model.DescribeTableResponse;
+import com.lancedb.lance.namespace.model.RegisterTableRequest;
+import com.lancedb.lance.namespace.model.RegisterTableResponse;
import com.lancedb.lance.namespace.util.JsonUtil;
import java.util.Map;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
-import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.lance.common.ops.NamespaceWrapper;
@@ -81,18 +90,20 @@ public class LanceTableOperations {
@PathParam("id") String tableId,
@QueryParam("mode") @DefaultValue("create") String mode, // create,
exist_ok, overwrite
@QueryParam("delimiter") @DefaultValue(NAMESPACE_DELIMITER_DEFAULT)
String delimiter,
- @HeaderParam("x-lance-table-location") String tableLocation,
- @HeaderParam("x-lance-table-properties") String tableProperties,
- @HeaderParam("x-lance-root-catalog") String rootCatalog,
+ @Context HttpHeaders headers,
byte[] arrowStreamBody) {
try {
+ // Extract table properties from header
+ MultivaluedMap<String, String> headersMap = headers.getRequestHeaders();
+ String tableLocation = headersMap.getFirst(LANCE_TABLE_LOCATION_HEADER);
+ String tableProperties =
headersMap.getFirst(LANCE_TABLE_PROPERTIES_PREFIX_HEADER);
+
Map<String, String> props =
JsonUtil.mapper().readValue(tableProperties, new TypeReference<>()
{});
CreateTableResponse response =
lanceNamespace
.asTableOps()
- .createTable(
- tableId, mode, delimiter, tableLocation, props, rootCatalog,
arrowStreamBody);
+ .createTable(tableId, mode, delimiter, tableLocation, props,
arrowStreamBody);
return Response.ok(response).build();
} catch (Exception e) {
return LanceExceptionMapper.toRESTResponse(tableId, e);
@@ -107,10 +118,13 @@ public class LanceTableOperations {
@PathParam("id") String tableId,
@QueryParam("mode") @DefaultValue("create") String mode, // create,
exist_ok, overwrite
@QueryParam("delimiter") @DefaultValue(NAMESPACE_DELIMITER_DEFAULT)
String delimiter,
- @HeaderParam("x-lance-table-location") String tableLocation,
- @HeaderParam("x-lance-root-catalog") String rootCatalog,
- @HeaderParam("x-lance-table-properties") String tableProperties) {
+ @Context HttpHeaders headers) {
try {
+ // Extract table properties from header
+ MultivaluedMap<String, String> headersMap = headers.getRequestHeaders();
+ String tableLocation = headersMap.getFirst(LANCE_TABLE_LOCATION_HEADER);
+ String tableProperties =
headersMap.getFirst(LANCE_TABLE_PROPERTIES_PREFIX_HEADER);
+
Map<String, String> props =
StringUtils.isBlank(tableProperties)
? Map.of()
@@ -118,7 +132,52 @@ public class LanceTableOperations {
CreateTableResponse response =
lanceNamespace
.asTableOps()
- .createTable(tableId, mode, delimiter, tableLocation, props,
rootCatalog, null);
+ .createTable(tableId, mode, delimiter, tableLocation, props,
null);
+ return Response.ok(response).build();
+ } catch (Exception e) {
+ return LanceExceptionMapper.toRESTResponse(tableId, e);
+ }
+ }
+
+ @POST
+ @Path("/register")
+ @Timed(name = "register-table." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
+ @ResponseMetered(name = "register-table", absolute = true)
+ public Response registerTable(
+ @PathParam("id") String tableId,
+ @QueryParam("mode") @DefaultValue("create") String mode, // overwrite or
+ @QueryParam("delimiter") @DefaultValue("$") String delimiter,
+ @Context HttpHeaders headers,
+ RegisterTableRequest registerTableRequest) {
+ try {
+ Map<String, String> props =
+ registerTableRequest.getProperties() == null
+ ? Maps.newHashMap()
+ : Maps.newHashMap(registerTableRequest.getProperties());
+ props.put("register", "true");
+ props.put("location", registerTableRequest.getLocation());
+ props.put("format", "lance");
+
+ RegisterTableResponse response =
+ lanceNamespace.asTableOps().registerTable(tableId, mode, delimiter,
props);
+ return Response.ok(response).build();
+ } catch (Exception e) {
+ return LanceExceptionMapper.toRESTResponse(tableId, e);
+ }
+ }
+
+ @POST
+ @Path("/deregister")
+ @Timed(name = "deregister-table." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
+ @ResponseMetered(name = "deregister-table", absolute = true)
+ public Response deregisterTable(
+ @PathParam("id") String tableId,
+ @QueryParam("delimiter") @DefaultValue("$") String delimiter,
+ @Context HttpHeaders headers,
+ DeregisterTableRequest deregisterTableRequest) {
+ try {
+ DeregisterTableResponse response =
+ lanceNamespace.asTableOps().deregisterTable(tableId, delimiter);
return Response.ok(response).build();
} catch (Exception e) {
return LanceExceptionMapper.toRESTResponse(tableId, e);