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

dengzhhu653 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new 4dc3c1eb171 HIVE-29701: Fix leaking queries in ObjectStore.unwrap() 
(#6585)
4dc3c1eb171 is described below

commit 4dc3c1eb1718cdf71ca6823cbcea8d0c6e130167
Author: dengzh <[email protected]>
AuthorDate: Fri Jul 10 08:49:25 2026 +0800

    HIVE-29701: Fix leaking queries in ObjectStore.unwrap() (#6585)
---
 .../apache/hadoop/hive/metastore/ObjectStore.java  |  28 +-
 .../org/apache/hadoop/hive/metastore/RawStore.java |   5 +-
 .../hive/metastore/metastore/RawStoreBundle.java   |   6 +-
 .../metastore/metastore/TransactionHandler.java    |  19 ++
 .../metastore/impl/ColStatsStoreImpl.java          |  32 +-
 .../metastore/impl/ConstraintStoreImpl.java        |  19 +-
 .../metastore/impl/PrivilegeStoreImpl.java         |  22 +-
 .../metastore/metastore/impl/TableStoreImpl.java   |  51 +--
 .../metastore/metastore/TestObjectStoreUnwrap.java | 365 +++++++++++++++++++++
 9 files changed, 469 insertions(+), 78 deletions(-)

diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
index c26d2d2de7d..9a42ba9f01a 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
@@ -118,6 +118,7 @@
 import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
 import org.apache.hadoop.hive.metastore.metastore.GetHelper;
 import org.apache.hadoop.hive.metastore.metastore.GetListHelper;
+import org.apache.hadoop.hive.metastore.metastore.PersistenceManagerProxy;
 import org.apache.hadoop.hive.metastore.metastore.iface.PrivilegeStore;
 import org.apache.hadoop.hive.metastore.model.MCatalog;
 import org.apache.hadoop.hive.metastore.model.MColumnDescriptor;
@@ -142,7 +143,6 @@
 import org.apache.hadoop.hive.metastore.model.MReplicationMetrics;
 import org.apache.hadoop.hive.metastore.properties.CachingPropertyStore;
 import org.apache.hadoop.hive.metastore.properties.PropertyStore;
-import org.apache.hadoop.hive.metastore.metastore.PersistenceManagerProxy;
 import org.apache.hadoop.hive.metastore.metastore.RawStoreBundle;
 import org.apache.hadoop.hive.metastore.metastore.MetaDescriptor;
 import org.apache.hadoop.hive.metastore.metastore.TransactionHandler;
@@ -207,7 +207,6 @@ private enum TXN_STATUS {
   private Transaction currentTransaction = null;
   private TXN_STATUS transactionStatus = TXN_STATUS.NO_STATE;
   private PropertyStore propertyStore;
-  private final Map<Class<?>, Object> cachedImpls = new HashMap<>();
 
   public ObjectStore() {
   }
@@ -382,7 +381,6 @@ public void shutdown() {
       pm.close();
       pm = null;
     }
-    cachedImpls.clear();
   }
 
   /**
@@ -412,27 +410,23 @@ public boolean openTransaction() {
     return result;
   }
 
-  @SuppressWarnings("unchecked")
+  @SuppressWarnings("unchecked, rawtypes")
   @Override
   public <T> T unwrap(Class<T> iface) {
+    if (pm == null) {
+      throw new IllegalStateException("ObjectStore hasn't been initialized 
yet");
+    }
     MetaDescriptor descriptor = iface.getAnnotation(MetaDescriptor.class);
     if (descriptor == null) {
       throw new IllegalArgumentException("Unable to unwrap the store as " + 
iface);
     }
-    String implClassName = conf.get("metastore." + descriptor.alias() + 
".store.impl", "");
-    T simpl;
-    T impl = (T) cachedImpls.get(iface);
-    if (impl != null &&
-        (StringUtils.isEmpty(implClassName) || 
impl.getClass().getName().equals(implClassName))) {
-      simpl = impl;
-    } else {
-      Class<?> ifaceImpl = descriptor.defaultImpl();
-      if (StringUtils.isNotEmpty(implClassName)) {
-        ifaceImpl = conf.getClass(implClassName, ifaceImpl);
-      }
-      simpl = (T) JavaUtils.newInstance(ifaceImpl);
-      cachedImpls.put(iface, simpl);
+    String implClassName =
+        conf.get("metastore." + descriptor.alias() + ".store.impl", "");
+    Class<?> ifaceImpl = descriptor.defaultImpl();
+    if (StringUtils.isNotEmpty(implClassName)) {
+      ifaceImpl = conf.getClass(implClassName, ifaceImpl);
     }
+    T simpl = (T) JavaUtils.newInstance(ifaceImpl);
     List<Query> openQueries = new LinkedList<>();
     if (simpl instanceof RawStoreBundle rsb) {
       rsb.setBaseStore(this);
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
index ca9211f27d8..45f1a32bb4a 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/RawStore.java
@@ -2475,10 +2475,6 @@ default MTable ensureGetMTable(String catName, String 
dbName, String tblName) th
 
   MDatabase ensureGetMDatabase(String catName, String dbName) throws 
NoSuchObjectException;
 
-  default MPartition ensureGetMPartition(TableName tableName, List<String> 
partVals) throws MetaException {
-    return unwrap(TableStore.class).ensureGetMPartition(tableName, partVals);
-  }
-
   /** Persistent Property Management. */
   default PropertyStore getPropertyStore() {
     return null;
@@ -2503,4 +2499,5 @@ default long updateParameterWithExpectedValue(Table 
table, String key, String ex
    * @throws RuntimeException If the context cannot be unwrapped to the 
provided class
    */
   <T> T unwrap(Class<T> iface);
+
 }
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/RawStoreBundle.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/RawStoreBundle.java
index add2f07dfd2..66a5b4e6fb0 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/RawStoreBundle.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/RawStoreBundle.java
@@ -33,7 +33,7 @@ public void setBaseStore(RawStore store) {
   }
 
   public void setPersistentManager(PersistenceManager manager) {
-    this.pm = Objects.requireNonNull(manager);
+    this.pm = manager;
   }
 
   public RawStore getBaseStore() {
@@ -43,4 +43,8 @@ public RawStore getBaseStore() {
   public PersistenceManager getPersistentManager() {
     return pm;
   }
+
+  protected <T> T siblingStore(Class<T> iface) {
+    return baseStore.unwrap(iface);
+  }
 }
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/TransactionHandler.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/TransactionHandler.java
index afde12e2231..512b815870b 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/TransactionHandler.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/TransactionHandler.java
@@ -28,6 +28,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import com.google.common.annotations.VisibleForTesting;
+
 import org.apache.hadoop.hive.metastore.RawStore;
 
 public record TransactionHandler<T> (RawStore rs, T simpl, List<Query> 
openQueries)
@@ -44,6 +46,9 @@ public static <T> T getProxy(Class<T> iface, 
TransactionHandler<T> handler) {
 
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws 
Throwable {
+    if (method.getDeclaringClass() == Object.class) {
+      return handleObjectMethod(proxy, method, args);
+    }
     boolean openTxn = method.getAnnotation(MetaDescriptor.NoTransaction.class) 
== null;
     boolean success = false;
     if (openTxn) {
@@ -67,4 +72,18 @@ public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwabl
       openQueries.clear();
     }
   }
+
+  @VisibleForTesting
+  public int getOpenQueryCount() {
+    return openQueries.size();
+  }
+
+  private static Object handleObjectMethod(Object proxy, Method method, 
Object[] args) {
+    return switch (method.getName()) {
+      case "toString" -> proxy.getClass().getInterfaces()[0].getName() + " 
proxy";
+      case "hashCode" -> System.identityHashCode(proxy);
+      case "equals" -> proxy == args[0];
+      default -> throw new UnsupportedOperationException(method.toString());
+    };
+  }
 }
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ColStatsStoreImpl.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ColStatsStoreImpl.java
index 3a166afa1f5..874209c70fb 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ColStatsStoreImpl.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ColStatsStoreImpl.java
@@ -271,7 +271,9 @@ public Map<String, String> 
updateTableColumnStatistics(ColumnStatistics colStats
     String catName = statsDesc.isSetCatName() ? statsDesc.getCatName() : 
getDefaultCatalog(conf);
     // DataNucleus objects get detached all over the place for no (real) 
reason.
     // So let's not use them anywhere unless absolutely necessary.
-    MTable mTable = baseStore.ensureGetMTable(catName, statsDesc.getDbName(), 
statsDesc.getTableName());
+    TableStore tableStore = siblingStore(TableStore.class);
+    MTable mTable = tableStore
+        .ensureGetMTable(new TableName(catName, statsDesc.getDbName(), 
statsDesc.getTableName()));
     int maxRetries = MetastoreConf.getIntVar(conf, 
MetastoreConf.ConfVars.METASTORE_S4U_NOWAIT_MAX_RETRIES);
     long sleepInterval = MetastoreConf.getTimeVar(conf,
         MetastoreConf.ConfVars.METASTORE_S4U_NOWAIT_RETRY_SLEEP_INTERVAL, 
TimeUnit.MILLISECONDS);
@@ -292,7 +294,7 @@ public Map<String, String> 
updateTableColumnStatistics(ColumnStatistics colStats
         throw new RetryingExecutor.RetryException(exceptionRef.get());
       }
       pm.refresh(mTable);
-      Table table = baseStore.unwrap(TableStore.class).getTable(new 
TableName(catName, statsDesc.getDbName(),
+      Table table = tableStore.getTable(new TableName(catName, 
statsDesc.getDbName(),
           statsDesc.getTableName()), null, -1);
       List<String> colNames = new ArrayList<>();
       for (ColumnStatisticsObj statsObj : statsObjs) {
@@ -357,8 +359,9 @@ public Map<String, String> 
updatePartitionColumnStatistics(Table table, MTable m
     List<ColumnStatisticsObj> statsObjs = colStats.getStatsObj();
     ColumnStatisticsDesc statsDesc = colStats.getStatsDesc();
     String catName = statsDesc.isSetCatName() ? statsDesc.getCatName() : 
getDefaultCatalog(conf);
-    MPartition mPartition =
-        baseStore.ensureGetMPartition(new TableName(catName, 
statsDesc.getDbName(), statsDesc.getTableName()), partVals);
+    TableStore tableStore = siblingStore(TableStore.class);
+    MPartition mPartition = tableStore
+        .ensureGetMPartition(new TableName(catName, statsDesc.getDbName(), 
statsDesc.getTableName()), partVals);
     if (mPartition == null) {
       throw new NoSuchObjectException("Partition for which stats is gathered 
doesn't exist.");
     }
@@ -387,7 +390,7 @@ public Map<String, String> 
updatePartitionColumnStatistics(Table table, MTable m
         throw new RetryingExecutor.RetryException(exceptionRef.get());
       }
       pm.refresh(mPartition);
-      Partition partition = baseStore.unwrap(TableStore.class)
+      Partition partition = tableStore
           .getPartition(new TableName(catName, statsDesc.getDbName(), 
statsDesc.getTableName()), mPartition.getValues(), null);
       Map<String, MPartitionColumnStatistics> oldStats = Maps.newHashMap();
       List<MPartitionColumnStatistics> stats =
@@ -566,7 +569,7 @@ public ColumnStatistics getTableColumnStatistics(
     String dbName = normalizeIdentifier(tableName.getDb());
     String tblName = normalizeIdentifier(tableName.getTable());
     if (writeIdList != null) {
-      MTable table = baseStore.ensureGetMTable(catName, dbName, tblName);
+      MTable table = siblingStore(TableStore.class).ensureGetMTable(new 
TableName(catName, dbName, tblName));
       isCompliant = !TxnUtils.isTransactionalTable(table.getParameters())
           || (areTxnStatsSupported && 
isCurrentStatsValidForTheQuery(table.getParameters(), table.getWriteId(), 
writeIdList, false));
     }
@@ -678,9 +681,10 @@ public List<ColumnStatistics> getPartitionColumnStatistics(
           cs.setIsStatsCompliant(false);
         }
       } else {
+        TableStore tableStore = siblingStore(TableStore.class);
         // TODO: this could be improved to get partitions in bulk
         for (ColumnStatistics cs : allStats) {
-          MPartition mpart = baseStore.ensureGetMPartition(tableName,
+          MPartition mpart = tableStore.ensureGetMPartition(tableName,
               
Warehouse.getPartValuesFromPartName(cs.getStatsDesc().getPartName()));
           if (mpart == null
               || !isCurrentStatsValidForTheQuery(mpart.getParameters(), 
mpart.getWriteId(), writeIdList, false)) {
@@ -758,7 +762,8 @@ public AggrStats get_aggr_stats_for(TableName tableName,
         return null;
       }
 
-      Table table = baseStore.unwrap(TableStore.class).getTable(tableName, 
null, -1);
+      TableStore tableStore = siblingStore(TableStore.class);
+      Table table = tableStore.getTable(tableName, null, -1);
       boolean isTxn = TxnUtils.isTransactionalTable(table.getParameters());
       if (isTxn && !areTxnStatsSupported) {
         return null;
@@ -769,7 +774,7 @@ public AggrStats get_aggr_stats_for(TableName tableName,
       GetProjectionsSpec ps = new GetProjectionsSpec();
       ps.setIncludeParamKeyPattern(StatsSetupConst.COLUMN_STATS_ACCURATE + 
'%');
       ps.setFieldList(Lists.newArrayList("writeId", "parameters", "values"));
-      List<Partition> parts = baseStore.unwrap(TableStore.class)
+      List<Partition> parts = tableStore
           .getPartitionSpecsByFilterAndProjection(table, ps, fs);
 
       // Loop through the given "partNames" list
@@ -915,7 +920,6 @@ public void deleteAllPartitionColumnStatistics(TableName 
tn, String writeIdList)
     if (tableName == null) {
       throw new RuntimeException("Table name is null.");
     }
-    MTable mTable = baseStore.ensureGetMTable(catName, dbName, tableName);
     Query query = pm.newQuery(MPartitionColumnStatistics.class);
     String filter = "partition.table.database.name == t2 && 
partition.table.tableName == t3 && partition.table.database.catalogName == t4";
     String parameters = "java.lang.String t2, java.lang.String t3, 
java.lang.String t4";
@@ -942,12 +946,12 @@ protected Integer getSqlResult() throws MetaException {
       @Override
       protected Integer getJdoResult() throws MetaException, 
NoSuchObjectException {
         try {
-          List<Partition> parts = baseStore.unwrap(TableStore.class)
-              .getPartitions(tn, GetPartitionsArgs.getAllPartitions());
+          TableStore tableStore = siblingStore(TableStore.class);
+          List<Partition> parts = tableStore.getPartitions(tn, 
GetPartitionsArgs.getAllPartitions());
           for (Partition part : parts) {
             Partition newPart = new Partition(part);
             StatsSetupConst.clearColumnStatsState(newPart.getParameters());
-            baseStore.unwrap(TableStore.class).alterPartition(tn, 
part.getValues(), newPart, writeIdList);
+            tableStore.alterPartition(tn, part.getValues(), newPart, 
writeIdList);
           }
           return parts.size();
         } catch (InvalidObjectException e) {
@@ -1133,7 +1137,7 @@ private boolean 
deleteTableColumnStatisticsViaJdo(TableName tblName, List<String
       pm.deletePersistentAll(mStatsObjColl);
     }
 
-    MTable mTable = baseStore.ensureGetMTable(catName, dbName, tableName);
+    MTable mTable = siblingStore(TableStore.class).ensureGetMTable(new 
TableName(catName, dbName, tableName));
     if (mTable != null) {
       Map<String, String> tableParams = mTable.getParameters();
       if (tableParams != null && 
tableParams.containsKey(StatsSetupConst.COLUMN_STATS_ACCURATE)) {
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ConstraintStoreImpl.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ConstraintStoreImpl.java
index d76cd8ff659..def4c89fe5c 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ConstraintStoreImpl.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/ConstraintStoreImpl.java
@@ -77,7 +77,7 @@ public void setBaseStore(RawStore store) {
   @Override
   public SQLAllTableConstraints createTableWithConstraints(Table tbl, 
SQLAllTableConstraints constraints)
       throws InvalidObjectException, MetaException {
-    baseStore.unwrap(TableStore.class).createTable(tbl);
+    siblingStore(TableStore.class).createTable(tbl);
     // Add constraints.
     // We need not do a deep retrieval of the Table Column Descriptor while 
persisting the
     // constraints since this transaction involving create table is not yet 
committed.
@@ -184,6 +184,7 @@ public List<SQLForeignKey> addForeignKeys(
   private List<SQLForeignKey> addForeignKeys(List<SQLForeignKey> foreignKeys, 
boolean retrieveCD,
       List<SQLPrimaryKey> primaryKeys, List<SQLUniqueConstraint> 
uniqueConstraints)
       throws InvalidObjectException, MetaException {
+    TableStore tableStore = siblingStore(TableStore.class);
     if (CollectionUtils.isNotEmpty(foreignKeys)) {
       List<MConstraint> mpkfks = new ArrayList<>();
       String currentConstraintName = null;
@@ -208,7 +209,7 @@ private List<SQLForeignKey> 
addForeignKeys(List<SQLForeignKey> foreignKeys, bool
         // If retrieveCD is false, we do not need to do a deep retrieval of 
the Table Column Descriptor.
         // For instance, this is the case when we are creating the table.
         final TableStore.AttachedMTableInfo nChildTable =
-            baseStore.unwrap(TableStore.class).getMTable(new 
TableName(catName, fkTableDB, fkTableName), retrieveCD);
+            tableStore.getMTable(new TableName(catName, fkTableDB, 
fkTableName), retrieveCD);
         final MTable childTable = nChildTable.mtbl;
         if (childTable == null) {
           throw new InvalidObjectException("Child table not found: " + 
fkTableName);
@@ -242,7 +243,7 @@ private List<SQLForeignKey> 
addForeignKeys(List<SQLForeignKey> foreignKeys, bool
           existingTableUniqueConstraints = uniqueConstraints;
         } else {
           nParentTable =
-              baseStore.unwrap(TableStore.class).getMTable(new 
TableName(catName, pkTableDB, pkTableName), true);
+              tableStore.getMTable(new TableName(catName, pkTableDB, 
pkTableName), true);
           parentTable = nParentTable.mtbl;
           if (parentTable == null) {
             throw new InvalidObjectException("Parent table not found: " + 
pkTableName);
@@ -441,7 +442,7 @@ private List<SQLPrimaryKey> 
addPrimaryKeys(List<SQLPrimaryKey> pks, boolean retr
       MetaException {
     List<MConstraint> mpks = new ArrayList<>();
     String constraintName = null;
-
+    TableStore tableStore = siblingStore(TableStore.class);
     for (SQLPrimaryKey pk : pks) {
       final String catName = normalizeIdentifier(pk.getCatName());
       final String tableDB = normalizeIdentifier(pk.getTable_db());
@@ -450,7 +451,7 @@ private List<SQLPrimaryKey> 
addPrimaryKeys(List<SQLPrimaryKey> pks, boolean retr
 
       // If retrieveCD is false, we do not need to do a deep retrieval of the 
Table Column Descriptor.
       // For instance, this is the case when we are creating the table.
-      TableStore.AttachedMTableInfo nParentTable = 
baseStore.unwrap(TableStore.class)
+      TableStore.AttachedMTableInfo nParentTable = tableStore
           .getMTable(new TableName(catName, tableDB, tableName), retrieveCD);
       MTable parentTable = nParentTable.mtbl;
       if (parentTable == null) {
@@ -527,6 +528,7 @@ private List<SQLUniqueConstraint> 
addUniqueConstraints(List<SQLUniqueConstraint>
     List<MConstraint> cstrs = new ArrayList<>();
     String constraintName = null;
 
+    TableStore tableStore = siblingStore(TableStore.class);
     for (SQLUniqueConstraint uk : uks) {
       final String catName = normalizeIdentifier(uk.getCatName());
       final String tableDB = normalizeIdentifier(uk.getTable_db());
@@ -535,7 +537,7 @@ private List<SQLUniqueConstraint> 
addUniqueConstraints(List<SQLUniqueConstraint>
 
       // If retrieveCD is false, we do not need to do a deep retrieval of the 
Table Column Descriptor.
       // For instance, this is the case when we are creating the table.
-      TableStore.AttachedMTableInfo nParentTable = 
baseStore.unwrap(TableStore.class)
+      TableStore.AttachedMTableInfo nParentTable = tableStore
           .getMTable(new TableName(catName, tableDB, tableName), retrieveCD);
       MTable parentTable = nParentTable.mtbl;
       if (parentTable == null) {
@@ -652,7 +654,7 @@ private MConstraint addConstraint(String catName, String 
tableDB, String tableNa
     String constraintName = null;
     // If retrieveCD is false, we do not need to do a deep retrieval of the 
Table Column Descriptor.
     // For instance, this is the case when we are creating the table.
-    TableStore.AttachedMTableInfo nParentTable = 
baseStore.unwrap(TableStore.class)
+    TableStore.AttachedMTableInfo nParentTable = siblingStore(TableStore.class)
         .getMTable(new TableName(catName, tableDB, tableName), retrieveCD);
     MTable parentTable = nParentTable.mtbl;
     if (parentTable == null) {
@@ -735,6 +737,7 @@ private List<SQLNotNullConstraint> 
addNotNullConstraints(List<SQLNotNullConstrai
     List<MConstraint> cstrs = new ArrayList<>();
     String constraintName;
 
+    TableStore tableStore = siblingStore(TableStore.class);
     for (SQLNotNullConstraint nn : nns) {
       final String catName = normalizeIdentifier(nn.getCatName());
       final String tableDB = normalizeIdentifier(nn.getTable_db());
@@ -743,7 +746,7 @@ private List<SQLNotNullConstraint> 
addNotNullConstraints(List<SQLNotNullConstrai
 
       // If retrieveCD is false, we do not need to do a deep retrieval of the 
Table Column Descriptor.
       // For instance, this is the case when we are creating the table.
-      TableStore.AttachedMTableInfo nParentTable = 
baseStore.unwrap(TableStore.class)
+      TableStore.AttachedMTableInfo nParentTable = tableStore
           .getMTable(new TableName(catName, tableDB, tableName), retrieveCD);
       MTable parentTable = nParentTable.mtbl;
       if (parentTable == null) {
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/PrivilegeStoreImpl.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/PrivilegeStoreImpl.java
index 17f58867e5b..8a42643ee9e 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/PrivilegeStoreImpl.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/PrivilegeStoreImpl.java
@@ -760,6 +760,7 @@ public boolean grantPrivileges(PrivilegeBag privileges) 
throws InvalidObjectExce
     if (CollectionUtils.isNotEmpty(privilegeList)) {
       Iterator<HiveObjectPrivilege> privIter = privilegeList.iterator();
       Set<String> privSet = new HashSet<>();
+      TableStore tableStore = siblingStore(TableStore.class);
       while (privIter.hasNext()) {
         HiveObjectPrivilege privDef = privIter.next();
         HiveObjectRef hiveObject = privDef.getHiveObject();
@@ -836,8 +837,8 @@ public boolean grantPrivileges(PrivilegeBag privileges) 
throws InvalidObjectExce
             persistentObjs.add(mDc);
           }
         } else if (hiveObject.getObjectType() == HiveObjectType.TABLE) {
-          MTable tblObj = baseStore.ensureGetMTable(catName, 
hiveObject.getDbName(), hiveObject
-              .getObjectName());
+          MTable tblObj = tableStore
+              .ensureGetMTable(new TableName(catName, hiveObject.getDbName(), 
hiveObject.getObjectName()));
           if (tblObj != null) {
             List<MTablePrivilege> tablePrivs = this
                 .listAllMTableGrants(userName, principalType,
@@ -862,7 +863,7 @@ public boolean grantPrivileges(PrivilegeBag privileges) 
throws InvalidObjectExce
             }
           }
         } else if (hiveObject.getObjectType() == HiveObjectType.PARTITION) {
-          MPartition partObj = baseStore.ensureGetMPartition(new 
TableName(catName, hiveObject.getDbName(),
+          MPartition partObj = tableStore.ensureGetMPartition(new 
TableName(catName, hiveObject.getDbName(),
               hiveObject.getObjectName()), hiveObject.getPartValues());
           String partName = null;
           if (partObj != null) {
@@ -891,14 +892,15 @@ public boolean grantPrivileges(PrivilegeBag privileges) 
throws InvalidObjectExce
             }
           }
         } else if (hiveObject.getObjectType() == HiveObjectType.COLUMN) {
-          MTable tblObj = baseStore.ensureGetMTable(catName, 
hiveObject.getDbName(), hiveObject
-              .getObjectName());
+          MTable tblObj = tableStore
+              .ensureGetMTable(new TableName(catName, hiveObject.getDbName(), 
hiveObject.getObjectName()));
           if (tblObj != null) {
             if (hiveObject.getPartValues() != null) {
               MPartition partObj = null;
               List<MPartitionColumnPrivilege> colPrivs = null;
-              partObj = baseStore.ensureGetMPartition(new TableName(catName, 
hiveObject.getDbName(), hiveObject
-                  .getObjectName()), hiveObject.getPartValues());
+              partObj = tableStore
+                  .ensureGetMPartition(new TableName(catName, 
hiveObject.getDbName(), hiveObject.getObjectName()),
+                      hiveObject.getPartValues());
               if (partObj == null) {
                 continue;
               }
@@ -973,7 +975,7 @@ public boolean revokePrivileges(PrivilegeBag privileges, 
boolean grantOption)
 
     if (CollectionUtils.isNotEmpty(privilegeList)) {
       Iterator<HiveObjectPrivilege> privIter = privilegeList.iterator();
-
+      TableStore tableStore = siblingStore(TableStore.class);
       while (privIter.hasNext()) {
         HiveObjectPrivilege privDef = privIter.next();
         HiveObjectRef hiveObject = privDef.getHiveObject();
@@ -1100,7 +1102,7 @@ public boolean revokePrivileges(PrivilegeBag privileges, 
boolean grantOption)
           }
         } else if (hiveObject.getObjectType() == HiveObjectType.PARTITION) {
           boolean found = false;
-          Table tabObj = baseStore.unwrap(TableStore.class).getTable(
+          Table tabObj = tableStore.getTable(
               new TableName(catName, hiveObject.getDbName(), 
hiveObject.getObjectName()), null, -1);
           String partName = null;
           if (hiveObject.getPartValues() != null) {
@@ -1133,7 +1135,7 @@ public boolean revokePrivileges(PrivilegeBag privileges, 
boolean grantOption)
             }
           }
         } else if (hiveObject.getObjectType() == HiveObjectType.COLUMN) {
-          Table tabObj = baseStore.unwrap(TableStore.class).getTable(
+          Table tabObj = tableStore.getTable(
               new TableName(catName, hiveObject.getDbName(), 
hiveObject.getObjectName()), null, -1);
           String partName = null;
           if (hiveObject.getPartValues() != null) {
diff --git 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/TableStoreImpl.java
 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/TableStoreImpl.java
index 28a34be97b5..e0e183f93f2 100644
--- 
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/TableStoreImpl.java
+++ 
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/metastore/impl/TableStoreImpl.java
@@ -90,6 +90,8 @@
 import org.apache.hadoop.hive.metastore.client.builder.GetPartitionsArgs;
 import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
 import org.apache.hadoop.hive.metastore.metastore.RawStoreBundle;
+import org.apache.hadoop.hive.metastore.metastore.iface.ColStatsStore;
+import org.apache.hadoop.hive.metastore.metastore.iface.PrivilegeStore;
 import org.apache.hadoop.hive.metastore.model.FetchGroups;
 import org.apache.hadoop.hive.metastore.model.MColumnDescriptor;
 import org.apache.hadoop.hive.metastore.model.MConstraint;
@@ -194,7 +196,8 @@ public boolean dropTable(TableName table)
       }
 
       // delete column statistics if present
-      baseStore.deleteTableColumnStatistics(catName, dbName, tableName, null, 
null);
+      siblingStore(ColStatsStore.class)
+          .deleteTableColumnStatistics(new TableName(catName, dbName, 
tableName), null, null);
 
       List<MConstraint> tabConstraints = 
listAllTableConstraintsWithOptionalConstraintName(
           catName, dbName, tableName, null);
@@ -584,7 +587,7 @@ private MTable getMTable(String catName, String db, String 
table) {
   public AttachedMTableInfo getMTable(TableName tableName, boolean retrieveCD) 
{
     AttachedMTableInfo nmtbl = new AttachedMTableInfo();
     String catName = 
normalizeIdentifier(Optional.ofNullable(tableName.getCat())
-        .orElse(getDefaultCatalog(baseStore.getConf())));
+        .orElse(getDefaultCatalog(conf)));
     String db = normalizeIdentifier(tableName.getDb());
     String table = normalizeIdentifier(tableName.getTable());
     Query query = pm.newQuery(MTable.class,
@@ -616,7 +619,7 @@ public Table getTable(TableName table, String writeIdList, 
long tableId)
     String dbName = normalizeIdentifier(table.getDb());
     String tableName = normalizeIdentifier(table.getTable());
     MTable mtable = getMTable(catName, dbName, tableName);
-    tbl = convertToTable(mtable, conf);
+    tbl = convertToTable(mtable);
     // Retrieve creation metadata if needed
     if (tbl != null && 
TableType.MATERIALIZED_VIEW.toString().equals(tbl.getTableType())) {
       tbl.setCreationMetadata(
@@ -975,7 +978,7 @@ public Table alterTable(TableName tableName, Table 
newTable, String queryValidWr
         oldt.setWriteId(newTable.getWriteId());
       }
     }
-    newTable = convertToTable(oldt, conf);
+    newTable = convertToTable(oldt);
     return newTable;
   }
 
@@ -1248,7 +1251,7 @@ public List<Table> getTableObjectsByName(String catName, 
String db, List<String>
       }
     } else {
       for (Iterator iter = mtables.iterator(); iter.hasNext(); ) {
-        Table tbl = convertToTable((MTable) iter.next(), conf);
+        Table tbl = convertToTable((MTable) iter.next());
         // Retrieve creation metadata if needed
         if (TableType.MATERIALIZED_VIEW.toString().equals(tbl.getTableType())) 
{
           tbl.setCreationMetadata(
@@ -1450,7 +1453,7 @@ private String makeQueryFilterString(String catName, 
String dbName, Table table,
       params.put("catName", catName);
     }
 
-    tree.accept(new ExpressionTree.JDOFilterGenerator(baseStore.getConf(),
+    tree.accept(new ExpressionTree.JDOFilterGenerator(conf,
         table != null ? table.getPartitionKeys() : null, queryBuilder, 
params));
     if (queryBuilder.hasError()) {
       assert !isValidatedFilter;
@@ -1471,7 +1474,7 @@ private String makeQueryFilterString(String catName, 
String dbName, String tblNa
     params.put("t1", tblName);
     params.put("t2", dbName);
     params.put("t3", catName);
-    tree.accept(new ExpressionTree.JDOFilterGenerator(baseStore.getConf(), 
partitionKeys, queryBuilder, params));
+    tree.accept(new ExpressionTree.JDOFilterGenerator(conf, partitionKeys, 
queryBuilder, params));
     if (queryBuilder.hasError()) {
       assert !isValidatedFilter;
       LOG.debug("JDO filter pushdown cannot be used: {}", 
queryBuilder.getErrorMessage());
@@ -1532,7 +1535,7 @@ private List<String> getPartitionNamesViaOrm(String 
catName, String dbName, Stri
    */
   private String getDefaultPartitionName(String inputDefaultPartName) {
     return (((inputDefaultPartName == null) || 
(inputDefaultPartName.isEmpty()))
-        ? MetastoreConf.getVar(baseStore.getConf(), 
MetastoreConf.ConfVars.DEFAULTPARTITIONNAME)
+        ? MetastoreConf.getVar(conf, 
MetastoreConf.ConfVars.DEFAULTPARTITIONNAME)
         : inputDefaultPartName);
   }
 
@@ -1563,7 +1566,7 @@ public List<String> listPartitionNames(TableName 
tableName, String defaultPartNa
     ExpressionTree tmp = null;
     if (!isEmptyFilter) {
       tmp = PartFilterExprUtil.makeExpressionTree(expressionProxy, exprBytes,
-          getDefaultPartitionName(defaultPartName), baseStore.getConf());
+          getDefaultPartitionName(defaultPartName), conf);
     }
     String catName = normalizeIdentifier(tableName.getCat());
     String dbName = normalizeIdentifier(tableName.getDb());
@@ -1647,7 +1650,7 @@ public boolean getPartitionsByExpr(TableName tableName, 
List<Partition> result,
     byte[] expr = args.getExpr();
     final ExpressionTree exprTree = expr.length != 0 ? 
PartFilterExprUtil.makeExpressionTree(
         expressionProxy, expr,
-        getDefaultPartitionName(args.getDefaultPartName()), 
baseStore.getConf()) : ExpressionTree.EMPTY_TREE;
+        getDefaultPartitionName(args.getDefaultPartName()), conf) : 
ExpressionTree.EMPTY_TREE;
     final AtomicBoolean hasUnknownPartitions = new AtomicBoolean(false);
 
     String catName = normalizeIdentifier(tableName.getCat());
@@ -1664,7 +1667,7 @@ protected List<Partition> getSqlResult() throws 
MetaException {
           MetaStoreDirectSql.SqlFilterForPushdown filter = new 
MetaStoreDirectSql.SqlFilterForPushdown();
           if (getDirectSql().generateSqlFilterForPushdown(catName, dbName, 
tblName, partitionKeys,
               exprTree, args.getDefaultPartName(), filter)) {
-            String catalogName = (catName != null) ? catName : 
getDefaultCatalog(baseStore.getConf());
+            String catalogName = (catName != null) ? catName : 
getDefaultCatalog(conf);
             return getDirectSql().getPartitionsViaSqlFilter(catalogName, 
dbName, tblName, filter,
                 isAcidTable, args);
           }
@@ -2210,11 +2213,12 @@ public List<Partition> 
listPartitionsPsWithAuth(TableName tableName, GetPartitio
       partitions = getPartitionsByPs(tableName, args);
     }
     if (getauth) {
+      PrivilegeStore privilegeStore = siblingStore(PrivilegeStore.class);
       for (Partition part : partitions) {
         String partName = Warehouse.makePartName(convertToFieldSchemas(mtbl
             .getPartitionKeys()), part.getValues());
-        PrincipalPrivilegeSet partAuth = 
baseStore.getPartitionPrivilegeSet(catName, dbName,
-            tblName, partName, userName, groupNames);
+        PrincipalPrivilegeSet partAuth = privilegeStore
+            .getPartitionPrivilegeSet(new TableName(catName, dbName, tblName), 
partName, userName, groupNames);
         part.setPrivileges(partAuth);
       }
     }
@@ -2699,8 +2703,8 @@ public Partition getPartitionWithAuth(TableName 
tableName, List<String> partVals
     if 
("TRUE".equalsIgnoreCase(mtbl.getParameters().get("PARTITION_LEVEL_PRIVILEGE")))
 {
       String partName = Warehouse.makePartName(convertToFieldSchemas(mtbl
           .getPartitionKeys()), partVals);
-      PrincipalPrivilegeSet partAuth = 
baseStore.getPartitionPrivilegeSet(catName, dbName,
-          tblName, partName, user_name, group_names);
+      PrincipalPrivilegeSet partAuth = siblingStore(PrivilegeStore.class)
+          .getPartitionPrivilegeSet(new TableName(catName, dbName, tblName), 
partName, user_name, group_names);
       part.setPrivileges(partAuth);
     }
     return part;
@@ -2720,7 +2724,7 @@ private String makeQueryFilterString(String catName, 
String dbName, MTable mtabl
       Map<String, Object> params) throws MetaException {
     ExpressionTree tree = (filter != null && !filter.isEmpty())
         ? PartFilterExprUtil.parseFilterTree(filter) : 
ExpressionTree.EMPTY_TREE;
-    return makeQueryFilterString(catName, dbName, convertToTable(mtable, 
baseStore.getConf()), tree, params, true);
+    return makeQueryFilterString(catName, dbName, convertToTable(mtable), 
tree, params, true);
   }
 
   @Override
@@ -2749,7 +2753,7 @@ public List<Table> 
getAllMaterializedViewObjectsForRewriting(String catName) thr
     Collection<MTable> mTbls = (Collection<MTable>) query.executeWithArray(
         catName, TableType.MATERIALIZED_VIEW.toString(), true);
     for (MTable mTbl : mTbls) {
-      Table tbl = convertToTable(mTbl, conf);
+      Table tbl = convertToTable(mTbl);
       tbl.setCreationMetadata(
           convertToCreationMetadata(
               getCreationMetadata(tbl.getCatName(), tbl.getDbName(), 
tbl.getTableName())));
@@ -2959,7 +2963,7 @@ private void putPersistentPrivObjects(MTable mtbl, 
List<Object> toPersistPrivObj
     }
   }
 
-  private Table convertToTable(MTable mtbl, Configuration conf) throws 
MetaException {
+  private Table convertToTable(MTable mtbl) throws MetaException {
     if (mtbl == null) {
       return null;
     }
@@ -3013,7 +3017,7 @@ private MTable convertToMTable(Table tbl) throws 
InvalidObjectException,
       return null;
     }
     MDatabase mdb = null;
-    String catName = tbl.isSetCatName() ? tbl.getCatName() : 
getDefaultCatalog(baseStore.getConf());
+    String catName = tbl.isSetCatName() ? tbl.getCatName() : 
getDefaultCatalog(conf);
     try {
       mdb = baseStore.ensureGetMDatabase(catName, tbl.getDbName());
     } catch (NoSuchObjectException e) {
@@ -3241,7 +3245,7 @@ private MCreationMetadata 
convertToMCreationMetadata(CreationMetadata m)
   private MMVSource convertToSourceTable(String catalog, SourceTable 
sourceTable)
       throws NoSuchObjectException {
     Table table = sourceTable.getTable();
-    MTable mtbl = baseStore.ensureGetMTable(catalog, table.getDbName(), 
table.getTableName());
+    MTable mtbl = ensureGetMTable(new TableName(catalog, table.getDbName(), 
table.getTableName()));
     MMVSource source = new MMVSource();
     source.setTable(mtbl);
     source.setInsertedCount(sourceTable.getInsertedCount());
@@ -3262,7 +3266,7 @@ private MMVSource convertToSourceTable(String catalog, 
SourceTable sourceTable)
   private MMVSource convertToSourceTable(String catalog, String 
fullyQualifiedTableName)
       throws NoSuchObjectException {
     String[] names = fullyQualifiedTableName.split("\\.");
-    MTable mtbl = baseStore.ensureGetMTable(catalog, names[0], names[1]);
+    MTable mtbl = ensureGetMTable(new TableName(catalog, names[0], names[1]));
     MMVSource source = new MMVSource();
     source.setTable(mtbl);
     source.setInsertedCount(0L);
@@ -3300,9 +3304,8 @@ private SourceTable convertToSourceTable(MMVSource 
mmvSource, String catalogName
       throws MetaException, NoSuchObjectException {
     SourceTable sourceTable = new SourceTable();
     MTable mTable = mmvSource.getTable();
-    Table table =
-        convertToTable(baseStore.ensureGetMTable(catalogName, 
mTable.getDatabase().getName(), mTable.getTableName()),
-            baseStore.getConf());
+    Table table = convertToTable(
+        ensureGetMTable(new TableName(catalogName, 
mTable.getDatabase().getName(), mTable.getTableName())));
     sourceTable.setTable(table);
     sourceTable.setInsertedCount(mmvSource.getInsertedCount());
     sourceTable.setUpdatedCount(mmvSource.getUpdatedCount());
diff --git 
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/metastore/TestObjectStoreUnwrap.java
 
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/metastore/TestObjectStoreUnwrap.java
new file mode 100644
index 00000000000..ac5c6ac07b6
--- /dev/null
+++ 
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/metastore/TestObjectStoreUnwrap.java
@@ -0,0 +1,365 @@
+/*
+ * 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.hadoop.hive.metastore.metastore;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.common.TableName;
+import org.apache.hadoop.hive.metastore.Deadline;
+import org.apache.hadoop.hive.metastore.HMSHandler;
+import org.apache.hadoop.hive.metastore.MetaStoreTestUtils;
+import org.apache.hadoop.hive.metastore.ObjectStore;
+import org.apache.hadoop.hive.metastore.Warehouse;
+import org.apache.hadoop.hive.metastore.annotation.MetastoreUnitTest;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.client.builder.DatabaseBuilder;
+import org.apache.hadoop.hive.metastore.client.builder.GetPartitionsArgs;
+import org.apache.hadoop.hive.metastore.client.builder.PartitionBuilder;
+import org.apache.hadoop.hive.metastore.client.builder.TableBuilder;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.hive.metastore.metastore.iface.TableStore;
+import org.apache.hadoop.hive.metastore.model.MTable;
+import org.apache.hadoop.hive.metastore.utils.DirectSqlConfigurator;
+import org.apache.hadoop.hive.metastore.utils.MetaStoreServerUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import static org.apache.hadoop.hive.metastore.Warehouse.DEFAULT_CATALOG_NAME;
+
+@Category(MetastoreUnitTest.class)
+public class TestObjectStoreUnwrap {
+  private static final String DB = "unwrap_proxy_db";
+  private static final String TABLE = "unwrap_proxy_tbl";
+
+  private ObjectStore objectStore;
+  private Configuration conf;
+  private TableName tableName;
+
+  @Before
+  public void setUp() throws Exception {
+    conf = MetastoreConf.newMetastoreConf();
+    MetastoreConf.setBoolVar(conf, ConfVars.HIVE_IN_TEST, true);
+    MetaStoreTestUtils.setConfForStandloneMode(conf);
+
+    String currentUrl = MetastoreConf.getVar(conf, ConfVars.CONNECT_URL_KEY);
+    currentUrl = currentUrl.replace(MetaStoreServerUtils.JUNIT_DATABASE_PREFIX,
+        String.format("%s_%s", MetaStoreServerUtils.JUNIT_DATABASE_PREFIX, 
UUID.randomUUID()));
+    MetastoreConf.setVar(conf, ConfVars.CONNECT_URL_KEY, currentUrl);
+
+    objectStore = new ObjectStore();
+    objectStore.setConf(conf);
+    HMSHandler.createDefaultCatalog(objectStore, new Warehouse(conf));
+    tableName = new TableName(DEFAULT_CATALOG_NAME, DB, TABLE);
+    createPartitionedTable();
+  }
+
+  @Test
+  public void testQueryClosedAfterRead() throws Exception {
+    TableStore tableStore = objectStore.unwrap(TableStore.class);
+    TransactionHandler<?> handler = getHandler(tableStore);
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      List<Partition> partitions = tableStore.getPartitions(tableName, args);
+      Assert.assertEquals(3, partitions.size());
+    }
+
+    Assert.assertEquals(0, handler.getOpenQueryCount());
+    Assert.assertFalse(objectStore.isActiveTransaction());
+  }
+
+  @Test
+  public void testQueryClosedAfterDelete() throws Exception {
+    TableStore tableStore = objectStore.unwrap(TableStore.class);
+    TransactionHandler<?> handler = getHandler(tableStore);
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      tableStore.dropPartitions(tableName, Arrays.asList("test_part_col=a0", 
"test_part_col=a1"));
+    }
+
+    Assert.assertEquals(0, handler.getOpenQueryCount());
+    Assert.assertFalse(objectStore.isActiveTransaction());
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      Assert.assertEquals(1, tableStore.getPartitions(tableName,
+          new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build()).size());
+    }
+    Assert.assertEquals(0, handler.getOpenQueryCount());
+  }
+
+  @Test
+  public void testRepeatedUnwrapNoLeaks() throws Exception {
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      for (int i = 0; i < 5; i++) {
+        TableStore tableStore = objectStore.unwrap(TableStore.class);
+        TransactionHandler<?> handler = getHandler(tableStore);
+        Assert.assertEquals(3, tableStore.getPartitions(tableName, 
args).size());
+        Assert.assertEquals("queries leaked on iteration " + i, 0, 
handler.getOpenQueryCount());
+      }
+    }
+    Assert.assertFalse(objectStore.isActiveTransaction());
+  }
+
+  @Test
+  public void testProxiesReadThenDelete() throws Exception {
+    TableStore readProxy = objectStore.unwrap(TableStore.class);
+    TableStore deleteProxy = objectStore.unwrap(TableStore.class);
+    Assert.assertNotSame(readProxy, deleteProxy);
+
+    TransactionHandler<?> readHandler = getHandler(readProxy);
+    TransactionHandler<?> deleteHandler = getHandler(deleteProxy);
+    Assert.assertNotSame(readHandler.openQueries(), 
deleteHandler.openQueries());
+
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      Assert.assertEquals(3, readProxy.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, readHandler.getOpenQueryCount());
+      Assert.assertEquals(0, deleteHandler.getOpenQueryCount());
+
+      Assert.assertEquals(3, deleteProxy.getPartitions(tableName, 
args).size());
+      Assert.assertEquals(0, deleteHandler.getOpenQueryCount());
+      Assert.assertEquals(0, readHandler.getOpenQueryCount());
+
+      deleteProxy.dropPartitions(tableName, Arrays.asList("test_part_col=a0", 
"test_part_col=a1"));
+      Assert.assertEquals(0, deleteHandler.getOpenQueryCount());
+
+      Assert.assertEquals(1, readProxy.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, readHandler.getOpenQueryCount());
+    }
+    Assert.assertFalse(objectStore.isActiveTransaction());
+  }
+
+  @Test
+  public void testProxiesInterleavedOps() throws Exception {
+    TableStore proxyA = objectStore.unwrap(TableStore.class);
+    TableStore proxyB = objectStore.unwrap(TableStore.class);
+    TransactionHandler<?> handlerA = getHandler(proxyA);
+    TransactionHandler<?> handlerB = getHandler(proxyB);
+    Assert.assertNotSame(handlerA.openQueries(), handlerB.openQueries());
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      Assert.assertEquals(3, proxyA.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, handlerA.getOpenQueryCount());
+
+      Assert.assertEquals(3, proxyB.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, handlerB.getOpenQueryCount());
+
+      proxyA.dropPartitions(tableName, 
Collections.singletonList("test_part_col=a0"));
+      Assert.assertEquals(0, handlerA.getOpenQueryCount());
+
+      Assert.assertEquals(2, proxyB.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, handlerB.getOpenQueryCount());
+
+      proxyB.dropPartitions(tableName, 
Collections.singletonList("test_part_col=a1"));
+      Assert.assertEquals(0, handlerB.getOpenQueryCount());
+
+      Assert.assertEquals(1, proxyA.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, handlerA.getOpenQueryCount());
+    }
+    Assert.assertFalse(objectStore.isActiveTransaction());
+  }
+
+  @Test
+  public void testProxiesVisibleInTxn() throws Exception {
+    TableStore proxyA = objectStore.unwrap(TableStore.class);
+    TableStore proxyB = objectStore.unwrap(TableStore.class);
+    Assert.assertNotSame(proxyA, proxyB);
+
+    TransactionHandler<?> handlerA = getHandler(proxyA);
+    TransactionHandler<?> handlerB = getHandler(proxyB);
+    Assert.assertNotSame(handlerA.openQueries(), handlerB.openQueries());
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      objectStore.openTransaction();
+      try {
+        Assert.assertTrue(objectStore.isActiveTransaction());
+
+        Assert.assertEquals(3, proxyA.getPartitions(tableName, args).size());
+        Assert.assertEquals(0, handlerA.getOpenQueryCount());
+
+        proxyA.dropPartitions(tableName, Arrays.asList("test_part_col=a0", 
"test_part_col=a1"));
+        Assert.assertEquals(0, handlerA.getOpenQueryCount());
+        Assert.assertTrue(objectStore.isActiveTransaction());
+
+        // Uncommitted deletes from proxyA are visible to proxyB within the 
same transaction.
+        Assert.assertEquals(1, proxyB.getPartitions(tableName, args).size());
+        Assert.assertEquals(0, handlerB.getOpenQueryCount());
+
+        proxyB.dropPartitions(tableName, 
Collections.singletonList("test_part_col=a2"));
+        Assert.assertEquals(0, handlerB.getOpenQueryCount());
+
+        // Uncommitted deletes from proxyB are visible to proxyA within the 
same transaction.
+        Assert.assertEquals(0, proxyA.getPartitions(tableName, args).size());
+        Assert.assertEquals(0, handlerA.getOpenQueryCount());
+
+        objectStore.commitTransaction();
+      } catch (Exception e) {
+        objectStore.rollbackTransaction();
+        throw e;
+      }
+    }
+    Assert.assertFalse(objectStore.isActiveTransaction());
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      Assert.assertEquals(0, proxyA.getPartitions(tableName, args).size());
+      Assert.assertEquals(0, proxyB.getPartitions(tableName, args).size());
+    }
+  }
+
+  @Test
+  public void testProxiesRollbackInTxn() throws Exception {
+    TableStore proxyA = objectStore.unwrap(TableStore.class);
+    TableStore proxyB = objectStore.unwrap(TableStore.class);
+    GetPartitionsArgs args = new 
GetPartitionsArgs.GetPartitionsArgsBuilder().max(10).build();
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      objectStore.openTransaction();
+      try {
+        proxyA.dropPartitions(tableName, Arrays.asList("test_part_col=a0", 
"test_part_col=a1"));
+        Assert.assertEquals(1, proxyB.getPartitions(tableName, args).size());
+        objectStore.rollbackTransaction();
+      } catch (Exception e) {
+        objectStore.rollbackTransaction();
+        throw e;
+      }
+    }
+    Assert.assertFalse(objectStore.isActiveTransaction());
+
+    try (AutoCloseable ignored = deadline();
+         DirectSqlConfigurator directSql = new DirectSqlConfigurator(conf, 
false)) {
+      Assert.assertEquals(3, proxyA.getPartitions(tableName, args).size());
+      Assert.assertEquals(3, proxyB.getPartitions(tableName, args).size());
+    }
+  }
+
+  @Test
+  public void testLeakingQueries() throws Exception {
+    TableStore proxyA = objectStore.unwrap(TableStore.class);
+    TransactionHandler<TableStore> handlerA = getHandler(proxyA);
+    RawStoreBundle rsbA = (RawStoreBundle) handlerA.simpl();
+    rsbA.getPersistentManager().newQuery(MTable.class);
+    rsbA.getPersistentManager().newQuery(MTable.class);
+    rsbA.getPersistentManager().newQuery(MTable.class);
+    // handlerA should have 3 opening queries
+    Assert.assertEquals(3, handlerA.getOpenQueryCount());
+
+    // Imaging proxyA creates a nested proxyB inside the same transaction
+    TableStore proxyB = objectStore.unwrap(TableStore.class);
+    TransactionHandler<TableStore> handlerB = getHandler(proxyB);
+    RawStoreBundle rsbB = (RawStoreBundle) handlerB.simpl();
+    rsbB.getPersistentManager().newQuery(MTable.class);
+    // Don't overwrite the queries opened by handlerA
+    Assert.assertEquals(3, handlerA.getOpenQueryCount());
+    Assert.assertEquals(1, handlerB.getOpenQueryCount());
+
+    proxyA.getTable(tableName, null, -1);
+    // handleA should close all opening queries at the end of transaction
+    Assert.assertEquals(0, handlerA.getOpenQueryCount());
+    // Shouldn't affect the opening queries in handlerB
+    Assert.assertEquals(1, handlerB.getOpenQueryCount());
+
+    rsbA.getPersistentManager().newQuery(MTable.class);
+    proxyB.getTable(tableName, null, -1);
+    Assert.assertEquals(0, handlerB.getOpenQueryCount());
+    // Shouldn't affect the opening queries in handlerA
+    Assert.assertEquals(1, handlerA.getOpenQueryCount());
+  }
+
+  @Test
+  public void testCreateTableSharesPm() throws Exception {
+    String otherDb = "unwrap_other_db";
+    String otherTable = "unwrap_other_tbl";
+    objectStore.createDatabase(new DatabaseBuilder()
+        .setName(otherDb)
+        .setDescription("description")
+        .setLocation("locationurl")
+        .build(conf));
+
+    Table table = new TableBuilder()
+        .setDbName(otherDb)
+        .setTableName(otherTable)
+        .addCol("c", "int")
+        .build(conf);
+
+    TableStore tableStore = objectStore.unwrap(TableStore.class);
+    tableStore.createTable(table);
+
+    Table fetched = tableStore.getTable(
+        new TableName(DEFAULT_CATALOG_NAME, otherDb, otherTable), null, -1);
+    Assert.assertNotNull(fetched);
+    Assert.assertEquals(0, getHandler(tableStore).getOpenQueryCount());
+    Assert.assertFalse(objectStore.isActiveTransaction());
+  }
+
+  private void createPartitionedTable() throws Exception {
+    objectStore.createDatabase(new DatabaseBuilder()
+        .setName(DB)
+        .setDescription("description")
+        .setLocation("locationurl")
+        .build(conf));
+
+    Table table = new TableBuilder()
+        .setDbName(DB)
+        .setTableName(TABLE)
+        .addCol("test_col1", "int")
+        .addPartCol("test_part_col", "int")
+        .build(conf);
+    objectStore.createTable(table);
+
+    for (int i = 0; i < 3; i++) {
+      Partition part = new PartitionBuilder()
+          .inTable(table)
+          .addValue("a" + i)
+          .build(conf);
+      objectStore.addPartition(part);
+    }
+  }
+
+  private static <T> TransactionHandler<T> getHandler(Object storeProxy) {
+    return (TransactionHandler<T>) Proxy.getInvocationHandler(storeProxy);
+  }
+
+  private AutoCloseable deadline() throws Exception {
+    Deadline.registerIfNot(100_000);
+    Deadline.startTimer("TestObjectStoreUnwrap");
+    return Deadline::stopTimer;
+  }
+}

Reply via email to