/* * 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.datastructures; import java.io.Externalizable; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.ObjectStreamException; import javax.cache.processor.EntryProcessorException; import javax.cache.processor.EntryProcessorResult; import javax.cache.processor.MutableEntry; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.CacheEntryProcessor; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport; import org.apache.ignite.lang.IgniteBiTuple; /** * Cache atomic long implementation. */ public final class GridCacheAtomicLongImpl implements GridCacheAtomicLongEx, IgniteChangeGlobalStateSupport, Externalizable { /** */ private static final long serialVersionUID = 0L; /** Deserialization stash. */ private static final ThreadLocal<IgniteBiTuple<GridKernalContext, String>> stash = new ThreadLocal<IgniteBiTuple<GridKernalContext, String>>() { @Override protected IgniteBiTuple<GridKernalContext, String> initialValue() { return new IgniteBiTuple<>(); } }; /** Atomic long name. */ private String name; /** Removed flag.*/ private volatile boolean rmvd; /** Check removed flag. */ private boolean rmvCheck; /** Atomic long key. */ private GridCacheInternalKey key; /** Atomic long projection. */ private IgniteInternalCache<GridCacheInternalKey, GridCacheAtomicLongValue> atomicView; /** Cache context. */ private GridCacheContext ctx; /** * Empty constructor required by {@link Externalizable}. */ public GridCacheAtomicLongImpl() { // No-op. } /** * Default constructor. * * @param name Atomic long name. * @param key Atomic long key. * @param atomicView Atomic projection. * @param ctx CacheContext. */ public GridCacheAtomicLongImpl(String name, GridCacheInternalKey key, IgniteInternalCache<GridCacheInternalKey, GridCacheAtomicLongValue> atomicView, GridCacheContext ctx) { assert key != null; assert atomicView != null; assert ctx != null; assert name != null; this.ctx = ctx; this.key = key; this.atomicView = atomicView; this.name = name; } /** {@inheritDoc} */ @Override public String name() { return name; } /** {@inheritDoc} */ @Override public long get() { checkRemoved(); try { GridCacheAtomicLongValue val = atomicView.get(key); if (val == null) throw new IgniteException("Failed to find atomic long: " + name); return val.get(); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long incrementAndGet() { checkRemoved(); try{ EntryProcessorResult<Long> res = atomicView.invoke(key, IncrementAndGetProcessor.INSTANCE); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long getAndIncrement() { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, GetAndIncrementProcessor.INSTANCE); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long addAndGet(long l) { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, new AddAndGetProcessor(l)); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long getAndAdd(long l) { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, new GetAndAddProcessor(l)); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long decrementAndGet() { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, DecrementAndGetProcessor.INSTANCE); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long getAndDecrement() { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, GetAndDecrementProcessor.INSTANCE); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public long getAndSet(long l) { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, new GetAndSetProcessor(l)); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public boolean compareAndSet(long expVal, long newVal) { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, new CompareAndSetProcessor(expVal, newVal)); assert res != null && res.get() != null : res; return res.get() == expVal; } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** * @param expVal Expected value. * @param newVal New value. * @return Old value. */ public long compareAndSetAndGet(long expVal, long newVal) { checkRemoved(); try { EntryProcessorResult<Long> res = atomicView.invoke(key, new CompareAndSetProcessor(expVal, newVal)); assert res != null && res.get() != null : res; return res.get(); } catch (EntryProcessorException e) { throw new IgniteException(e.getMessage(), e); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** * Check removed flag. * * @throws IllegalStateException If removed. */ private void checkRemoved() throws IllegalStateException { if (rmvd) throw removedError(); if (rmvCheck) { try { rmvd = atomicView.get(key) == null; } catch (IgniteCheckedException e) { throw U.convertException(e); } rmvCheck = false; if (rmvd) { ctx.kernalContext().dataStructures().onRemoved(key, this); throw removedError(); } } } /** * @return Error. */ private IllegalStateException removedError() { return new IllegalStateException("Atomic long was removed from cache: " + name); } /** {@inheritDoc} */ @Override public boolean onRemoved() { return rmvd = true; } /** {@inheritDoc} */ @Override public void needCheckNotRemoved() { rmvCheck = true; } /** {@inheritDoc} */ @Override public GridCacheInternalKey key() { return key; } /** {@inheritDoc} */ @Override public boolean removed() { return rmvd; } /** {@inheritDoc} */ @Override public void close() { if (rmvd) return; try { ctx.kernalContext().dataStructures().removeAtomicLong(name); } catch (IgniteCheckedException e) { throw U.convertException(e); } } /** {@inheritDoc} */ @Override public void onActivate(GridKernalContext kctx) throws IgniteCheckedException { this.atomicView = kctx.cache().atomicsCache(); this.ctx = atomicView.context(); } /** {@inheritDoc} */ @Override public void onDeActivate(GridKernalContext kctx) throws IgniteCheckedException { // No-op. } /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(ctx.kernalContext()); out.writeUTF(name); } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { IgniteBiTuple<GridKernalContext, String> t = stash.get(); t.set1((GridKernalContext)in.readObject()); t.set2(in.readUTF()); } /** * Reconstructs object on unmarshalling. * * @return Reconstructed object. * @throws ObjectStreamException Thrown in case of unmarshalling error. */ private Object readResolve() throws ObjectStreamException { try { IgniteBiTuple<GridKernalContext, String> t = stash.get(); return t.get1().dataStructures().atomicLong(t.get2(), 0L, false); } catch (IgniteCheckedException e) { throw U.withCause(new InvalidObjectException(e.getMessage()), e); } finally { stash.remove(); } } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridCacheAtomicLongImpl.class, this); } /** * */ static class GetAndSetProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private final long newVal; /** * @param newVal New value. */ GetAndSetProcessor(long newVal) { this.newVal = newVal; } /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long curVal = val.get(); e.setValue(new GridCacheAtomicLongValue(newVal)); return curVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GetAndSetProcessor.class, this); } } /** * */ static class GetAndAddProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private final long delta; /** * @param delta Delta. */ GetAndAddProcessor(long delta) { this.delta = delta; } /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long curVal = val.get(); e.setValue(new GridCacheAtomicLongValue(curVal + delta)); return curVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GetAndAddProcessor.class, this); } } /** * */ static class AddAndGetProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private final long delta; /** * @param delta Delta. */ AddAndGetProcessor(long delta) { this.delta = delta; } /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long newVal = val.get() + delta; e.setValue(new GridCacheAtomicLongValue(newVal)); return newVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(AddAndGetProcessor.class, this); } } /** * */ static class CompareAndSetProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private final long expVal; /** */ private final long newVal; /** * @param expVal Expected value. * @param newVal New value. */ CompareAndSetProcessor(long expVal, long newVal) { this.expVal = expVal; this.newVal = newVal; } /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long curVal = val.get(); if (curVal == expVal) e.setValue(new GridCacheAtomicLongValue(newVal)); return curVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(CompareAndSetProcessor.class, this); } } /** * */ static class GetAndIncrementProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private static final GetAndIncrementProcessor INSTANCE = new GetAndIncrementProcessor(); /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long ret = val.get(); e.setValue(new GridCacheAtomicLongValue(ret + 1)); return ret; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GetAndIncrementProcessor.class, this); } } /** * */ static class IncrementAndGetProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private static final IncrementAndGetProcessor INSTANCE = new IncrementAndGetProcessor(); /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long newVal = val.get() + 1; e.setValue(new GridCacheAtomicLongValue(newVal)); return newVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(IncrementAndGetProcessor.class, this); } } /** * */ static class GetAndDecrementProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private static final GetAndDecrementProcessor INSTANCE = new GetAndDecrementProcessor(); /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long ret = val.get(); e.setValue(new GridCacheAtomicLongValue(ret - 1)); return ret; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GetAndDecrementProcessor.class, this); } } /** * */ static class DecrementAndGetProcessor implements CacheEntryProcessor<GridCacheInternalKey, GridCacheAtomicLongValue, Long> { /** */ private static final long serialVersionUID = 0L; /** */ private static final DecrementAndGetProcessor INSTANCE = new DecrementAndGetProcessor(); /** {@inheritDoc} */ @Override public Long process(MutableEntry<GridCacheInternalKey, GridCacheAtomicLongValue> e, Object... args) { GridCacheAtomicLongValue val = e.getValue(); if (val == null) throw new EntryProcessorException("Failed to find atomic long: " + e.getKey().name()); long newVal = val.get() - 1; e.setValue(new GridCacheAtomicLongValue(newVal)); return newVal; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(DecrementAndGetProcessor.class, this); } } }