/* * 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.distributed.near; import java.io.Externalizable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.Map; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxRemoteAdapter; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxRemoteStateImpl; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.GridLeanMap; import org.apache.ignite.internal.util.tostring.GridToStringBuilder; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.transactions.TransactionConcurrency; import org.apache.ignite.transactions.TransactionIsolation; import org.jetbrains.annotations.Nullable; /** * Transaction created by system implicitly on remote nodes. */ public class GridNearTxRemote extends GridDistributedTxRemoteAdapter { /** */ private static final long serialVersionUID = 0L; /** Evicted keys. */ private Collection<IgniteTxKey> evicted = new LinkedList<>(); /** Near node ID. */ private UUID nearNodeId; /** Near transaction ID. */ private GridCacheVersion nearXidVer; /** Owned versions. */ private Map<IgniteTxKey, GridCacheVersion> owned; /** * Empty constructor required for {@link Externalizable}. */ public GridNearTxRemote() { // No-op. } /** * This constructor is meant for optimistic transactions. * * @param topVer Transaction topology version. * @param ldr Class loader. * @param nodeId Node ID. * @param nearNodeId Near node ID. * @param xidVer XID version. * @param commitVer Commit version. * @param sys System flag. * @param plc IO policy. * @param concurrency Concurrency level (should be pessimistic). * @param isolation Transaction isolation. * @param invalidate Invalidate flag. * @param timeout Timeout. * @param writeEntries Write entries. * @param ctx Cache registry. * @param txSize Expected transaction size. * @param subjId Subject ID. * @param taskNameHash Task name hash code. * @throws IgniteCheckedException If unmarshalling failed. */ public GridNearTxRemote( GridCacheSharedContext ctx, AffinityTopologyVersion topVer, ClassLoader ldr, UUID nodeId, UUID nearNodeId, GridCacheVersion xidVer, GridCacheVersion commitVer, boolean sys, byte plc, TransactionConcurrency concurrency, TransactionIsolation isolation, boolean invalidate, long timeout, Collection<IgniteTxEntry> writeEntries, int txSize, @Nullable UUID subjId, int taskNameHash ) throws IgniteCheckedException { super( ctx, nodeId, xidVer, commitVer, sys, plc, concurrency, isolation, invalidate, timeout, txSize, subjId, taskNameHash ); assert nearNodeId != null; this.nearNodeId = nearNodeId; int writeSize = writeEntries != null ? Math.max(txSize, writeEntries.size()) : txSize; txState = new IgniteTxRemoteStateImpl(Collections.<IgniteTxKey, IgniteTxEntry>emptyMap(), U.<IgniteTxKey, IgniteTxEntry>newLinkedHashMap(writeSize)); if (writeEntries != null) { for (IgniteTxEntry entry : writeEntries) { entry.unmarshal(ctx, true, ldr); addEntry(entry); } } assert topVer != null && topVer.topologyVersion() > 0 : topVer; topologyVersion(topVer); } /** * This constructor is meant for pessimistic transactions. * * @param topVer Transaction topology version. * @param nodeId Node ID. * @param nearNodeId Near node ID. * @param nearXidVer Near transaction ID. * @param xidVer XID version. * @param commitVer Commit version. * @param sys System flag. * @param plc IO policy. * @param concurrency Concurrency level (should be pessimistic). * @param isolation Transaction isolation. * @param invalidate Invalidate flag. * @param timeout Timeout. * @param ctx Cache registry. * @param txSize Expected transaction size. * @param subjId Subject ID. * @param taskNameHash Task name hash code. */ public GridNearTxRemote( GridCacheSharedContext ctx, AffinityTopologyVersion topVer, UUID nodeId, UUID nearNodeId, GridCacheVersion nearXidVer, GridCacheVersion xidVer, GridCacheVersion commitVer, boolean sys, byte plc, TransactionConcurrency concurrency, TransactionIsolation isolation, boolean invalidate, long timeout, int txSize, @Nullable UUID subjId, int taskNameHash ) { super( ctx, nodeId, xidVer, commitVer, sys, plc, concurrency, isolation, invalidate, timeout, txSize, subjId, taskNameHash ); assert nearNodeId != null; this.nearXidVer = nearXidVer; this.nearNodeId = nearNodeId; txState = new IgniteTxRemoteStateImpl(U.<IgniteTxKey, IgniteTxEntry>newLinkedHashMap(1), U.<IgniteTxKey, IgniteTxEntry>newLinkedHashMap(txSize)); assert topVer != null && topVer.topologyVersion() > 0 : topVer; topologyVersion(topVer); } /** {@inheritDoc} */ @Override public boolean near() { return true; } /** {@inheritDoc} */ @Override public UUID eventNodeId() { return nearNodeId; } /** {@inheritDoc} */ @Override public GridCacheVersion ownedVersion(IgniteTxKey key) { return owned == null ? null : owned.get(key); } /** * @return Near transaction ID. */ @Override public GridCacheVersion nearXidVersion() { return nearXidVer; } /** * @param cntrs Partition indexes. */ @Override public void setPartitionUpdateCounters(long[] cntrs) { // No-op. } /** * Adds owned versions to map. * * @param vers Map of owned versions. */ public void ownedVersions(Map<IgniteTxKey, GridCacheVersion> vers) { if (F.isEmpty(vers)) return; if (owned == null) owned = new GridLeanMap<>(vers.size()); owned.putAll(vers); } /** * @return Near node ID. */ public UUID nearNodeId() { return nearNodeId; } /** {@inheritDoc} */ @Override public Collection<UUID> masterNodeIds() { Collection<UUID> res = new ArrayList<>(2); res.add(nodeId); res.add(nearNodeId); return res; } /** * @return Evicted keys. */ public Collection<IgniteTxKey> evicted() { return evicted; } /** * Adds evicted key bytes to evicted collection. * * @param key Evicted key. */ void addEvicted(IgniteTxKey key) { evicted.add(key); } /** * Adds entries to started near remote tx. * * @param ldr Class loader. * @param entries Entries to add. * @throws IgniteCheckedException If failed. */ public void addEntries(ClassLoader ldr, Iterable<IgniteTxEntry> entries) throws IgniteCheckedException { for (IgniteTxEntry entry : entries) { entry.unmarshal(cctx, true, ldr); addEntry(entry); } } /** * @param entry Entry to enlist. * @throws IgniteCheckedException If failed. * @return {@code True} if entry was enlisted. */ private boolean addEntry(IgniteTxEntry entry) throws IgniteCheckedException { checkInternal(entry.txKey()); GridCacheContext cacheCtx = entry.context(); if (!cacheCtx.isNear()) cacheCtx = cacheCtx.dht().near().context(); GridNearCacheEntry cached = cacheCtx.near().peekExx(entry.key()); if (cached == null) { evicted.add(entry.txKey()); return false; } else { try { cached.unswap(); CacheObject val = cached.peek(null); if (val == null && cached.evictInternal(xidVer, null, false)) { evicted.add(entry.txKey()); return false; } else { // Initialize cache entry. entry.cached(cached); txState.addWriteEntry(entry.txKey(), entry); addExplicit(entry); return true; } } catch (GridCacheEntryRemovedException ignore) { evicted.add(entry.txKey()); if (log.isDebugEnabled()) log.debug("Got removed entry when adding to remote transaction (will ignore): " + cached); return false; } } } /** * @param cacheCtx Cache context. * @param key Key to add to read set. * @param op Operation. * @param val Value. * @param drVer Data center replication version. * @param skipStore Skip store flag. * @throws IgniteCheckedException If failed. * @return {@code True} if entry has been enlisted. */ public boolean addEntry( GridCacheContext cacheCtx, IgniteTxKey key, GridCacheOperation op, CacheObject val, @Nullable GridCacheVersion drVer, boolean skipStore, boolean keepBinary ) throws IgniteCheckedException { checkInternal(key); GridNearCacheEntry cached = cacheCtx.near().peekExx(key.key()); try { if (cached == null) { evicted.add(key); return false; } else { cached.unswap(); CacheObject peek = cached.peek(null); if (peek == null && cached.evictInternal(xidVer, null, false)) { cached.context().cache().removeIfObsolete(key.key()); evicted.add(key); return false; } else { IgniteTxEntry txEntry = new IgniteTxEntry(cacheCtx, this, op, val, -1L, -1L, cached, drVer, skipStore, keepBinary); txState.addWriteEntry(key, txEntry); return true; } } } catch (GridCacheEntryRemovedException ignore) { evicted.add(key); if (log.isDebugEnabled()) log.debug("Got removed entry when adding reads to remote transaction (will ignore): " + cached); return false; } } /** {@inheritDoc} */ @Override public String toString() { return GridToStringBuilder.toString(GridNearTxRemote.class, this, "super", super.toString()); } }