/* * 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.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.internal.cluster.ClusterTopologyServerNotFoundException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture; import org.apache.ignite.internal.processors.cache.store.CacheStoreManager; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC; /** * */ public class IgniteTxImplicitSingleStateImpl extends IgniteTxLocalStateAdapter { /** */ private GridCacheContext cacheCtx; /** Entry is stored as singleton list for performance optimization. */ private List<IgniteTxEntry> entry; /** */ private boolean init; /** */ private boolean recovery; /** {@inheritDoc} */ @Override public void addActiveCache(GridCacheContext ctx, boolean recovery, IgniteTxLocalAdapter tx) throws IgniteCheckedException { assert cacheCtx == null : "Cache already set [cur=" + cacheCtx.name() + ", new=" + ctx.name() + ']'; cacheCtx = ctx; this.recovery = recovery; tx.activeCachesDeploymentEnabled(cacheCtx.deploymentEnabled()); } /** {@inheritDoc} */ @Nullable @Override public GridCacheContext singleCacheContext(GridCacheSharedContext cctx) { return cacheCtx; } /** {@inheritDoc} */ @Nullable @Override public Integer firstCacheId() { return cacheCtx != null ? cacheCtx.cacheId() : null; } /** {@inheritDoc} */ @Override public void unwindEvicts(GridCacheSharedContext cctx) { if (entry == null || entry.isEmpty()) return; assert entry.size() == 1; GridCacheContext ctx = cctx.cacheContext(entry.get(0).cacheId()); if (ctx != null) CU.unwindEvicts(ctx); } /** {@inheritDoc} */ @Override public void awaitLastFut(GridCacheSharedContext ctx) { if (cacheCtx == null) return; cacheCtx.cache().awaitLastFut(); } /** {@inheritDoc} */ @Override public boolean implicitSingle() { return true; } /** {@inheritDoc} */ @Override public IgniteCheckedException validateTopology( GridCacheSharedContext cctx, boolean read, GridDhtTopologyFuture topFut ) { if (cacheCtx == null) return null; Throwable err = topFut.validateCache(cacheCtx, recovery, read, null, entry); if (err != null) { return new IgniteCheckedException("Failed to perform cache operation (cache topology is not valid): " + U.maskName(cacheCtx.name())); } if (CU.affinityNodes(cacheCtx, topFut.topologyVersion()).isEmpty()) { return new ClusterTopologyServerNotFoundException("Failed to map keys for cache (all " + "partition nodes left the grid): " + cacheCtx.name()); } return null; } /** {@inheritDoc} */ @Override public CacheWriteSynchronizationMode syncMode(GridCacheSharedContext cctx) { return cacheCtx != null ? cacheCtx.config().getWriteSynchronizationMode() : FULL_ASYNC; } /** {@inheritDoc} */ @Override public boolean hasNearCache(GridCacheSharedContext cctx) { return cacheCtx != null && cacheCtx.isNear(); } /** {@inheritDoc} */ @Override public GridDhtTopologyFuture topologyReadLock(GridCacheSharedContext cctx, GridFutureAdapter<?> fut) { if (cacheCtx == null || cacheCtx.isLocal()) return cctx.exchange().lastTopologyFuture(); cacheCtx.topology().readLock(); if (cacheCtx.topology().stopping()) { fut.onDone(new IgniteCheckedException("Failed to perform cache operation (cache is stopped): " + cacheCtx.name())); return null; } return cacheCtx.topology().topologyVersionFuture(); } /** {@inheritDoc} */ @Override public void topologyReadUnlock(GridCacheSharedContext cctx) { if (cacheCtx == null || cacheCtx.isLocal()) return; cacheCtx.topology().readUnlock(); } /** {@inheritDoc} */ @Override public boolean storeWriteThrough(GridCacheSharedContext cctx) { if (cacheCtx == null) return false; CacheStoreManager store = cacheCtx.store(); return store.configured() && store.isWriteThrough(); } /** {@inheritDoc} */ @Override public boolean hasInterceptor(GridCacheSharedContext cctx) { GridCacheContext ctx0 = cacheCtx; return ctx0 != null && ctx0.config().getInterceptor() != null; } /** {@inheritDoc} */ @Override public Collection<CacheStoreManager> stores(GridCacheSharedContext cctx) { if (cacheCtx == null) return null; CacheStoreManager store = cacheCtx.store(); if (store.configured()) return Collections.singleton(store); return null; } /** {@inheritDoc} */ @Override public void onTxEnd(GridCacheSharedContext cctx, IgniteInternalTx tx, boolean commit) { if (cacheCtx != null) onTxEnd(cacheCtx, tx, commit); } /** {@inheritDoc} */ @Override public IgniteTxEntry entry(IgniteTxKey key) { if (entry != null && entry.get(0).txKey().equals(key)) return entry.get(0); return null; } /** {@inheritDoc} */ @Override public boolean hasWriteKey(IgniteTxKey key) { return entry != null && entry.get(0).txKey().equals(key); } /** {@inheritDoc} */ @Override public Set<IgniteTxKey> readSet() { return Collections.emptySet(); } /** {@inheritDoc} */ @Override public Set<IgniteTxKey> writeSet() { if (entry != null) { Set<IgniteTxKey> set = new HashSet<>(3, 0.75f); set.add(entry.get(0).txKey()); return set; } else return Collections.<IgniteTxKey>emptySet(); } /** {@inheritDoc} */ @Override public Collection<IgniteTxEntry> writeEntries() { return entry != null ? entry : Collections.<IgniteTxEntry>emptyList(); } /** {@inheritDoc} */ @Override public Collection<IgniteTxEntry> readEntries() { return Collections.emptyList(); } /** {@inheritDoc} */ @Override public Map<IgniteTxKey, IgniteTxEntry> writeMap() { return entry != null ? F.asMap(entry.get(0).txKey(), entry.get(0)) : Collections.<IgniteTxKey, IgniteTxEntry>emptyMap(); } /** {@inheritDoc} */ @Override public Map<IgniteTxKey, IgniteTxEntry> readMap() { return Collections.emptyMap(); } /** {@inheritDoc} */ @Override public boolean empty() { return entry == null; } /** {@inheritDoc} */ @Override public Collection<IgniteTxEntry> allEntries() { return entry != null ? entry : Collections.<IgniteTxEntry>emptyList(); } /** {@inheritDoc} */ @Override public boolean init(int txSize) { if (!init) { init = true; return true; } return false; } /** {@inheritDoc} */ @Override public boolean initialized() { return init; } /** {@inheritDoc} */ @Override public void addEntry(IgniteTxEntry entry) { assert this.entry == null : "Entry already set [cur=" + this.entry + ", new=" + entry + ']'; this.entry = Collections.singletonList(entry); } /** {@inheritDoc} */ @Override public void seal() { // No-op. } /** {@inheritDoc} */ @Override public IgniteTxEntry singleWrite() { return entry != null ? entry.get(0) : null; } /** {@inheritDoc} */ @Override public boolean hasNearCacheConfigured(GridCacheSharedContext ctx, AffinityTopologyVersion topVer) { return cacheCtx != null ? ctx.discovery().hasNearCache(cacheCtx.cacheId(), topVer) : false; } /** {@inheritDoc} */ public String toString() { return S.toString(IgniteTxImplicitSingleStateImpl.class, this); } }