com.gemstone.gemfire.cache.util.BridgeWriter 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.CacheFactory;
import com.gemstone.gemfire.cache.CacheWriter;
import com.gemstone.gemfire.cache.CacheWriterException;
import com.gemstone.gemfire.cache.Declarable;
import com.gemstone.gemfire.cache.EntryEvent;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionEvent;
import com.gemstone.gemfire.cache.client.internal.BridgePoolImpl;
import com.gemstone.gemfire.internal.cache.tier.ConnectionProxy;
import com.gemstone.gemfire.internal.concurrent.AI;
import com.gemstone.gemfire.internal.concurrent.CFactory;
/**
* A CacheWriter
that writes data to 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 using the BridgeWriter
, at least two GemFire Caches must
* exist 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 BridgeWriter
* installed in one or more of its Regions
. If a
* BridgeWriter
is defined in a client Region
,
* there must also be a Region
defined in the 'server' cache with
* the same exact name.
*
*
*
* The BridgeWriter
performs put()
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 put()
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 BridgeWriter
may be used to configure caches with
* multi-layer hierarchies.
*
*
*
* Load Balancing:
*
* The BridgeWriter
supports these load balancing mechanisms
* (specified by the LBPolicy
config attribute):
*
*
* - Sticky
* In this mode, the client writer 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
* BridgeWriter
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 BridgeWriter
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
* BridgeWriter
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>
*
*
*
*
* establishCallbackConnection (optional: default false)
* Instruct the server to make a connection back to this edge client through
* which the client receives cache updates.
* Example:
*
*
*
* <parameter name="establishCallbackConnection">
* <string>true</string>
* </parameter>
*
*
*
*
*
* redundancyLevel (optional: default 0)
* The number of secondary servers set for backup to the primary server for the
* high availability of client queue.
* Example:
*
*
*
* <parameter name="redundancyLevel">
* <string>1</string>
* </parameter>
*
*
*
*
*
* socketBufferSize (optional: default 32768)
* The size of the socket buffers in bytes.
* Example:
*
*
*
* <parameter name="socketBufferSize">
* <string>32768</string>
* </parameter>
*
*
*
*
*
* messageTrackingTimeout (optional: default 300000 milliseconds)
*
* messageTrackingTimeout property specifies the time-to-live period, in
* milliseconds, for entries in the client's message tracking list, to minimize
* duplicate events. Entries that have not been modified for this amount of time
* are expired from the list
* Example:
*
*
*
* <parameter name="messageTrackingTimeout">
* <string>300000</string>
* </parameter>
*
*
*
*
* clientAckInterval (optional: default 500 milliseconds)
* Bridge client sends an acknowledgement to its primary server for the events
* it has got after every ClientAckInterval time.Client will send an ack to the
* primary server only when redundancy level is greater than 0 or -1.
* Example:
*
*
*
* <parameter name="clientAckInterval">
* <string>5000</string>
* </parameter>
*
*
*
*
*
*
*
*
* If you are using a cache.xml
file to create a
* Region
declaratively, you can include the following to
* associate a BridgeWriter
with a Region
(default
* values shown for optional parameters):
*
*
*
* <cache-writer>
* <classname>com.gemstone.gemfire.cache.util.BridgeWriter</classname>
* <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="establishCallbackConnection">
* <string>false</string>
* </parameter>
* <parameter name="socketBufferSize">
* <string>32768</string>
* </parameter>
* </parameter>
* <parameter name="messageTrackingTimeout">
* <string>300000</string>
* </parameter>
* </parameter>
* </parameter>
* <parameter name="clientAckInterval">
* <string>5000</string>
* </parameter>
* </cache-writer>
*
*
* @since 3.5
* @author Barry Oglesby
* @deprecated as of 5.7 use {@link com.gemstone.gemfire.cache.client pools} instead.
*/
@Deprecated
public class BridgeWriter implements CacheWriter, Declarable
{
protected ConnectionProxy proxy = null; // package access for
// tests/com/gemstone/gemfire/cache/util/BridgeHelper
private Properties properties;
private LogWriterI18n logger = null;
private volatile boolean isClosed = false;
private final AI refCount = CFactory.createAI();
// all writers logic was moved to ConnectionProxyImpl
/**
* Initializes the writer with supplied config parameters. If instantiating
* the writer programmatically, this method must be called with a
* Properties
object that at a minimum contains the 'endpoints'
* parameter before the writer can be used. If init fails with a
* LicenseException, the resulting BridgeWriter will throw
* IllegalStateException until it is properly initialized.
*
* @param p configuration data such as 'endpoint' definitions
* @throws IllegalStateException if the writer is already initialized
*/
public void init(Properties p)
{
if (this.proxy != null) throw new IllegalStateException(LocalizedStrings.BridgeWriter_ALREADY_INITIALIZED.toLocalizedString());
this.properties = p;
if (Boolean.getBoolean("skipConnection")) {
// used by hydra when generating XML via RegionAttributesCreation
return;
}
this.proxy = BridgePoolImpl.create(properties, true/*useByBridgeWriter*/);
}
/**
* Initializes this writer from an existing BridgeWriter
. This
* method reuses the existing BridgeWriter
's proxy.
*
* @param bridgeWriter
* The existing BridgeWriter
* @throws IllegalStateException if the writer is already initialized
*
* @since 4.2
*/
public void init(BridgeWriter bridgeWriter)
{
if (this.proxy != null) throw new IllegalStateException(LocalizedStrings.BridgeWriter_ALREADY_INITIALIZED.toLocalizedString());
ConnectionProxy p = bridgeWriter.proxy;
p.reuse();
this.proxy = p;
}
/**
* Ensure that the BridgeClient and BridgePoolImpl classes
* get loaded.
*
* @see SystemFailure#loadEmergencyClasses()
*/
public static void loadEmergencyClasses() {
BridgeClient.loadEmergencyClasses(); // make sure subclass is taken care of
BridgePoolImpl.loadEmergencyClasses();
}
// emergency logic was moved to ConnectionProxyImpl
/**
* Called when a region using this BridgeWriter
is destroyed,
* when the cache is closed, or when a callback is removed from a region using
* an {@link AttributesMutator}.
*
* Closes connections to {@link BridgeServer BridgeServers}when all
* {@link Region Regions}are finished using this BridgeWriter,
*
*
* @see #attach(Region)
* @see #detach(Region)
*/
public void close()
{
if (this.refCount.get() <= 0) {
this.isClosed = true;
this.proxy.close();
}
}
// handleMarker moved to ConnectionProxyImpl
/**
* Returns true if this BridgeWriter
has been closed.
*/
public boolean isClosed() {
return this.isClosed;
}
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 BridgeWriterException(LocalizedStrings.BridgeWriter_THE_BRIDGEWRITER_HAS_BEEN_CLOSED.toLocalizedString());
}
if (this.proxy != null && !this.proxy.isOpen()) {
throw new BridgeWriterException(LocalizedStrings.BridgeWriter_THE_BRIDGEWRITER_HAS_BEEN_CLOSED.toLocalizedString());
}
}
/**
* Notify the BridgeWriter 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()}.
*
* @see #attach(Region)
* @see #close()
* @param r
* the Region which will no longer use this BridgeWriter
* @since 4.3
*/
public void detach(Region r)
{
this.refCount.decrementAndGet();
if (r != null) {
this.proxy.detachRegion(r);
}
// close(); // only closes if refCount is zero
}
/**
* Returns the number of attaches that have not yet called detach.
* @since 5.7
*/
public int getAttachCount() {
return this.refCount.get();
}
/**
* For speed optimizations, a connection to a server may be assigned to the
* calling thread when the BridgeWriter is used to do an operation.
* When the application thread is done doing its work it can invoke
* the BridgeWriter release method to make the connection available
* to other application threads.
*/
public void release()
{
proxy.release();
}
/**
* This method should be invoked when the BridgeWriter mechanism is to be shut
* down explicitly , outside of closing the cache.
*/
public void terminate()
{
this.isClosed = true;
proxy.terminate();
}
// removed checkForTransaction
/**
* Called before an entry is updated. The entry update is initiated by a
* put
or a get
that causes the writer to update
* an existing entry. The entry previously existed in the cache where the
* operation was initiated, although the old value may have been null. The
* entry being updated may or may not exist in the local cache where the
* CacheWriter is installed.
*
* @param event
* an EntryEvent that provides information about the operation in
* progress
* @throws CacheWriterException
* if thrown will abort the operation in progress, and the exception
* will be propagated back to caller that initiated the operation
* @see Region#put(Object, Object)
* @see Region#get(Object)
*/
public void beforeUpdate(EntryEvent event) throws CacheWriterException
{
throw new IllegalStateException("this method should not be called");
}
/**
* Called before an entry is created. Entry creation is initiated by a
* create
, a put
, or a get
.
* The CacheWriter
can determine whether this value comes from
* a get
or not from {@link EntryEvent#isLoad}. The entry
* being created may already exist in the local cache where this
* CacheWriter
is installed, but it does not yet exist in the
* cache where the operation was initiated.
*
* @param event
* an EntryEvent that provides information about the operation in
* progress
* @throws CacheWriterException
* if thrown will abort the operation in progress, and the exception
* will be propagated back to caller that initiated the operation
* @see Region#create(Object, Object)
* @see Region#put(Object, Object)
* @see Region#get(Object)
*/
public void beforeCreate(EntryEvent event) throws CacheWriterException
{
throw new IllegalStateException("this method should not be called");
}
/**
* Called before an entry is destroyed. The entry being destroyed may or may
* not exist in the local cache where the CacheWriter is installed. This
* method is not called as a result of expiration or
* {@link Region#localDestroy(Object)}.
*
* @param event
* an EntryEvent that provides information about the operation in
* progress
* @throws CacheWriterException
* if thrown will abort the operation in progress, and the exception
* will be propagated back to caller that initiated the operation
*
* @see Region#destroy(Object)
*/
public void beforeDestroy(EntryEvent event) throws CacheWriterException
{
throw new IllegalStateException("this method should not be called");
}
/**
* Called before a region is destroyed. The CacheWriter
will
* not additionally be called for each entry that is destroyed in the region
* as a result of a region destroy. If the region's subregions have
* CacheWriter
s installed, then they will be called for the
* cascading subregion destroys. This method is not called as a
* result of expiration or {@link Region#localDestroyRegion()}. However, the
* {@link #close}method is invoked regardless of whether a region is
* destroyed locally. A non-local region destroy results in an invocation of
* {@link #beforeRegionDestroy}followed by an invocation of {@link #close}.
*
* WARNING: This method should not destroy or create any regions itself or a
* deadlock will occur.
*
* @param event
* a RegionEvent that provides information about the
*
* @throws CacheWriterException
* if thrown, will abort the operation in progress, and the
* exception will be propagated back to the caller that initiated
* the operation
*
* @see Region#destroyRegion()
*/
public void beforeRegionDestroy(RegionEvent event)
throws CacheWriterException
{
throw new IllegalStateException("this method should not be called");
}
/**
* Called before a region is cleared. The CacheWriter
will
* not additionally be called for each entry that is cleared in the region
* as a result of a region clear. If the region's subregions have
* CacheWriter
s installed, then they will be called for the
* cascading subregion clears. This method is not called as a
* result of expiration or {@link Region#localDestroyRegion()}. However, the
* {@link #close}method is invoked regardless of whether a region is
* cleared locally. A non-local region clear results in an invocation of
* {@link #beforeRegionClear}followed by an invocation of {@link #close}.
*
* WARNING: This method should not destroy or create or clear any regions itself or a
* deadlock will occur.
*
* @param event
* a RegionEvent that provides information about the
*
* @throws CacheWriterException
* if thrown, will abort the operation in progress, and the
* exception will be propagated back to the caller that initiated
* the operation
*
*/
public void beforeRegionClear(RegionEvent event) throws CacheWriterException
{
throw new IllegalStateException("this method should not be called");
}
/**
* Return true if this writer has not been closed and it was configured to
* establish a callback connection.
*
* @since 4.3
*/
public boolean hasEstablishCallbackConnection()
{
if (this.isClosed) {
return false;
}
else {
return this.proxy.getEstablishCallbackConnection();
}
}
// removed unregisterInterest
// removed getInterestList
// removed getObjectFromPrimaryServer
// removed keySet
// removed containsKey
/** 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 writer tries to write 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 writer 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;
}
/**
* 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);
}
protected LogWriterI18n getLoggerI18n() {
if (logger == null)
logger = CacheFactory.getAnyInstance().getLoggerI18n();
return logger;
}
// removed handleException
// removed getExceptionMessage
/**
* Returns a brief description of this BridgeWriter
*
* @since 4.0
*/
@Override
public String toString()
{
return LocalizedStrings.BridgeWriter_BRIDGEWRITER_CONNECTED_TO_0.toLocalizedString(this.proxy);
}
/**
* Notify the BridgeWriter that the given Region will begin delivering events
* to this BridgeWriter. This method effects the behavior of {@link #close()}
*
* This is called internally when the BridgeWriter is added to a Region via
* {@link AttributesFactory#setCacheWriter(CacheWriter)}}
*
* @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();
}
/**
* Returns the ConnectionProxy
associated with this
* BridgeWriter
.
*
* For internal use only.
*
* @return the ConnectionProxy
associated with this
* BridgeWriter
*/
public Object/*ConnectionProxy*/ getConnectionProxy() {
return proxy;
}
}