/**
* 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.txn;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hive.common.classification.InterfaceAudience;
import org.apache.hadoop.hive.common.classification.InterfaceStability;
import org.apache.hadoop.hive.common.classification.RetrySemantics;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.api.*;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* A handler to answer transaction related calls that come into the metastore
* server.
*
* Note on log messages: Please include txnid:X and lockid info using
* {@link org.apache.hadoop.hive.common.JavaUtils#txnIdToString(long)}
* and {@link org.apache.hadoop.hive.common.JavaUtils#lockIdToString(long)} in all messages.
* The txnid:X and lockid:Y matches how Thrift object toString() methods are generated,
* so keeping the format consistent makes grep'ing the logs much easier.
*
* Note on HIVE_LOCKS.hl_last_heartbeat.
* For locks that are part of transaction, we set this 0 (would rather set it to NULL but
* Currently the DB schema has this NOT NULL) and only update/read heartbeat from corresponding
* transaction in TXNS.
*/
@InterfaceAudience.Private
@InterfaceStability.Evolving
public interface TxnStore {
enum MUTEX_KEY {Initiator, Cleaner, HouseKeeper, CompactionHistory, CheckLock,
WriteSetCleaner, CompactionScheduler}
// Compactor states (Should really be enum)
String INITIATED_RESPONSE = "initiated";
String WORKING_RESPONSE = "working";
String CLEANING_RESPONSE = "ready for cleaning";
String FAILED_RESPONSE = "failed";
String SUCCEEDED_RESPONSE = "succeeded";
String ATTEMPTED_RESPONSE = "attempted";
public static final int TIMED_OUT_TXN_ABORT_BATCH_SIZE = 50000;
public void setConf(HiveConf conf);
/**
* Get information about open transactions. This gives extensive information about the
* transactions rather than just the list of transactions. This should be used when the need
* is to see information about the transactions (e.g. show transactions).
* @return information about open transactions
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public GetOpenTxnsInfoResponse getOpenTxnsInfo() throws MetaException;
/**
* Get list of valid transactions. This gives just the list of transactions that are open.
* @return list of open transactions, as well as a high water mark.
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public GetOpenTxnsResponse getOpenTxns() throws MetaException;
/**
* Get the count for open transactions.
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public void countOpenTxns() throws MetaException;
/**
* Open a set of transactions
* @param rqst request to open transactions
* @return information on opened transactions
* @throws MetaException
*/
@RetrySemantics.Idempotent
public OpenTxnsResponse openTxns(OpenTxnRequest rqst) throws MetaException;
/**
* Abort (rollback) a transaction.
* @param rqst info on transaction to abort
* @throws NoSuchTxnException
* @throws MetaException
*/
@RetrySemantics.Idempotent
public void abortTxn(AbortTxnRequest rqst) throws NoSuchTxnException, MetaException, TxnAbortedException;
/**
* Abort (rollback) a list of transactions in one request.
* @param rqst info on transactions to abort
* @throws NoSuchTxnException
* @throws MetaException
*/
@RetrySemantics.Idempotent
public void abortTxns(AbortTxnsRequest rqst) throws NoSuchTxnException, MetaException;
/**
* Commit a transaction
* @param rqst info on transaction to commit
* @throws NoSuchTxnException
* @throws TxnAbortedException
* @throws MetaException
*/
@RetrySemantics.Idempotent
public void commitTxn(CommitTxnRequest rqst)
throws NoSuchTxnException, TxnAbortedException, MetaException;
/**
* Obtain a lock.
* @param rqst information on the lock to obtain. If the requester is part of a transaction
* the txn information must be included in the lock request.
* @return info on the lock, including whether it was obtained.
* @throws NoSuchTxnException
* @throws TxnAbortedException
* @throws MetaException
*/
@RetrySemantics.CannotRetry
public LockResponse lock(LockRequest rqst)
throws NoSuchTxnException, TxnAbortedException, MetaException;
/**
* Check whether a lock has been obtained. This is used after {@link #lock} returned a wait
* state.
* @param rqst info on the lock to check
* @return info on the state of the lock
* @throws NoSuchTxnException
* @throws NoSuchLockException
* @throws TxnAbortedException
* @throws MetaException
*/
@RetrySemantics.SafeToRetry
public LockResponse checkLock(CheckLockRequest rqst)
throws NoSuchTxnException, NoSuchLockException, TxnAbortedException, MetaException;
/**
* Unlock a lock. It is not legal to call this if the caller is part of a txn. In that case
* the txn should be committed or aborted instead. (Note someday this will change since
* multi-statement transactions will allow unlocking in the transaction.)
* @param rqst lock to unlock
* @throws NoSuchLockException
* @throws TxnOpenException
* @throws MetaException
*/
@RetrySemantics.Idempotent
public void unlock(UnlockRequest rqst)
throws NoSuchLockException, TxnOpenException, MetaException;
/**
* Get information on current locks.
* @param rqst lock information to retrieve
* @return lock information.
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public ShowLocksResponse showLocks(ShowLocksRequest rqst) throws MetaException;
/**
* Send a heartbeat for a lock or a transaction
* @param ids lock and/or txn id to heartbeat
* @throws NoSuchTxnException
* @throws NoSuchLockException
* @throws TxnAbortedException
* @throws MetaException
*/
@RetrySemantics.SafeToRetry
public void heartbeat(HeartbeatRequest ids)
throws NoSuchTxnException, NoSuchLockException, TxnAbortedException, MetaException;
/**
* Heartbeat a group of transactions together
* @param rqst set of transactions to heartbat
* @return info on txns that were heartbeated
* @throws MetaException
*/
@RetrySemantics.SafeToRetry
public HeartbeatTxnRangeResponse heartbeatTxnRange(HeartbeatTxnRangeRequest rqst)
throws MetaException;
/**
* Submit a compaction request into the queue. This is called when a user manually requests a
* compaction.
* @param rqst information on what to compact
* @return id of the compaction that has been started or existing id if this resource is already scheduled
* @throws MetaException
*/
@RetrySemantics.Idempotent
public CompactionResponse compact(CompactionRequest rqst) throws MetaException;
/**
* Show list of current compactions
* @param rqst info on which compactions to show
* @return compaction information
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public ShowCompactResponse showCompact(ShowCompactRequest rqst) throws MetaException;
/**
* Add information on a set of dynamic partitions that participated in a transaction.
* @param rqst dynamic partition info.
* @throws NoSuchTxnException
* @throws TxnAbortedException
* @throws MetaException
*/
@RetrySemantics.SafeToRetry
public void addDynamicPartitions(AddDynamicPartitions rqst)
throws NoSuchTxnException, TxnAbortedException, MetaException;
/**
* Clean up corresponding records in metastore tables
* @param type Hive object type
* @param db database object
* @param table table object
* @param partitionIterator partition iterator
* @throws MetaException
*/
@RetrySemantics.Idempotent
public void cleanupRecords(HiveObjectType type, Database db, Table table,
Iterator<Partition> partitionIterator) throws MetaException;
/**
* Timeout transactions and/or locks. This should only be called by the compactor.
*/
@RetrySemantics.Idempotent
public void performTimeOuts();
/**
* This will look through the completed_txn_components table and look for partitions or tables
* that may be ready for compaction. Also, look through txns and txn_components tables for
* aborted transactions that we should add to the list.
* @param maxAborted Maximum number of aborted queries to allow before marking this as a
* potential compaction.
* @return list of CompactionInfo structs. These will not have id, type,
* or runAs set since these are only potential compactions not actual ones.
*/
@RetrySemantics.ReadOnly
public Set<CompactionInfo> findPotentialCompactions(int maxAborted) throws MetaException;
/**
* Sets the user to run as. This is for the case
* where the request was generated by the user and so the worker must set this value later.
* @param cq_id id of this entry in the queue
* @param user user to run the jobs as
*/
@RetrySemantics.Idempotent
public void setRunAs(long cq_id, String user) throws MetaException;
/**
* This will grab the next compaction request off of
* the queue, and assign it to the worker.
* @param workerId id of the worker calling this, will be recorded in the db
* @return an info element for this compaction request, or null if there is no work to do now.
*/
@RetrySemantics.ReadOnly
public CompactionInfo findNextToCompact(String workerId) throws MetaException;
/**
* This will mark an entry in the queue as compacted
* and put it in the ready to clean state.
* @param info info on the compaction entry to mark as compacted.
*/
@RetrySemantics.SafeToRetry
public void markCompacted(CompactionInfo info) throws MetaException;
/**
* Find entries in the queue that are ready to
* be cleaned.
* @return information on the entry in the queue.
*/
@RetrySemantics.ReadOnly
public List<CompactionInfo> findReadyToClean() throws MetaException;
/**
* This will remove an entry from the queue after
* it has been compacted.
*
* @param info info on the compaction entry to remove
*/
@RetrySemantics.CannotRetry
public void markCleaned(CompactionInfo info) throws MetaException;
/**
* Mark a compaction entry as failed. This will move it to the compaction history queue with a
* failed status. It will NOT clean up aborted transactions in the table/partition associated
* with this compaction.
* @param info information on the compaction that failed.
* @throws MetaException
*/
@RetrySemantics.CannotRetry
public void markFailed(CompactionInfo info) throws MetaException;
/**
* Clean up aborted transactions from txns that have no components in txn_components. The reson such
* txns exist can be that now work was done in this txn (e.g. Streaming opened TransactionBatch and
* abandoned it w/o doing any work) or due to {@link #markCleaned(CompactionInfo)} being called.
*/
@RetrySemantics.SafeToRetry
public void cleanEmptyAbortedTxns() throws MetaException;
/**
* This will take all entries assigned to workers
* on a host return them to INITIATED state. The initiator should use this at start up to
* clean entries from any workers that were in the middle of compacting when the metastore
* shutdown. It does not reset entries from worker threads on other hosts as those may still
* be working.
* @param hostname Name of this host. It is assumed this prefixes the thread's worker id,
* so that like hostname% will match the worker id.
*/
@RetrySemantics.Idempotent
public void revokeFromLocalWorkers(String hostname) throws MetaException;
/**
* This call will return all compaction queue
* entries assigned to a worker but over the timeout back to the initiated state.
* This should be called by the initiator on start up and occasionally when running to clean up
* after dead threads. At start up {@link #revokeFromLocalWorkers(String)} should be called
* first.
* @param timeout number of milliseconds since start time that should elapse before a worker is
* declared dead.
*/
@RetrySemantics.Idempotent
public void revokeTimedoutWorkers(long timeout) throws MetaException;
/**
* Queries metastore DB directly to find columns in the table which have statistics information.
* If {@code ci} includes partition info then per partition stats info is examined, otherwise
* table level stats are examined.
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public List<String> findColumnsWithStats(CompactionInfo ci) throws MetaException;
/**
* Record the highest txn id that the {@code ci} compaction job will pay attention to.
*/
@RetrySemantics.Idempotent
public void setCompactionHighestTxnId(CompactionInfo ci, long highestTxnId) throws MetaException;
/**
* For any given compactable entity (partition, table if not partitioned) the history of compactions
* may look like "sssfffaaasffss", for example. The idea is to retain the tail (most recent) of the
* history such that a configurable number of each type of state is present. Any other entries
* can be purged. This scheme has advantage of always retaining the last failure/success even if
* it's not recent.
* @throws MetaException
*/
@RetrySemantics.SafeToRetry
public void purgeCompactionHistory() throws MetaException;
/**
* WriteSet tracking is used to ensure proper transaction isolation. This method deletes the
* transaction metadata once it becomes unnecessary.
*/
@RetrySemantics.SafeToRetry
public void performWriteSetGC();
/**
* Determine if there are enough consecutive failures compacting a table or partition that no
* new automatic compactions should be scheduled. User initiated compactions do not do this
* check.
* @param ci Table or partition to check.
* @return true if it is ok to compact, false if there have been too many failures.
* @throws MetaException
*/
@RetrySemantics.ReadOnly
public boolean checkFailedCompactions(CompactionInfo ci) throws MetaException;
@VisibleForTesting
public int numLocksInLockTable() throws SQLException, MetaException;
@VisibleForTesting
long setTimeout(long milliseconds);
@RetrySemantics.Idempotent
public MutexAPI getMutexAPI();
/**
* This is primarily designed to provide coarse grained mutex support to operations running
* inside the Metastore (of which there could be several instances). The initial goal is to
* ensure that various sub-processes of the Compactor don't step on each other.
*
* In RDMBS world each {@code LockHandle} uses a java.sql.Connection so use it sparingly.
*/
public static interface MutexAPI {
/**
* The {@code key} is name of the lock. Will acquire and exclusive lock or block. It retuns
* a handle which must be used to release the lock. Each invocation returns a new handle.
*/
public LockHandle acquireLock(String key) throws MetaException;
/**
* Same as {@link #acquireLock(String)} but takes an already existing handle as input. This
* will associate the lock on {@code key} with the same handle. All locks associated with
* the same handle will be released together.
* @param handle not NULL
*/
public void acquireLock(String key, LockHandle handle) throws MetaException;
public static interface LockHandle {
/**
* Releases all locks associated with this handle.
*/
public void releaseLocks();
}
}
/**
* Once a {@link java.util.concurrent.ThreadPoolExecutor.Worker} submits a job to the cluster,
* it calls this to update the metadata.
* @param id {@link CompactionInfo#id}
*/
@RetrySemantics.Idempotent
public void setHadoopJobId(String hadoopJobId, long id);
}