diff --git standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java index f53aebe4ad..9ed908b56b 100644 --- standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java +++ standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TxnHandler.java @@ -4338,6 +4338,54 @@ private LockResponse checkLock(Connection dbConn, long extLockId) LOG.debug("checkLock(): Setting savepoint. extLockId=" + JavaUtils.lockIdToString(extLockId)); Savepoint save = dbConn.setSavepoint(); + + // Ref: https://issues.apache.org/jira/browse/HIVE-5843, + // https://issues.apache.org/jira/secure/attachment/12614488/HiveTransactionManagerDetailedDesign%20%281%29.pdf (page 8) + // for lock interaction matrix. + // Check whether all lock requests are in SHARED_READ state + boolean sharedReadsForLocksBeingChecked = true; + Set dbs = new HashSet<>(); + for(LockInfo lockInfo : locksBeingChecked) { + dbs.add(lockInfo.db); + if (lockInfo.type != LockType.SHARED_READ) { + sharedReadsForLocksBeingChecked = false; + break; + } + } + + // Check if one of the databases is in exclusive mode. + // If so, we need to run through entire checks. Otherwise, we can skip + // expensive computation for lock acquisition. This reduces runtime by + // good margin with concurrency. + if (sharedReadsForLocksBeingChecked) { + StringBuilder query = new StringBuilder("select count(*) from " + + "HIVE_LOCKS where hl_db in ("); + boolean first = true; + for (String s : dbs) { + if (first) + first = false; + else + query.append(", "); + query.append('\''); + query.append(s); + query.append('\''); + } + query.append(") AND HL_LOCK_TYPE ='" + LOCK_EXCLUSIVE + "'"); + + stmt = dbConn.createStatement(); + rs = stmt.executeQuery(query.toString()); + if (rs.next()) { + int count = rs.getInt(1); + if (count <= 0) { + // Early exit + acquireAndCommit(dbConn, stmt, locksBeingChecked); + response.setState(LockState.ACQUIRED); + return response; + } + } + } + + StringBuilder query = new StringBuilder("SELECT \"HL_LOCK_EXT_ID\", " + "\"HL_LOCK_INT_ID\", \"HL_DB\", \"HL_TABLE\", \"HL_PARTITION\", \"HL_LOCK_STATE\", " + "\"HL_LOCK_TYPE\", \"HL_TXNID\" FROM \"HIVE_LOCKS\" WHERE \"HL_DB\" IN ("); @@ -4522,7 +4570,10 @@ private LockResponse checkLock(Connection dbConn, long extLockId) // We've found something that matches what we're trying to lock, // so figure out if we can lock it too. LockAction lockAction = jumpTable.get(info.type).get(locks[i].type).get(locks[i].state); - LOG.debug("desired Lock: " + info + " checked Lock: " + locks[i] + " action: " + lockAction); + if (LOG.isDebugEnabled()) { + LOG.debug("desired Lock: " + info + " checked Lock: " + locks[i] + + " action: " + lockAction); + } switch (lockAction) { case WAIT: if(!ignoreConflict(info, locks[i])) { @@ -4556,21 +4607,28 @@ private LockResponse checkLock(Connection dbConn, long extLockId) break;// so exit the loop and check next lock } } - //if here, ther were no locks that blocked any locks in 'locksBeingChecked' - acquire them all - acquire(dbConn, stmt, locksBeingChecked); - - // We acquired all of the locks, so commit and return acquired. - LOG.debug("Going to commit"); - dbConn.commit(); + acquireAndCommit(dbConn, stmt, locksBeingChecked); response.setState(LockState.ACQUIRED); + return response; } finally { close(rs, stmt, null); if(handle != null) { handle.releaseLocks(); } } - return response; } + + private void acquireAndCommit(Connection dbConn, Statement stmt, + List locksBeingChecked) + throws SQLException, NoSuchLockException, MetaException { + //if here, there were no locks that blocked any locks in 'locksBeingChecked' - acquire them all + acquire(dbConn, stmt, locksBeingChecked); + + // We acquired all of the locks, so commit and return acquired. + LOG.debug("Going to commit"); + dbConn.commit(); + } + private void acquire(Connection dbConn, Statement stmt, List locksBeingChecked) throws SQLException, NoSuchLockException, MetaException { if(locksBeingChecked == null || locksBeingChecked.isEmpty()) {