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

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

/**
 *  Copyright 2003-2009 Luck Consulting Pty Ltd
 *
 *  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 net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.CachePeer;
import net.sf.ehcache.distribution.RemoteCacheException;
import org.jgroups.stack.IpAddress;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Loads Elements from a random Cache Peer
 *
 * @author Greg Luck
 * @version $Id$
 */
public class JGroupsBootstrapCacheLoader implements BootstrapCacheLoader {

    private static final int ONE_SECOND = 1000;

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

    private static final int WAIT_FOR_RESPONSE = 3000;

    /**
     * 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 JGroupsBootstrapCacheLoader(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);
        }

        /**
         * thread method.
         */
        public final void run() {
            try {
                doLoad(cache);
            } catch (RemoteCacheException e) {
                LOG.log(Level.WARNING, "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 { JGroupManager jGroupManager = null; List cachePeers = acquireCachePeers(cache); if (cachePeers == null || cachePeers.size() == 0) { LOG.log(Level.INFO, "Empty list of cache peers for cache " + cache.getName() + ". No cache peer to bootstrap from."); return; } jGroupManager = (JGroupManager) cachePeers.get(0); IpAddress localAddress = (IpAddress) jGroupManager.getBusLocalAddress(); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "(" + cache.getName() + ") localAddress: " + localAddress); } List addresses = buildCachePeerAddressList(cache, jGroupManager, localAddress); if (addresses == null || addresses.size() == 0) { LOG.log(Level.INFO, "This is the first node to start: no cache bootstrap for " + cache.getName()); return; } IpAddress address = null; Random random = new Random(); while (addresses.size() > 0 && (address == null || cache.getSize() == 0)) { int randomPeerNumber = random.nextInt(addresses.size()); address = addresses.get(randomPeerNumber); addresses.remove(randomPeerNumber); JGroupEventMessage event = new JGroupEventMessage(JGroupEventMessage.ASK_FOR_BOOTSTRAP, localAddress, null, cache, cache.getName()); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "contact " + address + " to boot cache " + cache.getName()); } List events = new ArrayList(); events.add(event); try { jGroupManager.send(address, events); try { Thread.sleep(WAIT_FOR_RESPONSE); } catch (InterruptedException e) { LOG.log(Level.SEVERE, "InterruptedException", e); } } catch (RemoteException e1) { LOG.log(Level.SEVERE, "error calling " + address, e1); } } if (cache.getSize() == 0) { LOG.log(Level.WARNING, "Cache failed to bootstrap from its peers: " + cache.getName()); } else { LOG.log(Level.INFO, "Bootstrap for cache " + cache.getName() + " has loaded " + cache.getSize() + " elements"); } } private List buildCachePeerAddressList(Ehcache cache, JGroupManager jGroupManager, IpAddress localAddress) { List members = jGroupManager.getBusMembership(); List addresses = new ArrayList(); for (int i = 0; i < members.size(); i++) { IpAddress member = (IpAddress) members.get(i); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "(" + cache.getName() + ") member " + i + ": " + member.getIpAddress() + (member.equals(localAddress) ? " ***" : "")); } if (!member.equals(localAddress)) { addresses.add(member); } } return addresses; } /** * Acquires the cache peers for this cache. * * @param cache */ protected List acquireCachePeers(Ehcache cache) { long timeForClusterToForm = 0; CacheManagerPeerProvider cacheManagerPeerProvider = cache.getCacheManager().getCacheManagerPeerProvider("JGroups"); if (cacheManagerPeerProvider != null) { timeForClusterToForm = cacheManagerPeerProvider.getTimeForClusterToForm(); } if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "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; } */ LOG.log(Level.INFO, "waiting..."); try { Thread.sleep(ONE_SECOND); } catch (InterruptedException e) { LOG.log(Level.INFO, "doLoad for " + cache.getName() + " interrupted."); } } if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "cache peers: " + cachePeers.size()); } 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("JGroups"); if (provider == null) { return null; } else { return provider.listRemoteCachePeers(cache); } } /** * Gets the maximum chunk size */ public int getMaximumChunkSizeBytes() { return maximumChunkSizeBytes; } /** * Clones this loader */ public Object clone() throws CloneNotSupportedException { // checkstyle return new JGroupsBootstrapCacheLoader(asynchronous, maximumChunkSizeBytes); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy