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

net.sf.ehcache.distribution.RMIBootstrapCacheLoader Maven / Gradle / Ivy

There is a newer version: 2.10.9.2
Show newest version
/**
 *  Copyright 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;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

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

/**
 * Loads Elements from a random Cache Peer
 *
 * @author Greg Luck
 * @version $Id: RMIBootstrapCacheLoader.java 5594 2012-05-07 16:04:31Z cdennis $
 */
public class RMIBootstrapCacheLoader implements BootstrapCacheLoader, Cloneable {

    private static final int ONE_SECOND = 1000;

    private static final Logger LOG = LoggerFactory.getLogger(RMIBootstrapCacheLoader.class.getName());

    /**
     * Whether to load asynchronously
     */
    protected boolean asynchronous;

    /**
     * The maximum serialized size of the elements to request from a remote cache peer during bootstrap.
     */
    protected int maximumChunkSizeBytes;

    /**
     * Creates a boostrap cache loader that will work with RMI based distribution
     *
     * @param asynchronous Whether to load asynchronously
     */
    public RMIBootstrapCacheLoader(boolean asynchronous, int maximumChunkSize) {
        this.asynchronous = asynchronous;
        this.maximumChunkSizeBytes = maximumChunkSize;
    }


    /**
     * Bootstraps the cache from a random CachePeer. Requests are done in chunks estimated at 5MB Serializable
     * size. This balances memory use on each end and network performance.
     *
     * @throws RemoteCacheException
     *          if anything goes wrong with the remote call
     */
    public void load(Ehcache cache) throws RemoteCacheException {
        if (asynchronous) {
            BootstrapThread bootstrapThread = new BootstrapThread(cache);
            bootstrapThread.start();
        } else {
            doLoad(cache);
        }
    }

    /**
     * @return true if this bootstrap loader is asynchronous
     */
    public boolean isAsynchronous() {
        return asynchronous;
    }


    /**
     * A background daemon thread that asynchronously calls doLoad
     */
    private final class BootstrapThread extends Thread {
        private Ehcache cache;

        public BootstrapThread(Ehcache cache) {
            super("Bootstrap Thread for cache " + cache.getName());
            this.cache = cache;
            setDaemon(true);
            setPriority(Thread.NORM_PRIORITY);
        }

        /**
         * RemoteDebugger thread method.
         */
        public final void run() {
            try {
                doLoad(cache);
            } catch (RemoteCacheException e) {
                LOG.warn("Error asynchronously performing bootstrap. The cause was: " + e.getMessage(), e);
            } finally {
                cache = null;
            }

        }

    }


    /**
     * Bootstraps the cache from a random CachePeer. Requests are done in chunks estimated at 5MB Serializable
     * size. This balances memory use on each end and network performance.
     * 

* Bootstrapping requires the establishment of a cluster. This can be instantaneous for manually configued * clusters or may take a number of seconds for multicast ones. This method waits up to 11 seconds for a cluster * to form. * * @throws RemoteCacheException * if anything goes wrong with the remote call */ public void doLoad(Ehcache cache) throws RemoteCacheException { List cachePeers = acquireCachePeers(cache); if (cachePeers == null || cachePeers.size() == 0) { LOG.debug("Empty list of cache peers for cache " + cache.getName() + ". No cache peer to bootstrap from."); return; } Random random = new Random(); int randomPeerNumber = random.nextInt(cachePeers.size()); CachePeer cachePeer = (CachePeer) cachePeers.get(randomPeerNumber); LOG.debug("Bootstrapping " + cache.getName() + " from " + cachePeer); try { //Estimate element size Element sampleElement = null; List keys = cachePeer.getKeys(); for (int i = 0; i < keys.size(); i++) { Serializable key = (Serializable) keys.get(i); sampleElement = cachePeer.getQuiet(key); if (sampleElement != null && sampleElement.getSerializedSize() != 0) { break; } } if (sampleElement == null) { LOG.debug("All cache peer elements were either null or empty. Nothing to bootstrap from. Cache was " + cache.getName() + ". Cache peer was " + cachePeer); return; } long size = sampleElement.getSerializedSize(); int chunkSize = (int) (maximumChunkSizeBytes / size); List requestChunk = new ArrayList(); for (int i = 0; i < keys.size(); i++) { Serializable serializable = (Serializable) keys.get(i); requestChunk.add(serializable); if (requestChunk.size() == chunkSize) { fetchAndPutElements(cache, requestChunk, cachePeer); requestChunk.clear(); } } //get leftovers fetchAndPutElements(cache, requestChunk, cachePeer); LOG.debug("Bootstrap of " + cache.getName() + " from " + cachePeer + " finished. " + keys.size() + " keys requested."); } catch (Throwable t) { throw new RemoteCacheException("Error bootstrapping from remote peer. Message was: " + t.getMessage(), t); } } /** * Acquires the cache peers for this cache. * * @param cache */ protected List acquireCachePeers(Ehcache cache) { long timeForClusterToForm = 0; CacheManagerPeerProvider cacheManagerPeerProvider = cache.getCacheManager().getCacheManagerPeerProvider("RMI"); if (cacheManagerPeerProvider != null) { timeForClusterToForm = cacheManagerPeerProvider.getTimeForClusterToForm(); } if (LOG.isDebugEnabled()) { LOG.debug("Attempting to acquire cache peers for cache " + cache.getName() + " to bootstrap from. Will wait up to " + timeForClusterToForm + "ms for cache to join cluster."); } List cachePeers = null; for (int i = 0; i <= timeForClusterToForm; i = i + ONE_SECOND) { cachePeers = listRemoteCachePeers(cache); if (cachePeers == null) { break; } if (cachePeers.size() > 0) { break; } try { Thread.sleep(ONE_SECOND); } catch (InterruptedException e) { LOG.debug("doLoad for " + cache.getName() + " interrupted."); } } LOG.debug("cache peers: {}", cachePeers); return cachePeers; } /** * Fetches a chunk of elements from a remote cache peer * * @param cache the cache to put elements in * @param requestChunk the chunk of keys to request * @param cachePeer the peer to fetch from * @throws java.rmi.RemoteException */ protected void fetchAndPutElements(Ehcache cache, List requestChunk, CachePeer cachePeer) throws RemoteException { List receivedChunk = cachePeer.getElements(requestChunk); for (int i = 0; i < receivedChunk.size(); i++) { Element element = (Element) receivedChunk.get(i); // element could be expired at the peer if (element != null) { cache.put(element, true); } } } /** * Package protected List of cache peers * * @param cache */ protected List listRemoteCachePeers(Ehcache cache) { CacheManagerPeerProvider provider = cache.getCacheManager().getCacheManagerPeerProvider("RMI"); if (provider == null) { return null; } else { return provider.listRemoteCachePeers(cache); } } /** * Gets the maximum chunk size */ public int getMaximumChunkSizeBytes() { return maximumChunkSizeBytes; } /** * Clones this loader */ @Override public Object clone() throws CloneNotSupportedException { //checkstyle return new RMIBootstrapCacheLoader(asynchronous, maximumChunkSizeBytes); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy