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

net.sf.ehcache.distribution.jgroups.BootstrapRequestMap Maven / Gradle / Ivy

/**
 *  Copyright 2003-2010 Terracotta, Inc.
 *
 *  Licensed 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 net.sf.ehcache.distribution.jgroups;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Simplified version of a Map that wraps a weak value reference concurrent Map of {@link BootstrapRequest}s.
 * It also handles allowing clients to wait for the map's size to change to a specific value.
 * 
 * @author Eric Dalquist
 * @version $Revision$
 */
class BootstrapRequestMap {
    private static final Logger LOG = LoggerFactory.getLogger(BootstrapRequestMap.class.getName());
    
    private final ConcurrentMap> bootstrapRequests =
        new ConcurrentHashMap>();
    private final Object requestChangeNotifier = new Object();
    
    /**
     * Wait for the map to change to the specified size. Returns true if the map reached the size before
     * the timeout.
     */
    public boolean waitForMapSize(int size, long duration) {
        final long waitTime = Math.min(duration, 1000);
        
        final long start = System.currentTimeMillis();
        this.cleanBootstrapRequests();
        while (this.bootstrapRequests.size() != size && (System.currentTimeMillis() - start) < duration) {
            try {
                synchronized (this.requestChangeNotifier) {
                    this.requestChangeNotifier.wait(waitTime);
                }
            } catch (InterruptedException e) {
                LOG.warn("Interrupted while waiting for BootstrapRequestMap to empty", e);
            }

            this.cleanBootstrapRequests();
        }
        
        return this.bootstrapRequests.size() == size;
    }
    
    /**
     * @see Map#keySet()
     */
    public Set keySet() {
        this.cleanBootstrapRequests();
        return Collections.unmodifiableSet(this.bootstrapRequests.keySet());
    }
    
    /**
     * @see Map#isEmpty()
     */
    public boolean isEmpty() {
        this.cleanBootstrapRequests();
        return this.bootstrapRequests.isEmpty();
    }
    
    /**
     * @see Map#size()
     */
    public int size() {
        this.cleanBootstrapRequests();
        return this.bootstrapRequests.size();
    }
    
    /**
     * @see Map#put(Object, Object)
     */
    public BootstrapRequest put(String cacheName, BootstrapRequest bootstrapRequest) {
        final Reference oldReference = 
            this.bootstrapRequests.put(cacheName, new WeakReference(bootstrapRequest));
        
        synchronized (this.requestChangeNotifier) {
            this.requestChangeNotifier.notifyAll();
        }
        
        if (oldReference != null) {
            return oldReference.get();
        }
        
        return null;
    }
    
    /**
     * @see Map#get(Object)
     */
    public BootstrapRequest get(String cacheName) {
        final Reference reference = this.bootstrapRequests.get(cacheName);
        if (reference == null) {
            return null;
        }
        
        final BootstrapRequest bootstrapRequest = reference.get();
        if (bootstrapRequest == null) {
            LOG.info("BootstrapRequest for {} has been GCed, removing from requests map.", cacheName);
            
            //Remove GC'd entry
            if (this.bootstrapRequests.remove(cacheName, reference)) {
                synchronized (this.requestChangeNotifier) {
                    this.requestChangeNotifier.notifyAll();
                }
            }
            return null;
        }
        
        return bootstrapRequest;
    }
    
    /**
     * @see Map#remove(Object)
     */
    public BootstrapRequest remove(String cacheName) {
        final Reference reference = this.bootstrapRequests.remove(cacheName);
        if (reference == null) {
            return null;
        }

        synchronized (this.requestChangeNotifier) {
            this.requestChangeNotifier.notifyAll();
        }
        
        return reference.get();
    }
    
    /**
     * Iterates over the map cleaning up {@link WeakReference}s that have been GCd
     */
    public void cleanBootstrapRequests() {
        for (final Iterator>> bootstrapRequestItr = 
            this.bootstrapRequests.entrySet().iterator(); bootstrapRequestItr.hasNext();) {
            
            final Entry> bootstrapRequestEntry = bootstrapRequestItr.next();
            
            if (bootstrapRequestEntry.getValue().get() == null) {
                LOG.info("BootstrapRequest for {} has been GCed, removing from requests map.", bootstrapRequestEntry.getKey());
                bootstrapRequestItr.remove();
                
                synchronized (this.requestChangeNotifier) {
                    this.requestChangeNotifier.notifyAll();
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy