Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -70,7 +71,7 @@
import static org.lance.namespace.hive2.Hive2ErrorType.TableAlreadyExists;
import static org.lance.namespace.hive2.Hive2ErrorType.TableNotFound;

public class Hive2Namespace implements LanceNamespace {
public class Hive2Namespace implements LanceNamespace, Closeable {
private static final Logger LOG = LoggerFactory.getLogger(Hive2Namespace.class);

private Hive2ClientPool clientPool;
Expand Down Expand Up @@ -687,4 +688,19 @@ private String getDefaultTableLocation(String namespaceName, String tableName) {
return String.format(
"%s/%s.db/%s", config.getRoot(), namespaceName.toLowerCase(), tableName.toLowerCase());
}

/**
* Closes the underlying Hive Metastore client pool, releasing all pooled metastore connections.
*
* <p>As with any resource-holding namespace implementation, callers should close instances they
* no longer need so the pooled metastore client connections are released; this matters in
* particular for short-lived instances. Safe to call when {@link #initialize} was never invoked,
* and idempotent.
*/
@Override
public void close() {
if (clientPool != null) {
clientPool.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,30 @@ public void testDropNamespaceFailMode() {
assertThrows(LanceNamespaceException.class, () -> namespace.dropNamespace(dropRequest));
assertTrue(error.getMessage().contains("Database non_existent_db doesn't exist"));
}

@Test
public void testCloseReleasesClientPool() throws Exception {
// A freshly initialized namespace can be used and then closed (idempotently), releasing its
// client pool.
Hive2Namespace closeable = new Hive2Namespace();
closeable.setHadoopConf(metastore.hiveConf());
closeable.initialize(Maps.newHashMap(), allocator);

// Exercise the metastore client so the pool has at least one live connection.
CreateNamespaceRequest nsRequest = new CreateNamespaceRequest();
nsRequest.setId(Lists.list("close_test_db"));
nsRequest.setMode("Create");
closeable.createNamespace(nsRequest);

// close() must not throw, and must be idempotent.
closeable.close();
closeable.close();
}

@Test
public void testCloseBeforeInitializeIsSafe() {
// close() before initialize() (clientPool == null) must be a no-op, not an NPE.
Hive2Namespace uninitialized = new Hive2Namespace();
uninitialized.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class Hive3Namespace implements LanceNamespace {
public class Hive3Namespace implements LanceNamespace, Closeable {
private static final Logger LOG = LoggerFactory.getLogger(Hive3Namespace.class);

private Hive3ClientPool clientPool;
Expand Down Expand Up @@ -801,4 +802,19 @@ private String getDefaultTableLocation(String catalogName, String dbName, String
"%s/%s/%s.db/%s",
config.getRoot(), catalogName.toLowerCase(), dbName.toLowerCase(), tableName.toLowerCase());
}

/**
* Closes the underlying Hive Metastore client pool, releasing all pooled metastore connections.
*
* <p>As with any resource-holding namespace implementation, callers should close instances they
* no longer need so the pooled metastore client connections are released; this matters in
* particular for short-lived instances. Safe to call when {@link #initialize} was never invoked,
* and idempotent.
*/
@Override
public void close() {
if (clientPool != null) {
clientPool.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,33 @@ public void testDropCatalogRestrictWithDatabases() {
assertTrue(error.getMessage().contains("is not empty"));
assertTrue(error.getMessage().contains("databases"));
}

@Test
public void testCloseReleasesClientPool() throws Exception {
// A freshly initialized namespace can be used and then closed (idempotently), releasing its
// client pool.
Hive3Namespace closeable = new Hive3Namespace();
closeable.setHadoopConf(metastore.hiveConf());
closeable.initialize(Maps.newHashMap(), allocator);

// Exercise the metastore client so the pool has at least one live connection.
CreateNamespaceRequest nsRequest = new CreateNamespaceRequest();
Map<String, String> properties = Maps.newHashMap();
properties.put("catalog.location.uri", "file://" + tmpDirBase + "/close_test_catalog");
nsRequest.setProperties(properties);
nsRequest.setId(Lists.list("close_test_catalog"));
nsRequest.setMode("Create");
closeable.createNamespace(nsRequest);

// close() must not throw, and must be idempotent.
closeable.close();
closeable.close();
}

@Test
public void testCloseBeforeInitializeIsSafe() {
// close() before initialize() (clientPool == null) must be a no-op, not an NPE.
Hive3Namespace uninitialized = new Hive3Namespace();
uninitialized.close();
}
}
Loading