Search in sources :

Example 1 with PartitionUpdateCountersMessage

use of org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage in project ignite by apache.

the class IgniteTxLocalAdapter method calculatePartitionUpdateCounters.

/**
 * Calculates partition update counters for current transaction. Each partition will be supplied with
 * pair (init, delta) values, where init - initial update counter, and delta - updates count made
 * by current transaction for a given partition.
 */
public void calculatePartitionUpdateCounters() throws IgniteTxRollbackCheckedException {
    TxCounters counters = txCounters(false);
    if (counters != null && F.isEmpty(counters.updateCounters())) {
        List<PartitionUpdateCountersMessage> cntrMsgs = new ArrayList<>();
        for (Map.Entry<Integer, Map<Integer, AtomicLong>> record : counters.accumulatedUpdateCounters().entrySet()) {
            int cacheId = record.getKey();
            Map<Integer, AtomicLong> partToCntrs = record.getValue();
            assert partToCntrs != null;
            if (F.isEmpty(partToCntrs))
                continue;
            PartitionUpdateCountersMessage msg = new PartitionUpdateCountersMessage(cacheId, partToCntrs.size());
            GridCacheContext ctx0 = cctx.cacheContext(cacheId);
            GridDhtPartitionTopology top = ctx0.topology();
            assert top != null;
            for (Map.Entry<Integer, AtomicLong> e : partToCntrs.entrySet()) {
                AtomicLong acc = e.getValue();
                assert acc != null;
                long cntr = acc.get();
                assert cntr >= 0;
                if (cntr != 0) {
                    int p = e.getKey();
                    GridDhtLocalPartition part = top.localPartition(p);
                    // Verify primary tx mapping.
                    // LOST state is possible if tx is started over LOST partition.
                    boolean valid = part != null && (part.state() == OWNING || part.state() == LOST) && part.primary(top.readyTopologyVersion());
                    if (!valid) {
                        // Local node is no longer primary for the partition, need to rollback a transaction.
                        if (part != null && !part.primary(top.readyTopologyVersion())) {
                            log.warning("Failed to prepare a transaction on outdated topology, rolling back " + "[tx=" + CU.txString(this) + ", readyTopVer=" + top.readyTopologyVersion() + ", lostParts=" + top.lostPartitions() + ", part=" + part.toString() + ']');
                            throw new IgniteTxRollbackCheckedException("Failed to prepare a transaction on outdated " + "topology, please try again [timeout=" + timeout() + ", tx=" + CU.txString(this) + ']');
                        }
                        // Trigger error.
                        throw new AssertionError("Invalid primary mapping [tx=" + CU.txString(this) + ", readyTopVer=" + top.readyTopologyVersion() + ", lostParts=" + top.lostPartitions() + ", part=" + (part == null ? "NULL" : part.toString()) + ']');
                    }
                    msg.add(p, part.getAndIncrementUpdateCounter(cntr), cntr);
                }
            }
            if (msg.size() > 0)
                cntrMsgs.add(msg);
        }
        counters.updateCounters(cntrMsgs);
    }
}
Also used : GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) GridDhtPartitionTopology(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology) ArrayList(java.util.ArrayList) IgniteTxRollbackCheckedException(org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException) AtomicLong(java.util.concurrent.atomic.AtomicLong) PartitionUpdateCountersMessage(org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage) GridDhtLocalPartition(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition) Map(java.util.Map)

Example 2 with PartitionUpdateCountersMessage

use of org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage in project ignite by apache.

the class IgniteTxHandler method filterUpdateCountersForBackupNode.

/**
 * @param tx Transaction.
 * @param node Backup node.
 * @return Partition counters for the given backup node.
 */
