All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.atomic.FineGrainedAtomicHashMapProxy Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011 Red Hat Inc. and/or its affiliates and other
 * contributors as indicated by the @author tags. All rights reserved.
 * See the copyright.txt in the distribution for a full listing of
 * individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.infinispan.atomic;

import org.infinispan.AdvancedCache;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.DeltaAwareCacheEntry;
import org.infinispan.util.InfinispanCollections;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A layer of indirection around an {@link FineGrainedAtomicMap} to provide consistency and isolation for concurrent readers
 * while writes may also be going on.  The techniques used in this implementation are very similar to the lock-free
 * reader MVCC model used in the {@link org.infinispan.container.entries.MVCCEntry} implementations for the core data
 * container, which closely follow software transactional memory approaches to dealing with concurrency.
 * 

* Typically proxies are only created by the {@link AtomicMapLookup} helper, and would not be created by end-user code * directly. * * @author Manik Surtani * @author Vladimir Blagojevic * @author Sanne Grinovero * @param the type of keys maintained by this map * @param the type of mapped values * @see AtomicHashMap * @since 5.1 */ public class FineGrainedAtomicHashMapProxy extends AtomicHashMapProxy implements FineGrainedAtomicMap { private static final Log log = LogFactory.getLog(FineGrainedAtomicHashMapProxy.class); private static final boolean trace = log.isTraceEnabled(); FineGrainedAtomicHashMapProxy(AdvancedCache cache, Object deltaMapKey) { super(cache, deltaMapKey); } @SuppressWarnings("unchecked") @Override protected AtomicHashMap getDeltaMapForWrite() { CacheEntry lookedUpEntry = lookupEntryFromCurrentTransaction(); boolean lockedAndCopied = lookedUpEntry != null && lookedUpEntry.isChanged() && toMap(lookedUpEntry.getValue()).copied; if (lockedAndCopied) { return getDeltaMapForRead(); } else { AtomicHashMap map = getDeltaMapForRead(); boolean insertNewMap = map == null; // copy for write AtomicHashMap copy = insertNewMap ? new AtomicHashMap(true) : map.copy(); copy.initForWriting(); if (insertNewMap) { cacheForWriting.put(deltaMapKey, copy); } return copy; } } @Override public Set keySet() { if (hasUncommittedChanges()) { return new HashSet(keySetUncommitted()); } else { AtomicHashMap map = getDeltaMapForRead().copy(); Set result = new HashSet(keySetUncommitted()); if (map != null) { result.addAll(map.keySet()); } return result; } } @SuppressWarnings("unchecked") private Set keySetUncommitted() { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null ? (Set) entry.getUncommittedChages().keySet() : InfinispanCollections.emptySet(); } @Override public Collection values() { if (hasUncommittedChanges()) { return new ArrayList(valuesUncommitted()); } AtomicHashMap map = getDeltaMapForRead().copy(); List result = new ArrayList(valuesUncommitted()); if (map != null) { result.addAll(map.values()); } return result; } @SuppressWarnings("unchecked") private Collection valuesUncommitted() { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null ? (Collection) entry.getUncommittedChages().values() : InfinispanCollections.emptySet(); } @Override public Set> entrySet() { Set> result; if (hasUncommittedChanges()) { return new HashSet>(entrySetUncommitted()); } else { AtomicHashMap map = getDeltaMapForRead().copy(); result = new HashSet>(); if (map != null) { result.addAll(map.entrySet()); } return result; } } @SuppressWarnings("unchecked") private Set> entrySetUncommitted() { DeltaAwareCacheEntry entry = lookupEntry(); return (Set>) (entry != null ? entry.getUncommittedChages().entrySet() : InfinispanCollections.emptySet()); } @Override public int size() { final AtomicHashMap map = getDeltaMapForRead(); final int result = sizeUncommitted(); if (result <= 0 && map != null) { return map.size(); } return result; } public int sizeUncommitted() { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null ? entry.getUncommittedChages().size() : 0; } public boolean hasUncommittedChanges() { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null && ! entry.getUncommittedChages().isEmpty(); } @Override public boolean isEmpty() { AtomicHashMap map = getDeltaMapForRead(); return ! hasUncommittedChanges() && (map == null || map.isEmpty()); } @Override public boolean containsKey(Object key) { if (hasUncommittedChanges()) { return containsKeyUncommitted(key); } else { AtomicHashMap map = getDeltaMapForRead(); return map != null ? map.containsKey(key) : false; } } private boolean containsKeyUncommitted(Object key) { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null && entry.getUncommittedChages().containsKey(key); } @Override public boolean containsValue(Object value) { if (hasUncommittedChanges()) { return containsValueUncommitted(value); } else { AtomicHashMap map = getDeltaMapForRead(); return map != null ? map.containsValue(value) : false; } } private boolean containsValueUncommitted(Object value) { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null && entry.getUncommittedChages().containsValue(value); } @Override public V get(Object key) { V result = getUncommitted(key); if (result == null) { AtomicHashMap map = getDeltaMapForRead(); result = map == null ? null : map.get(key); } return result; } @SuppressWarnings("unchecked") public V getUncommitted(Object key) { DeltaAwareCacheEntry entry = lookupEntry(); return entry != null ? (V)entry.getUncommittedChages().get(key): null; } // writers @Override public V put(K key, V value) { AtomicHashMap deltaMapForWrite = null; try { startAtomic(); deltaMapForWrite = getDeltaMapForWrite(); V toReturn = deltaMapForWrite.put(key, value); invokeApplyDelta(deltaMapForWrite.getDelta()); return toReturn; } finally { endAtomic(); } } @Override public V remove(Object key) { AtomicHashMap deltaMapForWrite = null; try { startAtomic(); deltaMapForWrite = getDeltaMapForWrite(); V toReturn = deltaMapForWrite.remove(key); invokeApplyDelta(deltaMapForWrite.getDelta()); return toReturn; } finally { endAtomic(); } } @Override public void putAll(Map m) { AtomicHashMap deltaMapForWrite = null; try { startAtomic(); deltaMapForWrite = getDeltaMapForWrite(); deltaMapForWrite.putAll(m); invokeApplyDelta(deltaMapForWrite.getDelta()); } finally { endAtomic(); } } @Override public void clear() { AtomicHashMap deltaMapForWrite = null; try { startAtomic(); deltaMapForWrite = getDeltaMapForWrite(); deltaMapForWrite.clear(); invokeApplyDelta(deltaMapForWrite.getDelta()); } finally { endAtomic(); } } private DeltaAwareCacheEntry lookupEntry() { CacheEntry entry = lookupEntryFromCurrentTransaction(); if (entry instanceof DeltaAwareCacheEntry) { return (DeltaAwareCacheEntry)entry; } else { return null; } } private void invokeApplyDelta(AtomicHashMapDelta delta) { Collection keys = InfinispanCollections.emptyList(); if (delta.hasClearOperation()) { // if it has clear op we need to lock all keys AtomicHashMap map = (AtomicHashMap) cache.get(deltaMapKey); if (map != null) { keys = new ArrayList(map.keySet()); } } else { keys = delta.getKeys(); } cache.applyDelta(deltaMapKey, delta, keys); } @Override public String toString() { StringBuilder sb = new StringBuilder("FineGrainedAtomicHashMapProxy{deltaMapKey="); sb.append(deltaMapKey); sb.append("}"); return sb.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy