/** * @param delay time to delay for first heartbeat */ @VisibleForTesting void acquireLocksWithHeartbeatDelay(QueryPlan plan, Context ctx, String username, long delay) throws LockException { LockState ls = acquireLocks(plan, ctx, username, true); if (ls != null && !isTxnOpen()) { // If there's no lock, we don't need to do heartbeat // Start heartbeat for read-only queries which don't open transactions but requires locks. // For those that require transactions, the heartbeat has already been started in openTxn. ctx.setHeartbeater(startHeartbeat(delay)); } }
/** * Start the heartbeater threadpool and return the task. * @param initialDelay time to delay before first execution, in milliseconds * @return heartbeater */ private Heartbeater startHeartbeat(long initialDelay) throws LockException { long heartbeatInterval = getHeartbeatInterval(conf); assert heartbeatInterval > 0; UserGroupInformation currentUser; try { currentUser = UserGroupInformation.getCurrentUser(); } catch (IOException e) { throw new LockException("error while getting current user,", e); } Heartbeater heartbeater = new Heartbeater(this, conf, queryId, currentUser); heartbeatTask = startHeartbeat(initialDelay, heartbeatInterval, heartbeater); LOG.debug("Started heartbeat with delay/interval = " + initialDelay + "/" + heartbeatInterval + " " + TimeUnit.MILLISECONDS + " for query: " + queryId); return heartbeater; }
/** * @param delay time to delay for first heartbeat */ @VisibleForTesting void acquireLocksWithHeartbeatDelay(QueryPlan plan, Context ctx, String username, long delay) throws LockException { LockState ls = acquireLocks(plan, ctx, username, true); if (ls != null && !isTxnOpen()) { // If there's no lock, we don't need to do heartbeat // Start heartbeat for read-only queries which don't open transactions but requires locks. // For those that require transactions, the heartbeat has already been started in openTxn. ctx.setHeartbeater(startHeartbeat(delay)); } }
@Override public LockResponse acquireMaterializationRebuildLock(String dbName, String tableName, long txnId) throws LockException { // Acquire lock LockResponse lockResponse; try { lockResponse = getMS().lockMaterializationRebuild(dbName, tableName, txnId); } catch (TException e) { throw new LockException(ErrorMsg.METASTORE_COMMUNICATION_FAILED.getMsg(), e); } if (lockResponse.getState() == LockState.ACQUIRED) { // If lock response is ACQUIRED, we can create the heartbeater long initialDelay = 0L; long heartbeatInterval = getHeartbeatInterval(conf); assert heartbeatInterval > 0; MaterializationRebuildLockHeartbeater heartbeater = new MaterializationRebuildLockHeartbeater( this, dbName, tableName, queryId, txnId); ScheduledFuture<?> task = startHeartbeat(initialDelay, heartbeatInterval, heartbeater); heartbeater.task.set(task); LOG.debug("Started heartbeat for materialization rebuild lock for {} with delay/interval = {}/{} {} for query: {}", AcidUtils.getFullTableName(dbName, tableName), initialDelay, heartbeatInterval, TimeUnit.MILLISECONDS, queryId); } return lockResponse; }
@VisibleForTesting long openTxn(Context ctx, String user, long delay) throws LockException { /*Q: why don't we lock the snapshot here??? Instead of having client make an explicit call whenever it chooses A: If we want to rely on locks for transaction scheduling we must get the snapshot after lock acquisition. Relying on locks is a pessimistic strategy which works better under high contention.*/ init(); getLockManager(); if(isTxnOpen()) { throw new LockException("Transaction already opened. " + JavaUtils.txnIdToString(txnId)); } try { txnId = getMS().openTxn(user); stmtId = 0; numStatements = 0; tableWriteIds.clear(); isExplicitTransaction = false; startTransactionCount = 0; LOG.info("Opened " + JavaUtils.txnIdToString(txnId)); ctx.setHeartbeater(startHeartbeat(delay)); return txnId; } catch (TException e) { throw new LockException(e, ErrorMsg.METASTORE_COMMUNICATION_FAILED); } }
@VisibleForTesting long openTxn(Context ctx, String user, long delay) throws LockException { //todo: why don't we lock the snapshot here??? Instead of having client make an explicit call //whenever it chooses init(); if(isTxnOpen()) { throw new LockException("Transaction already opened. " + JavaUtils.txnIdToString(txnId)); } try { txnId = getMS().openTxn(user); statementId = 0; LOG.debug("Opened " + JavaUtils.txnIdToString(txnId)); ctx.setHeartbeater(startHeartbeat(delay)); return txnId; } catch (TException e) { throw new LockException(e, ErrorMsg.METASTORE_COMMUNICATION_FAILED); } }