@Nullable
public List<PartitionUpdateCountersMessage> filterUpdateCountersForBackupNode(IgniteInternalTx tx, ClusterNode node) {
    TxCounters txCntrs = tx.txCounters(false);
    Collection<PartitionUpdateCountersMessage> updCntrs;
    if (txCntrs == null || F.isEmpty(updCntrs = txCntrs.updateCounters()))
        return null;
    List<PartitionUpdateCountersMessage> res = new ArrayList<>(updCntrs.size());
    AffinityTopologyVersion top = tx.topologyVersionSnapshot();
    for (PartitionUpdateCountersMessage partCntrs : updCntrs) {
        GridDhtPartitionTopology topology = ctx.cacheContext(partCntrs.cacheId()).topology();
        PartitionUpdateCountersMessage resCntrs = new PartitionUpdateCountersMessage(partCntrs.cacheId(), partCntrs.size());
        for (int i = 0; i < partCntrs.size(); i++) {
            int part = partCntrs.partition(i);
            if (topology.nodes(part, top).indexOf(node) > 0)
                resCntrs.add(part, partCntrs.initialCounter(i), partCntrs.updatesCount(i));
        }
        if (resCntrs.size() > 0)
            res.add(resCntrs);
    }
    return res;
}
Also used : AffinityTopologyVersion(org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion) GridDhtPartitionTopology(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology) PartitionUpdateCountersMessage(org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage) ArrayList(java.util.ArrayList) Nullable(org.jetbrains.annotations.Nullable)

Example 3 with PartitionUpdateCountersMessage

use of org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage in project ignite by apache.

the class IgniteTxHandler method applyPartitionsUpdatesCounters.

/**
 * Applies partition counter updates for transactions.
 * <p>
 * Called after entries are written to WAL on commit or during rollback to close gaps in update counter sequence.
 * <p>
 * On rollback counters should be applied on the primary only after backup nodes, otherwise if the primary fail
 * before sending rollback requests to backups remote transactions can be committed by recovery protocol and
 * partition consistency will not be restored when primary returns to the grid because RollbackRecord was written
 * (actual for persistent mode only).
 *
 * @param counters Counter values to be updated.
 * @param rollback {@code True} if applied during rollbacks.
 * @param rollbackOnPrimary {@code True} if rollback happens on primary node. Passed to CQ engine.
 */
public void applyPartitionsUpdatesCounters(Iterable<PartitionUpdateCountersMessage> counters, boolean rollback, boolean rollbackOnPrimary) throws IgniteCheckedException {
    if (counters == null)
        return;
    WALPointer ptr = null;
    try {
        for (PartitionUpdateCountersMessage counter : counters) {
            GridCacheContext ctx0 = ctx.cacheContext(counter.cacheId());
            GridDhtPartitionTopology top = ctx0.topology();
            AffinityTopologyVersion topVer = top.readyTopologyVersion();
            assert top != null;
            for (int i = 0; i < counter.size(); i++) {
                boolean invalid = false;
                try {
                    GridDhtLocalPartition part = top.localPartition(counter.partition(i));
                    if (part != null && part.reserve()) {
                        try {
                            if (part.state() != RENTING) {
                                // Check is actual only for backup node.
                                long start = counter.initialCounter(i);
                                long delta = counter.updatesCount(i);
                                boolean updated = part.updateCounter(start, delta);
                                // Need to log rolled back range for logical recovery.
                                if (updated && rollback) {
                                    CacheGroupContext grpCtx = part.group();
                                    if (grpCtx.persistenceEnabled() && grpCtx.walEnabled() && !grpCtx.mvccEnabled()) {
                                        RollbackRecord rec = new RollbackRecord(grpCtx.groupId(), part.id(), start, delta);
                                        ptr = ctx.wal().log(rec);
                                    }
                                    for (int cntr = 1; cntr <= delta; cntr++) {
                                        ctx0.continuousQueries().skipUpdateCounter(null, part.id(), start + cntr, topVer, rollbackOnPrimary);
                                    }
                                }
                            } else
                                invalid = true;
                        } finally {
                            part.release();
                        }
                    } else
                        invalid = true;
                } catch (GridDhtInvalidPartitionException e) {
                    invalid = true;
                }
                if (log.isDebugEnabled() && invalid) {
                    log.debug("Received partition update counters message for invalid partition, ignoring: " + "[cacheId=" + counter.cacheId() + ", part=" + counter.partition(i) + ']');
                }
            }
        }
    } finally {
        if (ptr != null)
            ctx.wal().flush(ptr, false);
    }
}
Also used : GridDhtInvalidPartitionException(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException) GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) GridDhtPartitionTopology(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology) AffinityTopologyVersion(org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion) PartitionUpdateCountersMessage(org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage) RollbackRecord(org.apache.ignite.internal.pagemem.wal.record.RollbackRecord) GridDhtLocalPartition(org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition) CacheGroupContext(org.apache.ignite.internal.processors.cache.CacheGroupContext) WALPointer(org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer)

