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

com.gemstone.gemfire.cache.util.BridgeWriter Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * 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 Endpoints. * * @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 Endpoints. * 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 Connections * * @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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy