com.gemstone.gemfire.cache.util.BridgeLoader Maven / Gradle / Ivy
Show all versions of gemfire-core Show documentation
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.cache.util;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import java.util.Properties;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.AttributesMutator;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheLoaderException;
import com.gemstone.gemfire.cache.Declarable;
import com.gemstone.gemfire.cache.LoaderHelper;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.client.internal.BridgePoolImpl;
import com.gemstone.gemfire.cache.client.internal.ServerProxy;
import com.gemstone.gemfire.cache.query.SelectResults;
import com.gemstone.gemfire.internal.cache.tier.ConnectionProxy;
import com.gemstone.gemfire.internal.concurrent.AI;
import com.gemstone.gemfire.internal.concurrent.CFactory;
/**
* A CacheLoader
that loads data from one or more remote
* cacheserver
processes. This allows for a hierarchical caching
* scheme in which one cache ('client' cache) delegates a request to another
* cache ('server' cache) when it cannot find the data locally.
*
*
* When using the BridgeLoader
, at least two GemFire Caches must
* be running in a client/server mode (they should not be part of the same
* distributed system).
*
* The 'server' cache must be running a gemfire cacheserver
* process, while the 'client' cache must have a BridgeLoader
* installed in one or more of its Regions
. If a
* BridgeLoader
is defined in a client Region
,
* there must also be a Region
defined in the 'server' cache with
* the same exact name.
*
*
*
* The BridgeLoader
performs get()
operations on
* the remote server cache, and does not provide the distribution behavior that
* can be enabled by using a DISTRIBUTED
or
* DISTRIBUTED_NO_ACK
Region
. This mechanism is
* designed as a more targeted alternative to netSearch, in which the 'client'
* cache completely delegates the loading of the data to the 'server' cache if
* it is not yet cached in the client. This directed behavior enables a remote
* network get()
operation to be performed much more efficiently
* in a scenario where there is a hierarchical cache topology. Updates and
* invalidation remain local, in fact the Regions
that are used
* for this loosely coupled cache may even be LOCAL
in scope.
*
* The BridgeLoader
may be used to configure caches with
* multi-layer hierarchies.
*
*
*
* Load Balancing:
*
* The BridgeLoader
supports these load balancing mechanisms
* (specified by the LBPolicy
config attribute):
*
*
* - Sticky
* In this mode, the client loader picks the first server from the list of
* servers and establishes a connection to it. Once this connection has been
* established, every request from that particular 'client' cache is sent on
* that connection. If requests time out or produce exceptions, the
* BridgeLoader
picks another server and then sends further
* requests to that server. This achieves a level of load balancing by
* redirecting requests away from servers that produce timeouts.
*
* - RandomSticky
* The behavior is the same as Sticky, however the initial assignment of the
* connection is randomly selected from the list of servers.
*
* - RoundRobin
* In this mode, the client establishes connections to all the servers in the
* server list and then randomly picks a server for each given request. For the
* next request, it picks the next server in the list.
*
* - Random :
* In this mode, the edge establishes connections to all the servers in the
* server list and then randomly picks a server for every request.
*
*
*
*
*
* Failover:
*
*
* If a remote server cache throws an exception or times out, the client will
* retry based on the configured retryCount
parameter. If the
* retryCount
is exceeded, the server in question will be added
* to a failed server list, and the client will select another server to connect
* to. The servers in the failed server list will be periodically pinged with an
* intelligent ping that ensures cache health. If a server is determined to be
* healthy again, it will be promoted back to the healthy server list. The time
* period between failed server pings is configurable via the
* retryInterval
parameter.
*
*
* Configuration:
*
* The BridgeLoader
is configurable declaratively or
* programmatically. Declarative configuration is achieved through defining the
* configuration parameters in a cache.xml
file. Programmatic
* configuration may be achieved by first instantiating a
* BridgeLoader
object and subsequently calling
* {@link #init(Properties)}with a Properties
object containing
* each desired parameter and value.
*
* The supported parameters are:
*
*
* - endpoints (required)
* A comma delimited list of logical names, hostnames, and ports of 'server'
* caches to connect to
* The endpoints parameter follows this syntax:
* logicalName=host:port,logicalName2=host2:port2,....
* Example:
*
*
*
* <parameter name="endpoints">
* <string>MyPrimaryServer=hostsrv:40404,MySecondary=hostsrv2:40404</string>
* </parameter>
*
*
*
*
* - readTimeout (optional: default 10000)
* A millisecond value representing the amount of time to wait for a response
* from a cache server.
* Example:
*
*
*
* <parameter name="readTimeout">
* <string>5000</string>
* </parameter>
*
*
*
*
* - retryAttempts (optional: default 5)
* The number of times to retry a request after timeout/exception.
* Example:
*
*
*
* <parameter name="retryAttempts">
* <string>5</string>
* </parameter>
*
*
*
*
* - retryInterval (optional: default 10000)
* A millisecond value representing the amount of time to wait between attempts
* by the ServerMonitor
to ping living servers to verify that
* they are still alive and dead servers to verify that they are still dead.
*
* Example:
*
*
*
* <parameter name="retryInterval">
* <string>10000</string>
* </parameter>
*
*
*
* LBPolicy (optional: default "Sticky")
* A String value representing the load balancing policy to use. See above for
* more details.
* Options are:
*
* - "Sticky"
* - "RandomSticky"
* - "RoundRobin"
* - "Random"
*
* Example:
*
*
*
* <parameter name="LBPolicy">
* <string>Sticky</string>
* </parameter>
*
*
*
*
* connectionsPerServer (optional: default 1)
* The number of initial connections created to each time it is
* determined to be alive.
* The minimum of 0
causes no initial connections to be created (they are only created on demand).
*
* Example:
*
*
*
* <parameter name="connectionsPerServer">
* <string>10</string>
* </parameter>
*
*
*
*
* socketBufferSize (optional: default 32768)
* The size of the socket buffers in bytes.
* Example:
*
*
*
* <parameter name="socketBufferSize">
* <string>32768</string>
* </parameter>
*
*
*
*
*
*
*
*
* If you are using a cache.xml
file to create a
* Region
declaratively, you can include the following
* <cache-loader> definition to associate a BridgeLoader
* with a Region
(default values shown for optional parameters):
*
*
*
* <cache-loader>
* <class-name>com.gemstone.gemfire.cache.util.BridgeLoader</class-name>
* <parameter name="endpoints">
* <string>MyHost=ninja.gemstone.com:40404</string>
* </parameter>
* <parameter name="readTimeout">
* <string>10000</string>
* </parameter>
* <parameter name="retryAttempts">
* <string>5</string>
* </parameter>
* <parameter name="retryInterval">
* <string>10000</string>
* </parameter>
* <parameter name="LBPolicy">
* <string>Sticky</string>
* </parameter>
* <parameter name="socketBufferSize">
* <string>32768</string>
* </parameter>
* </parameter>
* </cache-loader>
*
*
* @since 2.0.2
* @author Greg Passmore
* @deprecated as of 5.7 use {@link com.gemstone.gemfire.cache.client pools} instead.
*/
@Deprecated
public class BridgeLoader implements CacheLoader, Declarable
{
ConnectionProxy proxy = null; // package access for
// tests/com/gemstone/gemfire/cache/util/BridgeHelper
private Properties properties;
public BridgeLoader() { }
/**
* Creates a loader from an existing BridgeWriter
. This
* method reuses the existing BridgeWriter
's proxy.
*
* @param bw
* The existing BridgeWriter
*
* @since 5.7
*/
public BridgeLoader(BridgeWriter bw) {
init(bw);
}
private LogWriterI18n logger = null;
private volatile boolean isClosed = false;
private final AI refCount = CFactory.createAI();
/**
* Initializes the loader with supplied config parameters. If instantiating
* the loader programmatically, this method must be called with a
* Properties
object that at a minimum contains the 'endpoints'
* parameter before the loader can be used. If a LicenseException is thrown
* during initialization the BridgeLoader will trhow IllegalStateExceptions
* until properly initialized.
*
* @param p
* configuration data such as 'endpoint' definitions
* @throws IllegalStateException if the loader is already initialized
*/
public void init(Properties p)
{
if (this.proxy != null) throw new IllegalStateException(LocalizedStrings.BridgeLoader_ALREADY_INITIALIZED.toLocalizedString());
this.properties = p;
if (Boolean.getBoolean("skipConnection")) {
// used by hydra when generating XML via RegionAttributesCreation
return;
}
this.proxy = BridgePoolImpl.create(properties, false/*useByBridgeWriter*/);
}
/**
* Initializes this loader from an existing BridgeLoader
.
* This method reuses the existing BridgeLoader
's connections
* to the server.
*
* @param bridgeLoader The existing BridgeLoader
* @throws IllegalStateException if the loader is already initialized
*
* @since 4.2
*/
public void init(BridgeLoader bridgeLoader)
{
if (this.proxy != null) throw new IllegalStateException(LocalizedStrings.BridgeLoader_ALREADY_INITIALIZED.toLocalizedString());
ConnectionProxy p = bridgeLoader.proxy;
p.reuse();
this.proxy = p;
}
/**
* Initializes this loader from an existing BridgeWriter
. This
* method reuses the existing BridgeWriter
's proxy.
*
* @param bridgeWriter
* The existing BridgeWriter
* @throws IllegalStateException if the loader is already initialized
*
* @since 5.7
*/
public void init(BridgeWriter bridgeWriter)
{
if (this.proxy != null) throw new IllegalStateException("Already initialized");
ConnectionProxy p = bridgeWriter.proxy;
p.reuse();
this.proxy = p;
}
/**
* Ensure that the ConnectionProxyImpl class gets loaded.
*
* @see SystemFailure#loadEmergencyClasses()
*/
public static void loadEmergencyClasses() {
BridgePoolImpl.loadEmergencyClasses();
}
/**
* Called when the region containing this BridgeLoader
is
* destroyed, when the {@link Cache}is closed, or when a callback is removed
* from a region using an {@link AttributesMutator}
*
* Closes connections to {@link BridgeServer}s when all {@link Region}s are
* finished using this BridgeLoader,
*
* @see #detach(Region)
* @see #attach(Region)
*/
public void close() {
if (this.refCount.get() <= 0) {
this.isClosed = true;
proxy.close();
}
}
/**
* Returns true if this BridgeLoader
has been closed.
*/
public boolean isClosed() {
return this.isClosed;
}
/**
* For speed optimizations, a connection to a server may be assigned to the
* calling thread when load is called. When the application thread is done
* doing its work it should invoke the BridgeLoader close method. This frees
* up the connection assigned to the application thread.
*/
public void release()
{
proxy.release();
}
/**
* This method should be invoked when the BridgeLoader mechanism is to be shut
* down explicitly , outside of closing the cache.
*/
public void terminate()
{
this.isClosed = true;
proxy.terminate();
}
// removed checkForTransaction
/**
* This method is invoked implicitly when an object requested on the client
* cache cannot be found. The server cache will attempt to be contacted, and
* if no server cache is available (or healthy) a CacheLoaderException will
* be thrown.
*
*/
public Object load(LoaderHelper helper) throws CacheLoaderException
{
throw new IllegalStateException("this method should not be called");
}
private void checkClosed() {
String reason = this.proxy.getCancelCriterion().cancelInProgress();
if(reason != null) {
throw new BridgeWriterException("The BridgeWriter has been closed: " + reason);
}
if (this.isClosed) {
throw new CacheLoaderException(LocalizedStrings.BridgeLoader_THE_BRIDGELOADER_HAS_BEEN_CLOSED.toLocalizedString());
}
if (this.proxy != null && !this.proxy.isOpen()) {
throw new CacheLoaderException(LocalizedStrings.BridgeLoader_THE_BRIDGELOADER_HAS_BEEN_CLOSED.toLocalizedString());
}
}
/**
* Invoke a query on the cache server.
* @deprecated use {@link Region#query} instead
*/
@Deprecated
public SelectResults query(String queryStr) throws CacheLoaderException {
ServerProxy sp = new ServerProxy((BridgePoolImpl)this.proxy);
return sp.query(queryStr, null);
}
/**
* Returns the retry interval in use. Retry interval refers to the interval at
* which dead servers are attempted to be reconnected. Internal use only.
*/
public int getRetryInterval()
{
return proxy.getRetryInterval();
}
/**
* Returns the read timeout being used to time out requests to the server
* Internal use only.
*/
public int getReadTimeout()
{
return proxy.getReadTimeout();
}
/**
* Returns the number of times the bridge loader tries to get data on
* encountering certain types of exceptions. Internal use only
*/
public int getRetryAttempts()
{
return this.proxy.getRetryAttempts();
}
/**
* Returns the load balancing policy being used by the bridge loader Internal
* use only
*/
public String getLBPolicy()
{
return proxy.getLBPolicy();
}
/**
* Returns the properties that defined this BridgeWriter
.
*
* @return the properties that defined this BridgeWriter
*
* @since 4.2
*/
public Properties getProperties()
{
return this.properties;
}
/**
* Returns the ConnectionProxy
associated with this
* BridgeLoader
.
*
* For internal use only.
*
* @return the ConnectionProxy
associated with this
* BridgeLoader
*/
public Object/*ConnectionProxy*/ getConnectionProxy()
{
return proxy;
}
/**
* Add an Endpoint
to the known Endpoint
s.
*
* @param name The name of the endpoint to add
* @param host The host name or ip address of the endpoint to add
* @param port The port of the endpoint to add
*
* @throws EndpointExistsException if the Endpoint
to be
* added already exists.
*
* @since 5.0.2
*/
public void addEndpoint(String name, String host, int port)
throws EndpointExistsException {
this.proxy.addEndpoint(name, host, port);
}
/**
* Remove an Endpoint
from the dead Endpoint
s.
* The specified Endpoint
must be dead.
*
* @param name The name of the endpoint to remove
* @param host The host name or ip address of the endpoint to remove
* @param port The port of the endpoint to remove
*
* @throws EndpointDoesNotExistException if the Endpoint
to be
* removed doesn't exist.
*
* @throws EndpointInUseException if the Endpoint
to be removed
* contains Connection
s
*
* @since 5.0.2
*/
public void removeEndpoint(String name, String host, int port)
throws EndpointDoesNotExistException, EndpointInUseException {
this.proxy.removeEndpoint(name, host, port);
}
// removed handleException
// removed getExceptionMessage
/**
* Returns a brief description of this BridgeLoader
*
* @since 4.0
*/
@Override
public String toString()
{
return LocalizedStrings.BridgeLoader_BRIDGELOADER_CONNECTED_TO_0.toLocalizedString(this.proxy);
}
/**
* Notify the BridgeLoader that the given region is no longer relevant. This
* method is used internally during Region
* {@link Region#destroyRegion() destruction}and
* {@link Region#close() closure}. This method effects the behavor of
* {@link #close()}.
*
* @param r
* the Region which will no longer use this BridgeLoader
* @see #close()
* @see #attach(Region)
* @since 4.3
*/
public void detach(Region r)
{
this.refCount.decrementAndGet();
}
/**
* Notify the BridgeLoader that the given Region will begin calling
* {@link #load(LoaderHelper)}.
*
* This method affects the behavior of {@link #close()}.
*
* This is called internally when the BridgeLoader is added to a Region via
* {@link AttributesFactory#setCacheLoader(CacheLoader)}
*
* @param r
* the Region which will begin use this BridgeWriter.
* @since 4.3
*
* @see #detach(Region)
* @see #close()
*/
public void attach(Region r)
{
checkClosed();
this.refCount.incrementAndGet();
}
protected LogWriterI18n getLoggerI18n() {
if (this.logger == null)
this.logger = CacheFactory.getAnyInstance().getLoggerI18n();
return this.logger;
}
}