Example 4 with PartitionUpdateCountersMessage

use of org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage in project ignite by apache.

the class MvccCachingManager method onTxFinished.

/**
 * @param tx Transaction.
 * @param commit {@code True} if commit.
 */
public void onTxFinished(IgniteInternalTx tx, boolean commit) throws IgniteCheckedException {
    if (log.isDebugEnabled())
        log.debug("Transaction finished: [commit=" + commit + ", tx=" + tx + ']');
    if (tx.system() || tx.internal() || tx.mvccSnapshot() == null)
        return;
    cntrs.remove(new TxKey(tx.mvccSnapshot().coordinatorVersion(), tx.mvccSnapshot().counter()));
    EnlistBuffer buf = enlistCache.remove(tx.xidVersion());
    Map<Integer, Map<KeyCacheObject, MvccTxEntry>> allCached = buf == null ? null : buf.getCached();
    TxCounters txCntrs = tx.txCounters(false);
    Collection<PartitionUpdateCountersMessage> cntrsColl = txCntrs == null ? null : txCntrs.updateCounters();
    if (txCntrs == null || F.isEmpty(cntrsColl))
        return;
    GridIntList cacheIds = tx.txState().cacheIds();
    assert cacheIds != null;
    for (int i = 0; i < cacheIds.size(); i++) {
        int cacheId = cacheIds.get(i);
        GridCacheContext ctx0 = cctx.cacheContext(cacheId);
        assert ctx0 != null;
        ctx0.group().listenerLock().readLock().lock();
        try {
            boolean hasListeners = ctx0.hasContinuousQueryListeners(tx);
            boolean drEnabled = ctx0.isDrEnabled();
            if (!hasListeners && !drEnabled)
                // There are no listeners to notify.
                continue;
            // Get cached entries for the given cache.
            Map<KeyCacheObject, MvccTxEntry> cached = allCached == null ? null : allCached.get(cacheId);
            Map<Integer, Map<Integer, T2<AtomicLong, Long>>> cntrsMap = countersPerPartition(cntrsColl);
            Map<Integer, T2<AtomicLong, Long>> cntrPerCache = cntrsMap.get(cacheId);
            if (F.isEmpty(cntrPerCache))
                // No updates were made for this cache.
                continue;
            boolean fakeEntries = false;
            if (F.isEmpty(cached)) {
                if (log.isDebugEnabled())
                    log.debug("Transaction updates were not cached fully (this can happen when listener started" + " during the transaction execution). [tx=" + tx + ']');
                if (hasListeners) {
                    // Create fake update entries if we have CQ listeners.
                    cached = createFakeCachedEntries(cntrPerCache, tx, cacheId);
                    fakeEntries = true;
                } else
                    // Nothing to do further if tx is not cached entirely and there are no any CQ listeners.
                    continue;
            }
            if (F.isEmpty(cached))
                continue;
            // Feed CQ & DR with entries.
            for (Map.Entry<KeyCacheObject, MvccTxEntry> entry : cached.entrySet()) {
                MvccTxEntry e = entry.getValue();
                assert e.key().partition() != -1;
                assert cntrPerCache != null;
                assert e.cacheId() == cacheId;
                T2<AtomicLong, Long> cntr = cntrPerCache.get(e.key().partition());
                long resCntr = cntr.getKey().incrementAndGet();
                assert resCntr <= cntr.getValue();
                e.updateCounter(resCntr);
                if (ctx0.group().sharedGroup()) {
                    ctx0.group().onPartitionCounterUpdate(cacheId, e.key().partition(), resCntr, tx.topologyVersion(), tx.local());
                }
                if (log.isDebugEnabled())
                    log.debug("Process cached entry:" + e);
                // DR
                if (ctx0.isDrEnabled() && !fakeEntries) {
                    ctx0.dr().replicate(e.key(), e.value(), e.ttl(), e.expireTime(), e.version(), tx.local() ? DR_PRIMARY : DR_BACKUP, e.topologyVersion());
                }
                // CQ
                CacheContinuousQueryManager contQryMgr = ctx0.continuousQueries();
                if (ctx0.continuousQueries().notifyContinuousQueries(tx)) {
                    Map<UUID, CacheContinuousQueryListener> lsnrCol = continuousQueryListeners(ctx0, tx);
                    if (!F.isEmpty(lsnrCol)) {
                        contQryMgr.onEntryUpdated(lsnrCol, e.key(), // Force skip update counter if rolled back.
                        commit ? e.value() : null, // Force skip update counter if rolled back.
                        commit ? e.oldValue() : null, false, e.key().partition(), tx.local(), false, e.updateCounter(), null, e.topologyVersion());
                    }
                }
            }
        } finally {
            ctx0.group().listenerLock().readLock().unlock();
        }
    }
}
Also used : TxKey(org.apache.ignite.internal.processors.cache.mvcc.txlog.TxKey) CacheContinuousQueryManager(org.apache.ignite.internal.processors.cache.query.continuous.CacheContinuousQueryManager) CacheContinuousQueryListener(org.apache.ignite.internal.processors.cache.query.continuous.CacheContinuousQueryListener) PartitionUpdateCountersMessage(org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage) UUID(java.util.UUID) T2(org.apache.ignite.internal.util.typedef.T2) KeyCacheObject(org.apache.ignite.internal.processors.cache.KeyCacheObject) TxCounters(org.apache.ignite.internal.processors.cache.transactions.TxCounters) GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) GridIntList(org.apache.ignite.internal.util.GridIntList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicLong(java.util.concurrent.atomic.AtomicLong) AtomicLong(java.util.concurrent.atomic.AtomicLong) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 5 with PartitionUpdateCountersMessage

use of org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage in project ignite by apache.

the class MvccCachingManager method countersPerPartition.

/**
 * Calculates counters updates per cache and partition: cacheId -> partId -> initCntr -> cntr + delta.
 *
 * @param cntrsColl Counters collection.
 * @return Counters updates per cache and partition.
 */
private Map<Integer, Map<Integer, T2<AtomicLong, Long>>> countersPerPartition(Collection<PartitionUpdateCountersMessage> cntrsColl) {
    // 
    Map<Integer, Map<Integer, T2<AtomicLong, Long>>> cntrsMap = new HashMap<>();
    for (PartitionUpdateCountersMessage msg : cntrsColl) {
        for (int i = 0; i < msg.size(); i++) {
            Map<Integer, T2<AtomicLong, Long>> cntrPerPart = cntrsMap.computeIfAbsent(msg.cacheId(), k -> new HashMap<>());
            T2 prev = cntrPerPart.put(msg.partition(i), new T2<>(new AtomicLong(msg.initialCounter(i)), msg.initialCounter(i) + msg.updatesCount(i)));
            assert prev == null;
        }
    }
    return cntrsMap;
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicLong(java.util.concurrent.atomic.AtomicLong) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) PartitionUpdateCountersMessage(org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage) AtomicLong(java.util.concurrent.atomic.AtomicLong) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap) T2(org.apache.ignite.internal.util.typedef.T2)

Aggregations

PartitionUpdateCountersMessage (org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage)5 Map (java.util.Map)3 AtomicLong (java.util.concurrent.atomic.AtomicLong)3 GridCacheContext (org.apache.ignite.internal.processors.cache.GridCacheContext)3 GridDhtPartitionTopology (org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 SortedMap (java.util.SortedMap)2 TreeMap (java.util.TreeMap)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 AffinityTopologyVersion (org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion)2 GridDhtLocalPartition (org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition)2 T2 (org.apache.ignite.internal.util.typedef.T2)2 UUID (java.util.UUID)1 RollbackRecord (org.apache.ignite.internal.pagemem.wal.record.RollbackRecord)1 CacheGroupContext (org.apache.ignite.internal.processors.cache.CacheGroupContext)1 KeyCacheObject (org.apache.ignite.internal.processors.cache.KeyCacheObject)1 GridDhtInvalidPartitionException (org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtInvalidPartitionException)1