blob: c537bb8e8ca82dd05bdd33542b9a1a76c25fa48e [file] [log] [blame]
/*
* 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.ignite.internal.processors.cache.transactions;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.GridKernalContextImpl;
import org.apache.ignite.internal.processors.cache.GridCacheMvccManager;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
import org.apache.ignite.internal.util.GridStringBuilder;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.transactions.TransactionMetrics;
import org.apache.ignite.transactions.TransactionState;
/**
* Tx metrics adapter.
*/
public class TransactionMetricsAdapter implements TransactionMetrics, Externalizable {
/** Grid kernal context. */
private final GridKernalContext gridKernalCtx;
/** */
private static final long serialVersionUID = 0L;
/** Number of transaction commits. */
private volatile int txCommits;
/** Number of transaction rollbacks. */
private volatile int txRollbacks;
/** Last commit time. */
private volatile long commitTime;
/** Last rollback time. */
private volatile long rollbackTime;
/**
* Create TransactionMetricsAdapter.
*/
public TransactionMetricsAdapter() {
this(null);
}
/**
* @param ctx Kernal context.
*/
public TransactionMetricsAdapter(GridKernalContext ctx) {
gridKernalCtx = ctx;
}
/** {@inheritDoc} */
@Override public long commitTime() {
return commitTime;
}
/** {@inheritDoc} */
@Override public long rollbackTime() {
return rollbackTime;
}
/** {@inheritDoc} */
@Override public int txCommits() {
return txCommits;
}
/** {@inheritDoc} */
@Override public int txRollbacks() {
return txRollbacks;
}
/** {@inheritDoc} */
@Override public Map<String, String> getAllOwnerTransactions() {
return getNearTxs(0);
}
/** {@inheritDoc} */
@Override public Map<String, String> getLongRunningOwnerTransactions(final int duration) {
return getNearTxs(duration);
}
/** {@inheritDoc} */
@Override public long getTransactionsCommittedNumber() {
return gridKernalCtx.cache().context().txMetrics().txCommits();
}
/** {@inheritDoc} */
@Override public long getTransactionsRolledBackNumber() {
return gridKernalCtx.cache().context().txMetrics().txRollbacks();
}
/** {@inheritDoc} */
@Override public long getTransactionsHoldingLockNumber() {
return txHoldingLockNum();
}
/** {@inheritDoc} */
@Override public long getLockedKeysNumber() {
return txLockedKeysNum();
}
/** {@inheritDoc} */
@Override public long getOwnerTransactionsNumber() {
return nearTxNum();
}
/**
* Transaction commit callback.
*/
public void onTxCommit() {
commitTime = U.currentTimeMillis();
txCommits++;
}
/**
* Transaction rollback callback.
*/
public void onTxRollback() {
rollbackTime = U.currentTimeMillis();
txRollbacks++;
}
/**
* Reset.
*/
public void reset() {
commitTime = 0;
txCommits = 0;
rollbackTime = 0;
txRollbacks = 0;
}
/**
* @param duration Duration.
*/
private Map<String, String> getNearTxs(long duration) {
final Collection<GridNearTxLocal> txs = nearTxs(duration);
final HashMap<String, String> res = new HashMap<>(txs.size());
for (GridNearTxLocal tx : txs)
res.put(tx.xid().toString(), composeTx(tx));
return res;
}
/**
* @param id Id.
*/
private String composeNodeInfo(final UUID id) {
final ClusterNode node = gridKernalCtx.discovery().node(id);
if (node == null)
return "";
return String.format("%s %s",
node.id(),
node.hostNames());
}
/**
* @param ids Ids.
*/
private String composeNodeInfo(final Set<UUID> ids) {
final GridStringBuilder sb = new GridStringBuilder();
sb.a("[");
String delim = "";
for (UUID id : ids) {
sb
.a(delim)
.a(composeNodeInfo(id));
delim = ", ";
}
sb.a("]");
return sb.toString();
}
/**
* @param tx Transaction.
*/
private String composeTx(final GridNearTxLocal tx) {
final TransactionState txState = tx.state();
String top = txState + ", NEAR, ";
if (txState == TransactionState.PREPARING) {
final Map<UUID, Collection<UUID>> transactionNodes = tx.transactionNodes();
if (!F.isEmpty(transactionNodes)) {
final Set<UUID> primaryNodes = transactionNodes.keySet();
if (!F.isEmpty(primaryNodes))
top += "PRIMARY: " + composeNodeInfo(primaryNodes) + ", ";
}
}
final Long duration = System.currentTimeMillis() - tx.startTime();
return top + "DURATION: " + duration;
}
/**
*
*/
private Collection<GridNearTxLocal> nearTxs(long duration) {
final long start = System.currentTimeMillis();
IgniteClosure<IgniteInternalTx, GridNearTxLocal> c = new IgniteClosure<IgniteInternalTx, GridNearTxLocal>() {
@Override public GridNearTxLocal apply(IgniteInternalTx tx) {
return ((GridNearTxLocal)tx);
}
};
IgnitePredicate<IgniteInternalTx> pred = new IgnitePredicate<IgniteInternalTx>() {
@Override public boolean apply(IgniteInternalTx tx) {
return tx.local() && tx.near() && start - tx.startTime() >= duration;
}
};
return F.viewReadOnly(gridKernalCtx.cache().context().tm().activeTransactions(), c, pred);
}
/**
*
*/
private long nearTxNum() {
IgnitePredicate<IgniteInternalTx> pred = new IgnitePredicate<IgniteInternalTx>() {
@Override public boolean apply(IgniteInternalTx tx) {
return tx.local() && tx.near();
}
};
return F.size(gridKernalCtx.cache().context().tm().activeTransactions(), pred);
}
/**
* Count total number of holding locks on local node.
*/
private long txHoldingLockNum() {
long holdingLockCounter = 0;
IgniteTxManager tm = gridKernalCtx.cache().context().tm();
for (IgniteInternalTx tx : tm.activeTransactions()) {
if ((tx.optimistic() && tx.state() == TransactionState.ACTIVE) || tx.empty() || !tx.local())
continue;
holdingLockCounter++;
}
return holdingLockCounter;
}
/**
* Count total number of locked keys on local node.
*/
private long txLockedKeysNum() {
GridCacheMvccManager mvccManager = gridKernalCtx.cache().context().mvcc();
return mvccManager.lockedKeys().size() + mvccManager.nearLockedKeys().size();
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeLong(commitTime);
out.writeLong(rollbackTime);
out.writeInt(txCommits);
out.writeInt(txRollbacks);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
commitTime = in.readLong();
rollbackTime = in.readLong();
txCommits = in.readInt();
txRollbacks = in.readInt();
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(TransactionMetricsAdapter.class, this);
}
}