/* * 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; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.eviction.EvictableEntry; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.util.lang.GridMetadataAwareAdapter; import org.apache.ignite.internal.util.lang.GridTuple; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; /** * Entry wrapper that never obscures obsolete entries from user. */ public class CacheEvictableEntryImpl<K, V> implements EvictableEntry<K, V> { /** */ private static final int META_KEY = GridMetadataAwareAdapter.EntryKey.CACHE_EVICTABLE_ENTRY_KEY.key(); /** Cached entry. */ @GridToStringInclude protected GridCacheEntryEx cached; /** * @param cached Cached entry. */ @SuppressWarnings({"TypeMayBeWeakened"}) protected CacheEvictableEntryImpl(GridCacheEntryEx cached) { this.cached = cached; } /** {@inheritDoc} */ @Override public K getKey() throws IllegalStateException { return cached.key().value(cached.context().cacheObjectContext(), false); } /** {@inheritDoc} */ @Override public boolean isCached() { return !cached.obsoleteOrDeleted(); } /** {@inheritDoc} */ @Override public boolean evict() { GridCacheContext<K, V> ctx = cached.context(); try { assert ctx != null; CacheEvictionManager mgr = ctx.evicts(); if (mgr == null) { assert ctx.kernalContext().isStopping(); return false; } return mgr.evict(cached, null, false, null); } catch (IgniteCheckedException e) { U.error(ctx.grid().log(), "Failed to evict entry from cache: " + cached, e); return false; } } /** * @return Peeks value. */ @Nullable public V peek() { try { CacheObject val = cached.peek(null); return val != null ? val.<V>value(cached.context().cacheObjectContext(), false) : null; } catch (GridCacheEntryRemovedException ignored) { return null; } catch (IgniteCheckedException e) { throw new IgniteException(e); } } /** {@inheritDoc} */ @Override public int size() { try { GridCacheContext<Object, Object> cctx = cached.context(); KeyCacheObject key = cached.key(); byte[] keyBytes = key.valueBytes(cctx.cacheObjectContext()); byte[] valBytes = null; CacheObject cacheObj = cached.valueBytes(); if (cacheObj != null) valBytes = cacheObj.valueBytes(cctx.cacheObjectContext()); return valBytes == null ? keyBytes.length : keyBytes.length + valBytes.length; } catch (GridCacheEntryRemovedException ignored) { return 0; } catch (IgniteCheckedException e) { throw new IgniteException(e); } } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public V getValue() { try { IgniteInternalTx tx = cached.context().tm().userTx(); if (tx != null) { GridTuple<CacheObject> peek = tx.peek(cached.context(), false, cached.key()); if (peek != null) return peek.get().value(cached.context().cacheObjectContext(), false); } if (cached.detached()) { CacheObject val = cached.rawGet(); return val != null ? val.<V>value(cached.context().cacheObjectContext(), false) : null; } for (;;) { GridCacheEntryEx e = cached.context().cache().peekEx(cached.key()); if (e == null) return null; try { CacheObject val = e.peek(null); return val != null ? val.<V>value(cached.context().cacheObjectContext(), false) : null; } catch (GridCacheEntryRemovedException ignored) { // No-op. } catch (IgniteCheckedException ex) { throw new IgniteException(ex); } } } catch (GridCacheFilterFailedException ignored) { throw new IgniteException("Should never happen."); } } /** {@inheritDoc} */ @Nullable @Override public <T> T addMeta(T val) { return cached.addMeta(META_KEY, val); } /** {@inheritDoc} */ @Nullable @Override public <T> T meta() { return cached.meta(META_KEY); } /** {@inheritDoc} */ @Nullable @Override public <T> T removeMeta() { return cached.removeMeta(META_KEY); } /** {@inheritDoc} */ @Override public <T> boolean removeMeta(T val) { return cached.removeMeta(META_KEY, val); } /** {@inheritDoc} */ @Nullable @Override public <T> T putMetaIfAbsent(T val) { return cached.putMetaIfAbsent(META_KEY, val); } /** {@inheritDoc} */ @Override public <T> boolean replaceMeta(T curVal, T newVal) { return cached.replaceMeta(META_KEY,curVal, newVal); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <T> T unwrap(Class<T> clazz) { if (clazz.isAssignableFrom(IgniteCache.class)) return (T)cached.context().grid().cache(cached.context().name()); if(clazz.isAssignableFrom(getClass())) return clazz.cast(this); throw new IllegalArgumentException(); } /** {@inheritDoc} */ @Override public int hashCode() { return cached.key().hashCode(); } /** {@inheritDoc} */ @SuppressWarnings({"unchecked"}) @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj instanceof CacheEvictableEntryImpl) { CacheEvictableEntryImpl<K, V> other = (CacheEvictableEntryImpl<K, V>)obj; return cached.key().equals(other.cached.key()); } return false; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheEvictableEntryImpl.class, this); } }