You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by ek...@apache.org on 2018/07/23 18:02:54 UTC
hive git commit: HIVE-17683: Add explain locks command (Igor
Kryvenko via Eugene Koifman)
Repository: hive
Updated Branches:
refs/heads/master bed17e54d -> 90d19acd2
HIVE-17683: Add explain locks <sql> command (Igor Kryvenko via Eugene Koifman)
Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/90d19acd
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/90d19acd
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/90d19acd
Branch: refs/heads/master
Commit: 90d19acd2b4f8301847ef13b4c8a91df3eafc65d
Parents: bed17e5
Author: Igor Kryvenko <kr...@gmail.com>
Authored: Mon Jul 23 11:02:17 2018 -0700
Committer: Eugene Koifman <ek...@apache.org>
Committed: Mon Jul 23 11:02:17 2018 -0700
----------------------------------------------------------------------
.../apache/hadoop/hive/ql/exec/ExplainTask.java | 46 ++++
.../org/apache/hadoop/hive/ql/io/AcidUtils.java | 206 ++++++++++++++++++
.../hadoop/hive/ql/lockmgr/DbTxnManager.java | 218 +------------------
.../apache/hadoop/hive/ql/metadata/Table.java | 4 +
.../hive/ql/parse/ExplainConfiguration.java | 8 +
.../hive/ql/parse/ExplainSemanticAnalyzer.java | 2 +
.../apache/hadoop/hive/ql/parse/HiveParser.g | 1 +
.../apache/hadoop/hive/ql/plan/ExplainWork.java | 17 ++
.../test/queries/clientpositive/explain_locks.q | 22 ++
.../results/clientpositive/explain_locks.q.out | 91 ++++++++
.../hive/metastore/LockComponentBuilder.java | 5 +
.../hive/metastore/LockRequestBuilder.java | 17 ++
12 files changed, 429 insertions(+), 208 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/exec/ExplainTask.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/ExplainTask.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/ExplainTask.java
index 752c3f3..f185d9d 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/ExplainTask.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/ExplainTask.java
@@ -45,9 +45,11 @@ import org.apache.hadoop.hive.common.jsonexplain.JsonParserFactory;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.metastore.api.FieldSchema;
+import org.apache.hadoop.hive.metastore.api.LockComponent;
import org.apache.hadoop.hive.ql.Driver;
import org.apache.hadoop.hive.ql.DriverContext;
import org.apache.hadoop.hive.ql.hooks.ReadEntity;
+import org.apache.hadoop.hive.ql.io.AcidUtils;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.optimizer.physical.StageIDsRearranger;
import org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer;
@@ -55,6 +57,7 @@ import org.apache.hadoop.hive.ql.parse.ExplainConfiguration.VectorizationDetailL
import org.apache.hadoop.hive.ql.plan.Explain;
import org.apache.hadoop.hive.ql.plan.Explain.Level;
import org.apache.hadoop.hive.ql.plan.Explain.Vectorization;
+import org.apache.hadoop.hive.ql.plan.ExplainLockDesc;
import org.apache.hadoop.hive.ql.plan.ExplainWork;
import org.apache.hadoop.hive.ql.plan.HiveOperation;
import org.apache.hadoop.hive.ql.plan.OperatorDesc;
@@ -330,6 +333,44 @@ public class ExplainTask extends Task<ExplainWork> implements Serializable {
return null;
}
+ private JSONObject getLocks(PrintStream out, ExplainWork work) {
+
+ JSONObject jsonObject = new JSONObject(new LinkedHashMap<>());
+
+ boolean jsonOutput = work.isFormatted();
+ if (jsonOutput) {
+ out = null;
+ }
+ if (work.getParseContext() != null) {
+ List<LockComponent> lockComponents = AcidUtils.makeLockComponents(work.getOutputs(), work.getInputs(), conf);
+ if (null != out) {
+ out.print("LOCK INFORMATION:\n");
+ }
+ List<ExplainLockDesc> locks = new ArrayList<>(lockComponents.size());
+
+ for (LockComponent component : lockComponents) {
+ ExplainLockDesc lockDesc = new ExplainLockDesc(component);
+
+ if (null != out) {
+ out.print(lockDesc.getFullName());
+ out.print(" -> ");
+ out.print(lockDesc.getLockType());
+ out.print('\n');
+ } else {
+ locks.add(lockDesc);
+ }
+
+ }
+
+ if (jsonOutput) {
+ jsonObject.put("LOCK INFORMATION:", locks);
+ }
+ } else {
+ System.err.println("No parse context!");
+ }
+ return jsonObject;
+ }
+
@Override
public int execute(DriverContext driverContext) {
@@ -352,6 +393,11 @@ public class ExplainTask extends Task<ExplainWork> implements Serializable {
} else if (work.getDependency()) {
JSONObject jsonDependencies = getJSONDependencies(work);
out.print(jsonDependencies);
+ } else if (work.isLocks()) {
+ JSONObject jsonLocks = getLocks(out, work);
+ if(work.isFormatted()) {
+ out.print(jsonLocks);
+ }
} else {
if (work.isUserLevelExplain()) {
// Because of the implementation of the JsonParserFactory, we are sure
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java b/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
index 16ba82e..a9983b0 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
@@ -32,6 +32,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
+import com.google.common.base.Preconditions;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
@@ -45,17 +46,25 @@ import org.apache.hadoop.hive.common.ValidTxnWriteIdList;
import org.apache.hadoop.hive.common.ValidWriteIdList;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
+import org.apache.hadoop.hive.metastore.LockComponentBuilder;
import org.apache.hadoop.hive.metastore.TransactionalValidationListener;
import org.apache.hadoop.hive.metastore.api.DataOperationType;
+import org.apache.hadoop.hive.metastore.api.LockComponent;
+import org.apache.hadoop.hive.metastore.api.LockType;
import org.apache.hadoop.hive.metastore.api.hive_metastoreConstants;
+import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils;
import org.apache.hadoop.hive.ql.ErrorMsg;
import org.apache.hadoop.hive.ql.exec.Utilities;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.ReadEntity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
import org.apache.hadoop.hive.ql.io.AcidUtils.ParsedDelta;
import org.apache.hadoop.hive.ql.io.orc.OrcFile;
import org.apache.hadoop.hive.ql.io.orc.OrcInputFormat;
import org.apache.hadoop.hive.ql.io.orc.OrcRecordUpdater;
import org.apache.hadoop.hive.ql.io.orc.Reader;
import org.apache.hadoop.hive.ql.io.orc.Writer;
+import org.apache.hadoop.hive.ql.metadata.HiveStorageHandler;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.plan.CreateTableDesc;
import org.apache.hadoop.hive.ql.plan.TableScanDesc;
@@ -1984,4 +1993,201 @@ public class AcidUtils {
tblProps.put(hive_metastoreConstants.TABLE_IS_TRANSACTIONAL, "false");
tblProps.remove(hive_metastoreConstants.TABLE_TRANSACTIONAL_PROPERTIES);
}
+
+ private static boolean needsLock(Entity entity) {
+ switch (entity.getType()) {
+ case TABLE:
+ return isLockableTable(entity.getTable());
+ case PARTITION:
+ return isLockableTable(entity.getPartition().getTable());
+ default:
+ return true;
+ }
+ }
+
+ private static Table getTable(WriteEntity we) {
+ Table t = we.getTable();
+ if (t == null) {
+ throw new IllegalStateException("No table info for " + we);
+ }
+ return t;
+ }
+
+ private static boolean isLockableTable(Table t) {
+ if (t.isTemporary()) {
+ return false;
+ }
+ switch (t.getTableType()) {
+ case MANAGED_TABLE:
+ case MATERIALIZED_VIEW:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Create lock components from write/read entities.
+ * @param outputs write entities
+ * @param inputs read entities
+ * @param conf
+ * @return list with lock components
+ */
+ public static List<LockComponent> makeLockComponents(Set<WriteEntity> outputs, Set<ReadEntity> inputs,
+ HiveConf conf) {
+ List<LockComponent> lockComponents = new ArrayList<>();
+ // For each source to read, get a shared lock
+ for (ReadEntity input : inputs) {
+ if (!input.needsLock() || input.isUpdateOrDelete() || !AcidUtils.needsLock(input)) {
+ // We don't want to acquire read locks during update or delete as we'll be acquiring write
+ // locks instead. Also, there's no need to lock temp tables since they're session wide
+ continue;
+ }
+ LockComponentBuilder compBuilder = new LockComponentBuilder();
+ compBuilder.setShared();
+ compBuilder.setOperationType(DataOperationType.SELECT);
+
+ Table t = null;
+ switch (input.getType()) {
+ case DATABASE:
+ compBuilder.setDbName(input.getDatabase().getName());
+ break;
+
+ case TABLE:
+ t = input.getTable();
+ compBuilder.setDbName(t.getDbName());
+ compBuilder.setTableName(t.getTableName());
+ break;
+
+ case PARTITION:
+ case DUMMYPARTITION:
+ compBuilder.setPartitionName(input.getPartition().getName());
+ t = input.getPartition().getTable();
+ compBuilder.setDbName(t.getDbName());
+ compBuilder.setTableName(t.getTableName());
+ break;
+
+ default:
+ // This is a file or something we don't hold locks for.
+ continue;
+ }
+ if (t != null) {
+ compBuilder.setIsTransactional(AcidUtils.isTransactionalTable(t));
+ }
+ LockComponent comp = compBuilder.build();
+ LOG.debug("Adding lock component to lock request " + comp.toString());
+ lockComponents.add(comp);
+ }
+ // For each source to write to, get the appropriate lock type. If it's
+ // an OVERWRITE, we need to get an exclusive lock. If it's an insert (no
+ // overwrite) than we need a shared. If it's update or delete then we
+ // need a SEMI-SHARED.
+ for (WriteEntity output : outputs) {
+ LOG.debug("output is null " + (output == null));
+ if (output.getType() == Entity.Type.DFS_DIR || output.getType() == Entity.Type.LOCAL_DIR || !AcidUtils
+ .needsLock(output)) {
+ // We don't lock files or directories. We also skip locking temp tables.
+ continue;
+ }
+ LockComponentBuilder compBuilder = new LockComponentBuilder();
+ Table t = null;
+ switch (output.getType()) {
+ case DATABASE:
+ compBuilder.setDbName(output.getDatabase().getName());
+ break;
+
+ case TABLE:
+ case DUMMYPARTITION: // in case of dynamic partitioning lock the table
+ t = output.getTable();
+ compBuilder.setDbName(t.getDbName());
+ compBuilder.setTableName(t.getTableName());
+ break;
+
+ case PARTITION:
+ compBuilder.setPartitionName(output.getPartition().getName());
+ t = output.getPartition().getTable();
+ compBuilder.setDbName(t.getDbName());
+ compBuilder.setTableName(t.getTableName());
+ break;
+
+ default:
+ // This is a file or something we don't hold locks for.
+ continue;
+ }
+ switch (output.getWriteType()) {
+ /* base this on HiveOperation instead? this and DDL_NO_LOCK is peppered all over the code...
+ Seems much cleaner if each stmt is identified as a particular HiveOperation (which I'd think
+ makes sense everywhere). This however would be problematic for merge...*/
+ case DDL_EXCLUSIVE:
+ compBuilder.setExclusive();
+ compBuilder.setOperationType(DataOperationType.NO_TXN);
+ break;
+ case INSERT_OVERWRITE:
+ t = AcidUtils.getTable(output);
+ if (AcidUtils.isTransactionalTable(t)) {
+ if (conf.getBoolVar(HiveConf.ConfVars.TXN_OVERWRITE_X_LOCK)) {
+ compBuilder.setExclusive();
+ } else {
+ compBuilder.setSemiShared();
+ }
+ compBuilder.setOperationType(DataOperationType.UPDATE);
+ } else {
+ compBuilder.setExclusive();
+ compBuilder.setOperationType(DataOperationType.NO_TXN);
+ }
+ break;
+ case INSERT:
+ assert t != null;
+ if (AcidUtils.isTransactionalTable(t)) {
+ compBuilder.setShared();
+ } else if (MetaStoreUtils.isNonNativeTable(t.getTTable())) {
+ final HiveStorageHandler storageHandler = Preconditions.checkNotNull(t.getStorageHandler(),
+ "Thought all the non native tables have an instance of storage handler");
+ LockType lockType = storageHandler.getLockType(output);
+ if (null == LockType.findByValue(lockType.getValue())) {
+ throw new IllegalArgumentException(String
+ .format("Lock type [%s] for Database.Table [%s.%s] is unknown", lockType, t.getDbName(),
+ t.getTableName()));
+ }
+ compBuilder.setLock(lockType);
+ } else {
+ if (conf.getBoolVar(HiveConf.ConfVars.HIVE_TXN_STRICT_LOCKING_MODE)) {
+ compBuilder.setExclusive();
+ } else { // this is backward compatible for non-ACID resources, w/o ACID semantics
+ compBuilder.setShared();
+ }
+ }
+ compBuilder.setOperationType(DataOperationType.INSERT);
+ break;
+ case DDL_SHARED:
+ compBuilder.setShared();
+ compBuilder.setOperationType(DataOperationType.NO_TXN);
+ break;
+
+ case UPDATE:
+ compBuilder.setSemiShared();
+ compBuilder.setOperationType(DataOperationType.UPDATE);
+ break;
+ case DELETE:
+ compBuilder.setSemiShared();
+ compBuilder.setOperationType(DataOperationType.DELETE);
+ break;
+
+ case DDL_NO_LOCK:
+ continue; // No lock required here
+
+ default:
+ throw new RuntimeException("Unknown write type " + output.getWriteType().toString());
+ }
+ if (t != null) {
+ compBuilder.setIsTransactional(AcidUtils.isTransactionalTable(t));
+ }
+
+ compBuilder.setIsDynamicPartitionWrite(output.isDynamicPartitionWrite());
+ LockComponent comp = compBuilder.build();
+ LOG.debug("Adding lock component to lock request " + comp.toString());
+ lockComponents.add(comp);
+ }
+ return lockComponents;
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/DbTxnManager.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/DbTxnManager.java b/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/DbTxnManager.java
index 78980fa..06067a2 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/DbTxnManager.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/DbTxnManager.java
@@ -18,20 +18,16 @@
package org.apache.hadoop.hive.ql.lockmgr;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.common.JavaUtils;
import org.apache.hadoop.hive.common.ValidTxnList;
import org.apache.hadoop.hive.common.ValidTxnWriteIdList;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.IMetaStoreClient;
-import org.apache.hadoop.hive.metastore.LockComponentBuilder;
import org.apache.hadoop.hive.metastore.LockRequestBuilder;
-import org.apache.hadoop.hive.metastore.api.DataOperationType;
import org.apache.hadoop.hive.metastore.api.LockComponent;
import org.apache.hadoop.hive.metastore.api.LockResponse;
import org.apache.hadoop.hive.metastore.api.LockState;
-import org.apache.hadoop.hive.metastore.api.LockType;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.hive.metastore.api.NoSuchLockException;
import org.apache.hadoop.hive.metastore.api.NoSuchTxnException;
@@ -39,18 +35,13 @@ import org.apache.hadoop.hive.metastore.api.TxnAbortedException;
import org.apache.hadoop.hive.metastore.api.TxnToWriteId;
import org.apache.hadoop.hive.metastore.api.CommitTxnRequest;
import org.apache.hadoop.hive.metastore.txn.TxnUtils;
-import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils;
import org.apache.hadoop.hive.ql.Context;
import org.apache.hadoop.hive.ql.ErrorMsg;
import org.apache.hadoop.hive.ql.QueryPlan;
-import org.apache.hadoop.hive.ql.hooks.Entity;
-import org.apache.hadoop.hive.ql.hooks.ReadEntity;
import org.apache.hadoop.hive.ql.hooks.WriteEntity;
import org.apache.hadoop.hive.ql.io.AcidUtils;
import org.apache.hadoop.hive.ql.metadata.Hive;
import org.apache.hadoop.hive.ql.metadata.HiveException;
-import org.apache.hadoop.hive.ql.metadata.HiveStorageHandler;
-import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.plan.HiveOperation;
import org.apache.hadoop.hive.ql.plan.LockDatabaseDesc;
import org.apache.hadoop.hive.ql.plan.LockTableDesc;
@@ -381,28 +372,7 @@ public final class DbTxnManager extends HiveTxnManagerImpl {
//todo: handle Insert Overwrite as well: HIVE-18154
return false;
}
- private boolean needsLock(Entity entity) {
- switch (entity.getType()) {
- case TABLE:
- return isLockableTable(entity.getTable());
- case PARTITION:
- return isLockableTable(entity.getPartition().getTable());
- default:
- return true;
- }
- }
- private boolean isLockableTable(Table t) {
- if(t.isTemporary()) {
- return false;
- }
- switch (t.getTableType()) {
- case MANAGED_TABLE:
- case MATERIALIZED_VIEW:
- return true;
- default:
- return false;
- }
- }
+
/**
* Normally client should call {@link #acquireLocks(org.apache.hadoop.hive.ql.QueryPlan, org.apache.hadoop.hive.ql.Context, String)}
* @param isBlocking if false, the method will return immediately; thus the locks may be in LockState.WAITING
@@ -414,7 +384,6 @@ public final class DbTxnManager extends HiveTxnManagerImpl {
// Make sure we've built the lock manager
getLockManager();
verifyState(plan);
- boolean atLeastOneLock = false;
queryId = plan.getQueryId();
switch (plan.getOperation()) {
case SET_AUTOCOMMIT:
@@ -429,193 +398,26 @@ public final class DbTxnManager extends HiveTxnManagerImpl {
rqstBuilder.setTransactionId(txnId)
.setUser(username);
- // For each source to read, get a shared lock
- for (ReadEntity input : plan.getInputs()) {
- if (!input.needsLock() || input.isUpdateOrDelete() || !needsLock(input)) {
- // We don't want to acquire read locks during update or delete as we'll be acquiring write
- // locks instead. Also, there's no need to lock temp tables since they're session wide
- continue;
- }
- LockComponentBuilder compBuilder = new LockComponentBuilder();
- compBuilder.setShared();
- compBuilder.setOperationType(DataOperationType.SELECT);
-
- Table t = null;
- switch (input.getType()) {
- case DATABASE:
- compBuilder.setDbName(input.getDatabase().getName());
- break;
-
- case TABLE:
- t = input.getTable();
- compBuilder.setDbName(t.getDbName());
- compBuilder.setTableName(t.getTableName());
- break;
-
- case PARTITION:
- case DUMMYPARTITION:
- compBuilder.setPartitionName(input.getPartition().getName());
- t = input.getPartition().getTable();
- compBuilder.setDbName(t.getDbName());
- compBuilder.setTableName(t.getTableName());
- break;
-
- default:
- // This is a file or something we don't hold locks for.
- continue;
- }
- if(t != null) {
- compBuilder.setIsTransactional(AcidUtils.isTransactionalTable(t));
- }
- LockComponent comp = compBuilder.build();
- LOG.debug("Adding lock component to lock request " + comp.toString());
- rqstBuilder.addLockComponent(comp);
- atLeastOneLock = true;
- }
-
- // For each source to write to, get the appropriate lock type. If it's
- // an OVERWRITE, we need to get an exclusive lock. If it's an insert (no
- // overwrite) than we need a shared. If it's update or delete then we
- // need a SEMI-SHARED.
- for (WriteEntity output : plan.getOutputs()) {
- LOG.debug("output is null " + (output == null));
- if (output.getType() == Entity.Type.DFS_DIR || output.getType() == Entity.Type.LOCAL_DIR ||
- !needsLock(output)) {
- // We don't lock files or directories. We also skip locking temp tables.
- continue;
- }
- LockComponentBuilder compBuilder = new LockComponentBuilder();
- Table t = null;
- switch (output.getType()) {
- case DATABASE:
- compBuilder.setDbName(output.getDatabase().getName());
- break;
-
- case TABLE:
- case DUMMYPARTITION: // in case of dynamic partitioning lock the table
- t = output.getTable();
- compBuilder.setDbName(t.getDbName());
- compBuilder.setTableName(t.getTableName());
- break;
-
- case PARTITION:
- compBuilder.setPartitionName(output.getPartition().getName());
- t = output.getPartition().getTable();
- compBuilder.setDbName(t.getDbName());
- compBuilder.setTableName(t.getTableName());
- break;
-
- default:
- // This is a file or something we don't hold locks for.
- continue;
- }
- switch (output.getWriteType()) {
- /* base this on HiveOperation instead? this and DDL_NO_LOCK is peppered all over the code...
- Seems much cleaner if each stmt is identified as a particular HiveOperation (which I'd think
- makes sense everywhere). This however would be problematic for merge...*/
- case DDL_EXCLUSIVE:
- compBuilder.setExclusive();
- compBuilder.setOperationType(DataOperationType.NO_TXN);
- break;
- case INSERT_OVERWRITE:
- t = getTable(output);
- if (AcidUtils.isTransactionalTable(t)) {
- if (conf.getBoolVar(HiveConf.ConfVars.TXN_OVERWRITE_X_LOCK)) {
- compBuilder.setExclusive();
- } else {
- compBuilder.setSemiShared();
- }
- compBuilder.setOperationType(DataOperationType.UPDATE);
- } else {
- compBuilder.setExclusive();
- compBuilder.setOperationType(DataOperationType.NO_TXN);
- }
- break;
- case INSERT:
- assert t != null;
- if (AcidUtils.isTransactionalTable(t)) {
- compBuilder.setShared();
- } else if (MetaStoreUtils.isNonNativeTable(t.getTTable())) {
- final HiveStorageHandler storageHandler = Preconditions.checkNotNull(t.getStorageHandler(),
- "Thought all the non native tables have an instance of storage handler"
- );
- LockType lockType = storageHandler.getLockType(output);
- switch (lockType) {
- case EXCLUSIVE:
- compBuilder.setExclusive();
- break;
- case SHARED_READ:
- compBuilder.setShared();
- break;
- case SHARED_WRITE:
- compBuilder.setSemiShared();
- break;
- default:
- throw new IllegalArgumentException(String
- .format("Lock type [%s] for Database.Table [%s.%s] is unknown", lockType, t.getDbName(),
- t.getTableName()
- ));
- }
-
- } else {
- if (conf.getBoolVar(HiveConf.ConfVars.HIVE_TXN_STRICT_LOCKING_MODE)) {
- compBuilder.setExclusive();
- } else { // this is backward compatible for non-ACID resources, w/o ACID semantics
- compBuilder.setShared();
- }
- }
- compBuilder.setOperationType(DataOperationType.INSERT);
- break;
- case DDL_SHARED:
- compBuilder.setShared();
- compBuilder.setOperationType(DataOperationType.NO_TXN);
- break;
-
- case UPDATE:
- compBuilder.setSemiShared();
- compBuilder.setOperationType(DataOperationType.UPDATE);
- break;
- case DELETE:
- compBuilder.setSemiShared();
- compBuilder.setOperationType(DataOperationType.DELETE);
- break;
-
- case DDL_NO_LOCK:
- continue; // No lock required here
-
- default:
- throw new RuntimeException("Unknown write type " + output.getWriteType().toString());
- }
- if (t != null) {
- compBuilder.setIsTransactional(AcidUtils.isTransactionalTable(t));
- }
-
- compBuilder.setIsDynamicPartitionWrite(output.isDynamicPartitionWrite());
- LockComponent comp = compBuilder.build();
- LOG.debug("Adding lock component to lock request " + comp.toString());
- rqstBuilder.addLockComponent(comp);
- atLeastOneLock = true;
- }
- //plan
// Make sure we need locks. It's possible there's nothing to lock in
// this operation.
- if (!atLeastOneLock) {
+ if(plan.getInputs().isEmpty() && plan.getOutputs().isEmpty()) {
+ LOG.debug("No locks needed for queryId" + queryId);
+ return null;
+ }
+ List<LockComponent> lockComponents = AcidUtils.makeLockComponents(plan.getOutputs(), plan.getInputs(), conf);
+ //It's possible there's nothing to lock even if we have w/r entities.
+ if(lockComponents.isEmpty()) {
LOG.debug("No locks needed for queryId" + queryId);
return null;
}
+ rqstBuilder.addLockComponents(lockComponents);
List<HiveLock> locks = new ArrayList<HiveLock>(1);
LockState lockState = lockMgr.lock(rqstBuilder.build(), queryId, isBlocking, locks);
ctx.setHiveLocks(locks);
return lockState;
}
- private static Table getTable(WriteEntity we) {
- Table t = we.getTable();
- if(t == null) {
- throw new IllegalStateException("No table info for " + we);
- }
- return t;
- }
+
/**
* @param delay time to delay for first heartbeat
*/
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java b/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java
index 14e60f0..03b0269 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java
@@ -1087,4 +1087,8 @@ public class Table implements Serializable {
public boolean hasDeserializer() {
return deserializer != null;
}
+
+ public String getCatalogName() {
+ return this.tTable.getCatName();
+ }
};
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainConfiguration.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainConfiguration.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainConfiguration.java
index 105ef08..5ca6b59 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainConfiguration.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainConfiguration.java
@@ -47,6 +47,7 @@ public class ExplainConfiguration {
private boolean vectorization = false;
private boolean vectorizationOnly = false;
private VectorizationDetailLevel vectorizationDetailLevel = VectorizationDetailLevel.SUMMARY;
+ private boolean locks = false;
private Path explainRootPath;
private Map<String, Long> opIdToRuntimeNumRows;
@@ -153,4 +154,11 @@ public class ExplainConfiguration {
this.opIdToRuntimeNumRows = opIdToRuntimeNumRows;
}
+ public boolean isLocks() {
+ return locks;
+ }
+
+ public void setLocks(boolean locks) {
+ this.locks = locks;
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainSemanticAnalyzer.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainSemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainSemanticAnalyzer.java
index feec0fd..3aefb61 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainSemanticAnalyzer.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/ExplainSemanticAnalyzer.java
@@ -112,6 +112,8 @@ public class ExplainSemanticAnalyzer extends BaseSemanticAnalyzer {
i++;
}
}
+ } else if (explainOptions == HiveParser.KW_LOCKS) {
+ config.setLocks(true);
} else {
// UNDONE: UNKNOWN OPTION?
}
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g b/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g
index 1f53321..6be48ca 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g
@@ -799,6 +799,7 @@ explainOption
| KW_AUTHORIZATION
| KW_ANALYZE
| KW_REOPTIMIZATION
+ | KW_LOCKS
| (KW_VECTORIZATION vectorizationOnly? vectorizatonDetail?)
;
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/java/org/apache/hadoop/hive/ql/plan/ExplainWork.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/plan/ExplainWork.java b/ql/src/java/org/apache/hadoop/hive/ql/plan/ExplainWork.java
index ce03003..3e62142 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/plan/ExplainWork.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/plan/ExplainWork.java
@@ -26,6 +26,7 @@ import java.util.List;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hive.ql.exec.Task;
import org.apache.hadoop.hive.ql.hooks.ReadEntity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
import org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer;
import org.apache.hadoop.hive.ql.parse.ExplainConfiguration;
import org.apache.hadoop.hive.ql.parse.ExplainConfiguration.VectorizationDetailLevel;
@@ -42,6 +43,7 @@ public class ExplainWork implements Serializable {
private ArrayList<Task<?>> rootTasks;
private Task<?> fetchTask;
private HashSet<ReadEntity> inputs;
+ private HashSet<WriteEntity> outputs;
private ParseContext pCtx;
private ExplainConfiguration config;
@@ -72,6 +74,9 @@ public class ExplainWork implements Serializable {
if (analyzer != null) {
this.inputs = analyzer.getInputs();
}
+ if (analyzer != null) {
+ this.outputs = analyzer.getAllOutputs();
+ }
this.pCtx = pCtx;
this.cboInfo = cboInfo;
this.optimizedSQL = optimizedSQL;
@@ -110,6 +115,14 @@ public class ExplainWork implements Serializable {
this.inputs = inputs;
}
+ public HashSet<WriteEntity> getOutputs() {
+ return outputs;
+ }
+
+ public void setOutputs(HashSet<WriteEntity> outputs) {
+ this.outputs = outputs;
+ }
+
public boolean getExtended() {
return config.isExtended();
}
@@ -190,4 +203,8 @@ public class ExplainWork implements Serializable {
this.config = config;
}
+ public boolean isLocks() {
+ return config.isLocks();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/test/queries/clientpositive/explain_locks.q
----------------------------------------------------------------------
diff --git a/ql/src/test/queries/clientpositive/explain_locks.q b/ql/src/test/queries/clientpositive/explain_locks.q
new file mode 100644
index 0000000..a0e273f
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/explain_locks.q
@@ -0,0 +1,22 @@
+set hive.exec.dynamic.partition.mode=nonstrict;
+set hive.support.concurrency=true;
+set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
+
+explain locks drop table test_explain_locks;
+explain locks create table test_explain_locks (a int, b int);
+drop table if exists target;
+drop table if exists source;
+
+create table target (a int, b int) partitioned by (p int, q int) clustered by (a) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true');
+create table source (a1 int, b1 int, p1 int, q1 int) clustered by (a1) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true');
+insert into target partition(p,q) values (1,2,1,2), (3,4,1,2), (5,6,1,3), (7,8,2,2);
+
+-- the intent here is to record the set of ReadEntity and WriteEntity objects for these 2 update statements
+explain locks update target set b = 1 where p in (select t.q1 from source t where t.a1=5);
+
+explain locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2);
+
+explain formatted locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2);
+
+-- the extra predicates in when matched clause match 1 partition
+explain locks merge into target t using source s on t.a = s.a1 when matched and p = 1 and q = 2 then update set b = 1 when matched and p = 2 and q = 2 then delete when not matched and a1 > 100 then insert values(s.a1,s.b1,s.p1, s.q1);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/ql/src/test/results/clientpositive/explain_locks.q.out
----------------------------------------------------------------------
diff --git a/ql/src/test/results/clientpositive/explain_locks.q.out b/ql/src/test/results/clientpositive/explain_locks.q.out
new file mode 100644
index 0000000..72aa410
--- /dev/null
+++ b/ql/src/test/results/clientpositive/explain_locks.q.out
@@ -0,0 +1,91 @@
+PREHOOK: query: explain locks drop table test_explain_locks
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: explain locks drop table test_explain_locks
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: explain locks create table test_explain_locks (a int, b int)
+PREHOOK: type: CREATETABLE
+POSTHOOK: query: explain locks create table test_explain_locks (a int, b int)
+POSTHOOK: type: CREATETABLE
+LOCK INFORMATION:
+default -> SHARED_READ
+PREHOOK: query: drop table if exists target
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: drop table if exists target
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: drop table if exists source
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: drop table if exists source
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: create table target (a int, b int) partitioned by (p int, q int) clustered by (a) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@target
+POSTHOOK: query: create table target (a int, b int) partitioned by (p int, q int) clustered by (a) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@target
+PREHOOK: query: create table source (a1 int, b1 int, p1 int, q1 int) clustered by (a1) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@source
+POSTHOOK: query: create table source (a1 int, b1 int, p1 int, q1 int) clustered by (a1) into 2 buckets stored as orc TBLPROPERTIES ('transactional'='true')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@source
+PREHOOK: query: insert into target partition(p,q) values (1,2,1,2), (3,4,1,2), (5,6,1,3), (7,8,2,2)
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@target
+POSTHOOK: query: insert into target partition(p,q) values (1,2,1,2), (3,4,1,2), (5,6,1,3), (7,8,2,2)
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@target@p=1/q=2
+POSTHOOK: Output: default@target@p=1/q=3
+POSTHOOK: Output: default@target@p=2/q=2
+POSTHOOK: Lineage: target PARTITION(p=1,q=2).a SCRIPT []
+POSTHOOK: Lineage: target PARTITION(p=1,q=2).b SCRIPT []
+POSTHOOK: Lineage: target PARTITION(p=1,q=3).a SCRIPT []
+POSTHOOK: Lineage: target PARTITION(p=1,q=3).b SCRIPT []
+POSTHOOK: Lineage: target PARTITION(p=2,q=2).a SCRIPT []
+POSTHOOK: Lineage: target PARTITION(p=2,q=2).b SCRIPT []
+PREHOOK: query: explain locks update target set b = 1 where p in (select t.q1 from source t where t.a1=5)
+PREHOOK: type: QUERY
+POSTHOOK: query: explain locks update target set b = 1 where p in (select t.q1 from source t where t.a1=5)
+POSTHOOK: type: QUERY
+LOCK INFORMATION:
+default.source -> SHARED_READ
+default.target.p=1/q=2 -> SHARED_READ
+default.target.p=1/q=3 -> SHARED_READ
+default.target.p=2/q=2 -> SHARED_READ
+default.target.p=2/q=2 -> SHARED_WRITE
+default.target.p=1/q=3 -> SHARED_WRITE
+default.target.p=1/q=2 -> SHARED_WRITE
+PREHOOK: query: explain locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2)
+PREHOOK: type: QUERY
+POSTHOOK: query: explain locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2)
+POSTHOOK: type: QUERY
+LOCK INFORMATION:
+default.target -> SHARED_READ
+default.target.p=2/q=2 -> SHARED_READ
+default.source -> SHARED_WRITE
+PREHOOK: query: explain formatted locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2)
+PREHOOK: type: QUERY
+POSTHOOK: query: explain formatted locks update source set b1 = 1 where p1 in (select t.q from target t where t.p=2)
+POSTHOOK: type: QUERY
+{"LOCK INFORMATION:":"[default.target -> SHARED_READ, default.target.p=2/q=2 -> SHARED_READ, default.source -> SHARED_WRITE]"}
+PREHOOK: query: explain locks merge into target t using source s on t.a = s.a1 when matched and p = 1 and q = 2 then update set b = 1 when matched and p = 2 and q = 2 then delete when not matched and a1 > 100 then insert values(s.a1,s.b1,s.p1, s.q1)
+PREHOOK: type: QUERY
+POSTHOOK: query: explain locks merge into target t using source s on t.a = s.a1 when matched and p = 1 and q = 2 then update set b = 1 when matched and p = 2 and q = 2 then delete when not matched and a1 > 100 then insert values(s.a1,s.b1,s.p1, s.q1)
+POSTHOOK: type: QUERY
+LOCK INFORMATION:
+default.source -> SHARED_READ
+default.target.p=1/q=2 -> SHARED_READ
+default.target.p=1/q=3 -> SHARED_READ
+default.target.p=2/q=2 -> SHARED_READ
+default.target.p=2/q=2 -> SHARED_WRITE
+default.target.p=2/q=2 -> SHARED_WRITE
+default.target.p=1/q=3 -> SHARED_WRITE
+default.target.p=1/q=3 -> SHARED_WRITE
+default.target.p=1/q=2 -> SHARED_WRITE
+default.target.p=1/q=2 -> SHARED_WRITE
+default.target -> SHARED_READ
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockComponentBuilder.java
----------------------------------------------------------------------
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockComponentBuilder.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockComponentBuilder.java
index 1ad0638..c739d4d 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockComponentBuilder.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockComponentBuilder.java
@@ -118,4 +118,9 @@ public class LockComponentBuilder {
component.setLevel(level);
return component;
}
+
+ public LockComponent setLock(LockType type) {
+ component.setType(type);
+ return component;
+ }
}
http://git-wip-us.apache.org/repos/asf/hive/blob/90d19acd/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockRequestBuilder.java
----------------------------------------------------------------------
diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockRequestBuilder.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockRequestBuilder.java
index d03c73a..22902a9 100644
--- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockRequestBuilder.java
+++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/LockRequestBuilder.java
@@ -23,6 +23,7 @@ import org.apache.hadoop.hive.metastore.api.LockType;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -94,6 +95,16 @@ public class LockRequestBuilder {
return this;
}
+ /**
+ * Add a collection with lock components to the lock request
+ * @param components to add
+ * @return reference to this builder
+ */
+ public LockRequestBuilder addLockComponents(Collection<LockComponent> components) {
+ trie.addAll(components);
+ return this;
+ }
+
// For reasons that are completely incomprehensible to me the semantic
// analyzers often ask for multiple locks on the same entity (for example
// a shared_read and an exlcusive lock). The db locking system gets confused
@@ -120,6 +131,12 @@ public class LockRequestBuilder {
setTable(comp, tabs);
}
+ public void addAll(Collection<LockComponent> components) {
+ for(LockComponent component: components) {
+ add(component);
+ }
+ }
+
public void addLocksToRequest(LockRequest request) {
for (TableTrie tab : trie.values()) {
for (PartTrie part : tab.values()) {