com.gemstone.gemfire.internal.cache.tier.sockets.CacheClientUpdater 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.internal.cache.tier.sockets;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.SSLException;
import com.gemstone.gemfire.CancelException;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.InvalidDeltaException;
import com.gemstone.gemfire.StatisticDescriptor;
import com.gemstone.gemfire.Statistics;
import com.gemstone.gemfire.StatisticsType;
import com.gemstone.gemfire.StatisticsTypeFactory;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.EntryNotFoundException;
import com.gemstone.gemfire.cache.InterestResultPolicy;
import com.gemstone.gemfire.cache.Operation;
import com.gemstone.gemfire.cache.RegionDestroyedException;
import com.gemstone.gemfire.cache.client.ServerRefusedConnectionException;
import com.gemstone.gemfire.cache.client.internal.ClientUpdater;
import com.gemstone.gemfire.cache.client.internal.Endpoint;
import com.gemstone.gemfire.cache.client.internal.EndpointManager;
import com.gemstone.gemfire.cache.client.internal.GetEventValueOp;
import com.gemstone.gemfire.cache.client.internal.PoolImpl;
import com.gemstone.gemfire.cache.client.internal.QueueManager;
import com.gemstone.gemfire.cache.query.internal.CqService;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.DistributionManager;
import com.gemstone.gemfire.distributed.internal.DistributionStats;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.DisconnectListener;
import com.gemstone.gemfire.distributed.internal.ServerLocation;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.distributed.internal.membership.MemberAttributes;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.Assert;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.InternalInstantiator;
import com.gemstone.gemfire.internal.LogWriterImpl;
import com.gemstone.gemfire.internal.SocketCreator;
import com.gemstone.gemfire.internal.StatisticsTypeFactoryImpl;
import com.gemstone.gemfire.internal.cache.BridgeObserver;
import com.gemstone.gemfire.internal.cache.BridgeObserverHolder;
import com.gemstone.gemfire.internal.cache.BridgeServerImpl;
import com.gemstone.gemfire.internal.cache.EntryEventImpl;
import com.gemstone.gemfire.internal.cache.EventID;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.cache.tier.CachedRegionHelper;
import com.gemstone.gemfire.internal.cache.tier.MessageType;
import com.gemstone.gemfire.internal.cache.versions.ConcurrentCacheModificationException;
import com.gemstone.gemfire.internal.cache.versions.VersionSource;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.sequencelog.EntryLogger;
import com.gemstone.gemfire.internal.shared.Version;
import com.gemstone.gemfire.security.AuthenticationFailedException;
import com.gemstone.gemfire.security.AuthenticationRequiredException;
import com.gemstone.gemfire.security.GemFireSecurityException;
/**
* CacheClientUpdater
is a thread that processes update messages
* from a cache server and
* {@linkplain com.gemstone.gemfire.cache.Region#localInvalidate(Object) invalidates}
* the local cache based on the contents of those messages.
*
* @author Barry Oglesby
* @since 3.5
*/
public class CacheClientUpdater extends Thread implements ClientUpdater,
DisconnectListener {
/**
* true if the constructor successfully created a connection. If false, the
* run method for this thread immediately exits.
*/
private final boolean connected;
/**
* System of which we are a part
*/
private final InternalDistributedSystem system;
/**
* The socket by which we communicate with the server
*/
private final Socket socket;
/**
* The output stream of the socket
*/
private final OutputStream out;
/**
* The input stream of the socket
*/
private final InputStream in;
/**
* Failed updater from the endpoint previously known as the primary
*/
private volatile ClientUpdater failedUpdater;
/**
* The buffer upon which we receive messages
*/
private final ByteBuffer commBuffer;
private final CCUStats stats;
/**
* Cache for which we provide service
*/
private /*final*/ GemFireCacheImpl cache;
private /*final*/ LogWriterI18n logger;
private /*final*/ CachedRegionHelper cacheHelper;
/**
* Principle flag to signal thread's run loop to terminate
*/
private volatile boolean continueProcessing = true;
/**
* Is the client durable
* Used for bug 39010 fix
*/
private final boolean isDurableClient;
/**
* Represents the server we are connected to
*/
private final InternalDistributedMember serverId;
/**
* true if the EndPoint represented by this updater thread is primary
*/
private final boolean isPrimary;
/**
* Added to avoid recording of the event if the concerned operation failed.
* See #43247
*/
private boolean isOpCompleted;
public final static String CLIENT_UPDATER_THREAD_NAME = "Cache Client Updater Thread ";
/*
* to enable test flag
*/
public static boolean isUsedByTest;
/**
* Indicates if full value was requested from server as a result of failure in
* applying delta bytes.
*/
public static boolean fullValueRequested = false;
// /**
// * True if this thread been initialized. Indicates that the run thread is
// * initialized and ready to process messages
// *
// * TODO is this still needed?
// *
// * Accesses synchronized via this
// *
// * @see #notifyInitializationComplete()
// * @see #waitForInitialization()
// */
// private boolean initialized = false;
private final ServerLocation location;
// TODO - remove these fields
private QueueManager qManager = null;
private EndpointManager eManager = null;
private Endpoint endpoint = null;
static private final long MAX_CACHE_WAIT =
Long.getLong("gemfire.CacheClientUpdater.MAX_WAIT", 120).longValue(); // seconds
/**
* Return true if cache appears
* @return true if cache appears
*/
private boolean waitForCache() {
GemFireCacheImpl c;
long tilt = System.currentTimeMillis() + MAX_CACHE_WAIT * 1000;
for (;;) {
if (quitting()) {
logger.warning(
LocalizedStrings.CacheClientUpdater_0_ABANDONED_WAIT_DUE_TO_CANCELLATION, this);
return false;
}
if (!this.connected) {
logger.warning(
LocalizedStrings.CacheClientUpdater_0_ABANDONED_WAIT_BECAUSE_IT_IS_NO_LONGER_CONNECTED,
this);
return false;
}
if (System.currentTimeMillis() > tilt) {
logger.warning(
LocalizedStrings.CacheClientUpdater_0_WAIT_TIMED_OUT_MORE_THAN_1_SECONDS,
new Object[] { this,MAX_CACHE_WAIT });
return false;
}
c = GemFireCacheImpl.getInstance();
if (c != null && !c.isClosed()) {
break;
}
boolean interrupted = Thread.interrupted();
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
interrupted = true;
}
finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
} // for
this.cache = c;
this.cacheHelper = new CachedRegionHelper(c);
this.logger = c.getLoggerI18n();
return true;
}
/**
* Creates a new CacheClientUpdater
with a given name that
* waits for a server to connect on a given port.
*
* @param name
* descriptive name, used for our ThreadGroup
* @param location
* the endpoint we represent
* @param primary
* true if our endpoint is primary TODO ask the ep for this?
* @param ids
* the system we are distributing messages through
*
* @throws AuthenticationRequiredException
* when client is not configured to send credentials using
* security-* system properties but server expects credentials
* @throws AuthenticationFailedException
* when authentication of the client fails
* @throws ServerRefusedConnectionException
* when handshake fails for other reasons like using durable
* client ID that is already in use by another client or some
* server side exception while reading handshake/verifying
* credentials
*/
public CacheClientUpdater(
String name, ServerLocation location,
boolean primary, DistributedSystem ids,
HandShake handshake, QueueManager qManager, EndpointManager eManager,
Endpoint endpoint, int handshakeTimeout) throws AuthenticationRequiredException,
AuthenticationFailedException, ServerRefusedConnectionException {
super(LogWriterImpl.createThreadGroup("Client update thread", (LogWriterI18n)null), name);
this.logger = qManager.getLogger();
this.setDaemon(true);
this.system = (InternalDistributedSystem)ids;
this.isDurableClient = handshake.getMembership().isDurable();
this.isPrimary = primary;
this.location = location;
this.qManager = qManager;
this.eManager = eManager;
this.endpoint = endpoint;
this.stats = new CCUStats(this.system, this.location);
// Create the connection...
if (logger.fineEnabled()) {
logger.fine("Creating asynchronous update connection");
}
boolean success = false;
Socket mySock = null;
InternalDistributedMember sid = null;
ByteBuffer cb = null;
OutputStream tmpOut = null;
InputStream tmpIn = null;
try {
/** Size of the server-to-client communication socket buffers */
int socketBufferSize = Integer.getInteger(
"BridgeServer.SOCKET_BUFFER_SIZE", 32768).intValue();
if (!SocketCreator.getDefaultInstance()
.isHostReachable(InetAddress.getByName(location.getHostName()))) {
throw new NoRouteToHostException("Server is not reachable: " + location.getHostName());
}
mySock = SocketCreator.getDefaultInstance().connectForClient(
location.getHostName(), location.getPort(), logger, handshakeTimeout, socketBufferSize);
mySock.setTcpNoDelay(true);
mySock.setSendBufferSize(socketBufferSize);
// Verify buffer sizes
verifySocketBufferSize(socketBufferSize, mySock.getReceiveBufferSize(), "receive");
verifySocketBufferSize(socketBufferSize, mySock.getSendBufferSize(), "send");
// set the timeout for the handshake
mySock.setSoTimeout(handshakeTimeout);
tmpOut = mySock.getOutputStream();
tmpIn = mySock.getInputStream();
if (logger.fineEnabled()) {
logger.fine("Initialized server-to-client socket with send buffer size: "
+ mySock.getSendBufferSize() + " bytes and receive buffer size: "
+ mySock.getReceiveBufferSize() + " bytes");
}
if (logger.fineEnabled()) {
logger.fine("Created connection from "
+ mySock.getInetAddress().getHostAddress() + ":"
+ mySock.getLocalPort() + " to CacheClientNotifier on port "
+ mySock.getPort() + " for server-to-client communication");
}
handshake.greetNotifier(mySock, this.isPrimary, location);
{
int bufSize = 1024;
try {
bufSize = mySock.getSendBufferSize();
if (bufSize < 1024) {
bufSize = 1024;
}
}
catch (SocketException ignore) {
}
cb = ServerConnection.allocateCommBuffer(bufSize);
}
{
// create a "server" memberId we currently don't know much about the
// server.
// Would be nice for it to send us its member id
// @todo - change the serverId to use the endpoint's getMemberId() which
// returns a
// DistributedMember (once gfecq branch is merged to trunk).
MemberAttributes ma = new MemberAttributes(0, -1, DistributionManager.NORMAL_DM_TYPE, -1, null, null, null);
sid = new InternalDistributedMember(mySock.getInetAddress(), mySock.getPort(), false, true, ma);
}
success = true;
}
catch (ConnectException e) {
if (!quitting()) {
logger.warning( LocalizedStrings.CacheClientUpdater_0_CONNECTION_WAS_REFUSED, this);
}
}
catch (SSLException ex) {
if (!quitting()) {
getSecurityLogger().warning(
LocalizedStrings.CacheClientUpdater_0_SSL_NEGOTIATION_FAILED_1,
new Object[] { this, ex});
throw new AuthenticationFailedException(
LocalizedStrings.CacheClientUpdater_SSL_NEGOTIATION_FAILED_WITH_ENDPOINT_0
.toLocalizedString(location), ex);
}
}
catch (GemFireSecurityException ex) {
if (!quitting()) {
getSecurityLogger().warning(
LocalizedStrings.CacheClientUpdater_0_SECURITY_EXCEPTION_WHEN_CREATING_SERVERTOCLIENT_COMMUNICATION_SOCKET_1,
new Object[] {this, ex});
throw ex;
}
}
catch (IOException e) {
if (!quitting()) {
if (logger.warningEnabled()) {
logger.warning( LocalizedStrings.CacheClientUpdater_0_CAUGHT_FOLLOWING_EXECPTION_WHILE_ATTEMPTING_TO_CREATE_A_SERVER_TO_CLIENT_COMMUNICATION_SOCKET_AND_WILL_EXIT_1, new Object[] {this, e}, logger.fineEnabled() ? e : null);
}
}
eManager.serverCrashed(this.endpoint);
}
catch (ClassNotFoundException e) {
if (!quitting()) {
logger.warning( LocalizedStrings.CacheClientUpdater_CLASS_NOT_FOUND, e.getMessage());
}
}
finally {
connected = success;
if (mySock != null) {
try {
mySock.setSoTimeout(0);
} catch (SocketException e) {
// ignore: nothing we can do about this
}
}
if (connected) {
socket = mySock;
out = tmpOut;
in = tmpIn;
serverId = sid;
commBuffer = cb;
// Don't want the timeout after handshake
if (mySock != null) {
try {
mySock.setSoTimeout(0);
} catch (SocketException ignore) {
}
}
}
else {
socket = null;
serverId = null;
commBuffer = null;
out = null;
in = null;
if (mySock != null) {
try {
mySock.close();
}
catch (IOException ioe) {
logger.warning(LocalizedStrings.CacheClientUpdater_CLOSING_SOCKET_IN_0_FAILED, this, ioe);
}
}
}
}
}
public boolean isConnected() {
return connected;
}
public LogWriterI18n getSecurityLogger() {
return this.qManager.getSecurityLogger();
}
public LogWriterI18n getLogger() {
return this.qManager.getLogger();
}
public void setFailedUpdater(ClientUpdater failedUpdater) {
this.failedUpdater = failedUpdater;
}
/**
* Performs the work of the client update thread. Creates a
* ServerSocket
and waits for the server to connect to it.
*/
@Override
public void run() {
boolean addedListener = false;
EntryLogger.setSource(serverId, "RI");
try {
this.system.addDisconnectListener(this);
addedListener = true;
if (!waitForCache()) {
logger.warning(LocalizedStrings.CacheClientUpdater_0_NO_CACHE_EXITING, this);
return;
}
processMessages();
}
catch (CancelException e) {
return; // just bail
}
finally {
if (addedListener) {
this.system.removeDisconnectListener(this);
}
this.close();
EntryLogger.clearSource();
}
}
// /**
// * Waits for this thread to be initialized
// *
// * @return true if initialized; false if stopped before init
// */
// public boolean waitForInitialization() {
// boolean result = false;
// // Yogesh : waiting on this thread object is a bad idea
// // as when thread exits it notifies to the waiting threads.
// synchronized (this) {
// for (;;) {
// if (quitting()) {
// break;
// }
// boolean interrupted = Thread.interrupted();
// try {
// this.wait(100); // spurious wakeup ok // timed wait, should fix lost notification problem rahul.
// }
// catch (InterruptedException e) {
// interrupted = true;
// }
// finally {
// if (interrupted) {
// Thread.currentThread().interrupt();
// }
// }
// } // while
// // Even if we succeed, there is a risk that we were shut down
// // Can't check for cache; it isn't set yet :-(
// this.system.getCancelCriterion().checkCancelInProgress(null);
// result = this.continueProcessing;
// } // synchronized
// return result;
// }
// /**
// * @see #waitForInitialization()
// */
// private void notifyInitializationComplete() {
// synchronized (this) {
// this.initialized = true;
// this.notifyAll();
// }
// }
/**
* Notifies this thread to stop processing
*/
protected void stopProcessing() {
continueProcessing = false;
}
/**
* Stops the updater. It will wait for a while for the thread to finish to try
* to prevent duplicates. Note: this method is not named stop because this is
* a Thread which has a deprecated stop method.
*/
public void stopUpdater() {
boolean isSelfDestroying = Thread.currentThread() == this;
stopProcessing();
// need to also close the socket for this interrupt to wakeup
// the thread. This fixes bug 35691.
// this.close(); // this should not be done here.
if (this.isAlive()) {
if (logger.fineEnabled()) {
logger.fine(this.location + ": Stopping " + this);
}
if (!isSelfDestroying) {
interrupt();
try {
if (socket != null) {
socket.close();
}
}
catch (Throwable t) {
Error err;
if (t instanceof Error && SystemFailure.isJVMFailureError(
err = (Error)t)) {
SystemFailure.initiateFailure(err);
// If this ever returns, rethrow the error. We're poisoned
// now, so don't let this thread continue.
throw err;
}
// Whenever you catch Error or Throwable, you must also
// check for fatal JVM error (see above). However, there is
// _still_ a possibility that you are dealing with a cascading
// error condition, so you also need to check to see if the JVM
// is still usable:
SystemFailure.checkFailure();
// dont care...
if(logger.fineEnabled()){
logger.fine(t);
}
}
} // !isSelfDestroying
} // isAlive
}
/**
* Signals the run thread to stop, closes underlying resources.
*/
public void close() {
this.continueProcessing = false; // signals we are done.
// Close the socket
// This will also cause the underlying streams to fail.
try {
if (socket != null) {
socket.close();
}
} catch (Exception e) {
// ignore
}
try {
this.stats.close();
} catch (Exception e) {
// ignore
}
// close the helper
try {
if (cacheHelper != null) {
cacheHelper.close();
}
} catch (Exception e) {
// ignore
}
}
/**
* Creates a cached {@link Message}object whose state is filled in with a
* message received from the server.
*/
private Message initializeMessage() {
Message _message = new Message(2, Version.CURRENT);
_message.setLogger(logger);
try {
_message.setComms(socket, in, out, commBuffer, this.stats);
}
catch (IOException e) {
if (!quitting()) {
if (logger.fineEnabled()){
logger.fine(toString()
+ ": Caught following exception while attempting to initialize a server-to-client communication socket and will exit"
, e);
}
stopProcessing();
}
}
return _message;
}
/* refinement of method inherited from Thread */
@Override
public String toString() {
return this.getName() + " (" + this.location.getHostName() + ":"
+ this.location.getPort() + ")";
}
/**
* Handle a marker message
*
* @param m
* message containing the data
*/
private void handleMarker(Message m) {
try {
if (logger.fineEnabled()) {
logger.fine("Received marker message of length ("
+ m.getPayloadLength() + " bytes)");
}
this.qManager.getState().processMarker();
if (logger.fineEnabled()) {
logger.fine("Processed marker message");
}
} catch (Exception e) {
String message =
LocalizedStrings.CacheClientUpdater_THE_FOLLOWING_EXCEPTION_OCCURRED_WHILE_ATTEMPTING_TO_HANDLE_A_MARKER.toLocalizedString();
handleException(message, e);
}
}
/**
* Create or update an entry
*
* @param m
* message containing the data
*/
private void handleUpdate(Message m) {
String regionName = null;
Object key = null;
Part valuePart = null;
Object newValue = null;
byte[] deltaBytes = null;
Object fullValue = null;
boolean isValueObject = false;
int partCnt = 0;
try {
this.isOpCompleted = false;
// Retrieve the data from the put message parts
if (logger.fineEnabled()) {
logger.fine("Received put message of length (" + m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part keyPart = m.getPart(partCnt++);
boolean isDeltaSent = ((Boolean)m.getPart(partCnt++).getObject())
.booleanValue();
valuePart = m.getPart(partCnt++);
Part callbackArgumentPart = m.getPart(partCnt++);
VersionTag versionTag = (VersionTag)m.getPart(partCnt++).getObject();
if (versionTag != null) {
versionTag.replaceNullIDs((InternalDistributedMember) this.endpoint.getMemberId());
}
Part isInterestListPassedPart = m.getPart(partCnt++);
Part hasCqsPart = m.getPart(partCnt++);
EventID eventId = (EventID)m.getPart(m.getNumberOfParts() - 1)
.getObject();
boolean withInterest = ((Boolean)isInterestListPassedPart.getObject()).booleanValue();
boolean withCQs = ((Boolean)hasCqsPart.getObject()).booleanValue();
regionName = regionNamePart.getString();
key = keyPart.getStringOrObject();
Object callbackArgument = callbackArgumentPart.getObject();
// Don't automatically deserialize the value.
// Pass it onto the region as a byte[]. If it is a serialized
// object, it will be stored as a CachedDeserializable and
// deserialized only when requested.
boolean isCreate = (m.getMessageType() == MessageType.LOCAL_CREATE);
if (logger.fineEnabled()) {
logger.fine("Putting entry for region: "
+ regionName + " key: " + key
+ " create: " + isCreate
+ (valuePart.isObject() ? (" value: " +
deserialize(valuePart.getSerializedForm())): "")
+ " callbackArgument: " + callbackArgument
+ " withInterest=" + withInterest
+ " withCQs=" + withCQs
+ " eventID=" + eventId
+ " version=" + versionTag);
}
LocalRegion region = (LocalRegion) cacheHelper.getRegion(regionName);
if (!isDeltaSent) {
// bug #42162 - must check for a serialized null here
byte[] serializedForm = valuePart.getSerializedForm();
if (isCreate && InternalDataSerializer.isSerializedNull(serializedForm)) {
//newValue = null; newValue is already null
} else {
newValue = valuePart.getSerializedForm();
}
if (withCQs) {
fullValue = valuePart.getObject();
}
isValueObject = valuePart.isObject();
} else {
deltaBytes = valuePart.getSerializedForm();
isValueObject = true;
}
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine(toString()+": Region named " + regionName + " does not exist");
}
}
else if (region.hasServerProxy()
&& ServerResponseMatrix.checkForValidStateAfterNotification(region,
key, m.getMessageType()) && (withInterest || !withCQs)) {
EntryEventImpl newEvent = null;
try {
// Create an event and put the entry
newEvent = EntryEventImpl.create(
region,
((m.getMessageType() == MessageType.LOCAL_CREATE) ? Operation.CREATE
: Operation.UPDATE), key, null /* newValue */,
callbackArgument /* callbackArg */, true /* originRemote */,
eventId.getDistributedMember());
newEvent.setVersionTag(versionTag);
newEvent.setFromServer(true);
region.basicBridgeClientUpdate(eventId.getDistributedMember(), key,
newValue, deltaBytes, isValueObject, callbackArgument, m
.getMessageType() == MessageType.LOCAL_CREATE, qManager
.getState().getProcessedMarker()
|| !this.isDurableClient, newEvent, eventId);
this.isOpCompleted = true;
// bug 45520 - ConcurrentCacheModificationException is not thrown and we must check this flag
// if (newEvent.isConcurrencyConflict()) {
// return; // this is logged elsewhere at fine level
// }
if (withCQs && isDeltaSent) {
fullValue = newEvent.getNewValue();
}
} catch (InvalidDeltaException ide) {
Part fullValuePart = requestFullValue(eventId,
"Caught InvalidDeltaException.");
region.getCachePerfStats().incDeltaFullValuesRequested();
fullValue = newValue = fullValuePart.getObject();
isValueObject = Boolean.valueOf(fullValuePart.isObject());
region.basicBridgeClientUpdate(eventId.getDistributedMember(), key,
newValue, null, isValueObject, callbackArgument, m
.getMessageType() == MessageType.LOCAL_CREATE, qManager
.getState().getProcessedMarker()
|| !this.isDurableClient, newEvent, eventId);
this.isOpCompleted = true;
} finally {
if (newEvent != null) newEvent.release();
}
if (logger.fineEnabled()) {
logger.fine("Put entry for region: " + regionName
+ " key: " + key + " callbackArgument: " + callbackArgument);
}
}
// Update CQs. CQs can exist without client region.
if (withCQs) {
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger.fine("Received message has CQ Event. Number of cqs interested in the event : " +
numCqsPart.getInt()/2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), m
.getMessageType(), key, fullValue, deltaBytes, eventId);
this.isOpCompleted = true;
}
} catch (Exception e) {
String message = LocalizedStrings.CacheClientUpdater_THE_FOLLOWING_EXCEPTION_OCCURRED_WHILE_ATTEMPTING_TO_PUT_ENTRY_REGION_0_KEY_1_VALUE_2.toLocalizedString(new Object[] { regionName, key, deserialize(valuePart.getSerializedForm())});
handleException(message, e);
}
}
private Part requestFullValue(EventID eventId, String reason) throws Exception {
if (isUsedByTest) {
fullValueRequested = true;
}
if (logger.fineEnabled()) {
logger.fine(reason + " Requesting full value...");
}
Part result = (Part)GetEventValueOp.executeOnPrimary(qManager.getPool(),
eventId, null);
if (result == null) {
// Just log a warning. Do not stop CCU thread.
throw new Exception("Could not retrieve full value for "
+ eventId);
}
if (logger.fineEnabled()) {
logger.fine("Full value received.");
}
return result;
}
/**
* Invalidate an entry
*
* @param m
* message describing the entry
*/
private void handleInvalidate(Message m) {
String regionName = null;
Object key = null;
int partCnt = 0;
try {
this.isOpCompleted = false;
// Retrieve the data from the local-invalidate message parts
if (logger.fineEnabled()) {
logger.fine("Received invalidate message of length (" + m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part keyPart = m.getPart(partCnt++);
Part callbackArgumentPart = m.getPart(partCnt++);
VersionTag versionTag = (VersionTag)m.getPart(partCnt++).getObject();
if (versionTag != null) {
versionTag.replaceNullIDs((InternalDistributedMember) this.endpoint.getMemberId());
}
Part isInterestListPassedPart = m.getPart(partCnt++);
Part hasCqsPart = m.getPart(partCnt++);
regionName = regionNamePart.getString();
key = keyPart.getStringOrObject();
Object callbackArgument = callbackArgumentPart.getObject();
boolean withInterest = ((Boolean)isInterestListPassedPart.getObject()).booleanValue();
boolean withCQs = ((Boolean)hasCqsPart.getObject()).booleanValue();
if (logger.fineEnabled()) {
logger.fine("Invalidating entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument
+ " withInterest=" + withInterest
+ " withCQs=" + withCQs
+ " version=" + versionTag);
}
LocalRegion region = (LocalRegion) cacheHelper.getRegion(regionName);
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine("Region named " + regionName
+ " does not exist");
}
} else {
if (region.hasServerProxy()
&& (withInterest || !withCQs)) {
try {
Part eid = m.getPart(m.getNumberOfParts() - 1);
EventID eventId = (EventID)eid.getObject();
try {
region.basicBridgeClientInvalidate(eventId.getDistributedMember(), key,
callbackArgument, qManager.getState().getProcessedMarker() || !this.isDurableClient,
eventId, versionTag);
} catch (ConcurrentCacheModificationException e) {
// return; allow CQs to be processed
}
this.isOpCompleted = true;
//fix for 36615
qManager.getState().incrementInvalidatedStats();
if (logger.fineEnabled()) {
logger.fine("Invalidated entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument);
}
}
catch (EntryNotFoundException e) {
/*ignore*/
if (logger.fineEnabled() && !quitting()) {
logger.fine("Already invalidated entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument);
}
this.isOpCompleted = true;
}
}
}
if (withCQs) {
// The client may have been registered to receive invalidates for
// create and updates operations. Get the actual region operation.
Part regionOpType = m.getPart(partCnt++);
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger.fine("Received message has CQ Event. Number of cqs interested in the event : "
+ numCqsPart.getInt() / 2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), regionOpType.getInt(), key, null);
this.isOpCompleted = true;
}
}
catch (Exception e) {
final String message = LocalizedStrings.CacheClientUpdater_THE_FOLLOWING_EXCEPTION_OCCURRED_WHILE_ATTEMPTING_TO_INVALIDATE_ENTRY_REGION_0_KEY_1.toLocalizedString(new Object[] { regionName, key });
handleException(message, e);
}
}
/**
* locally destroy an entry
*
* @param m
* message describing the entry
*/
private void handleDestroy(Message m) {
String regionName = null;
Object key = null;
int partCnt = 0;
try {
this.isOpCompleted = false;
// Retrieve the data from the local-destroy message parts
if (logger.fineEnabled()) {
logger.fine("Received destroy message of length ("
+ m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part keyPart = m.getPart(partCnt++);
Part callbackArgumentPart = m.getPart(partCnt++);
VersionTag versionTag = (VersionTag)m.getPart(partCnt++).getObject();
if (versionTag != null) {
versionTag.replaceNullIDs((InternalDistributedMember) this.endpoint.getMemberId());
}
regionName = regionNamePart.getString();
key = keyPart.getStringOrObject();
Part isInterestListPassedPart = m.getPart(partCnt++);
Part hasCqsPart = m.getPart(partCnt++);
boolean withInterest = ((Boolean)isInterestListPassedPart.getObject()).booleanValue();
boolean withCQs = ((Boolean)hasCqsPart.getObject()).booleanValue();
Object callbackArgument = callbackArgumentPart.getObject();
if (logger.fineEnabled()) {
logger.fine("Destroying entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument
+ " withInterest=" + withInterest
+ " withCQs=" + withCQs
+ " version=" + versionTag);
}
LocalRegion region = (LocalRegion) cacheHelper.getRegion(regionName);
EventID eventId = null;
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine("Region named " + regionName
+ " does not exist");
}
}
else if (region.hasServerProxy()
&& (withInterest || !withCQs)) {
try {
Part eid = m.getPart(m.getNumberOfParts() - 1);
eventId = (EventID)eid.getObject();
try {
region.basicBridgeClientDestroy(eventId.getDistributedMember(),
key, callbackArgument,
qManager.getState().getProcessedMarker() || !this.isDurableClient,
eventId, versionTag);
} catch (ConcurrentCacheModificationException e) {
// return; allow CQs to be processed
}
this.isOpCompleted = true;
if (logger.fineEnabled()) {
logger.fine("Destroyed entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument);
}
}
catch (EntryNotFoundException e) {
/*ignore*/
if (logger.fineEnabled() && !quitting()) {
logger.fine("Already destroyed entry for region: "
+ regionName + " key: " + key + " callbackArgument: "
+ callbackArgument + " eventId=" + eventId.expensiveToString());
}
this.isOpCompleted = true;
}
}
if (withCQs) {
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()){
logger
.fine("Received message has CQ Event. Number of cqs interested in the event : "
+ numCqsPart.getInt() / 2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), m.getMessageType(), key, null);
this.isOpCompleted = true;
}
}
catch (Exception e) {
String message = LocalizedStrings.CacheClientUpdater_THE_FOLLOWING_EXCEPTION_OCCURRED_WHILE_ATTEMPTING_TO_DESTROY_ENTRY_REGION_0_KEY_1.toLocalizedString(new Object[] { regionName, key });
handleException(message, e);
}
}
/**
* Locally destroy a region
*
* @param m
* message describing the region
*/
private void handleDestroyRegion(Message m) {
Part regionNamePart = null, callbackArgumentPart = null;
String regionName = null;
Object callbackArgument = null;
LocalRegion region = null;
int partCnt = 0;
try {
// Retrieve the data from the local-destroy-region message parts
if (logger.fineEnabled()) {
logger.fine("Received destroy region message of length ("
+ m.getPayloadLength() + " bytes)");
}
regionNamePart = m.getPart(partCnt++);
callbackArgumentPart = m.getPart(partCnt++);
regionName = regionNamePart.getString();
callbackArgument = callbackArgumentPart.getObject();
Part hasCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger.fine("Destroying region: " + regionName
+ " callbackArgument: " + callbackArgument);
}
// Handle CQs if any on this region.
if (((Boolean)hasCqsPart.getObject()).booleanValue()) {
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger
.fine("Received message has CQ Event. Number of cqs interested in the event : "
+ numCqsPart.getInt() / 2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), m.getMessageType(), null, null);
}
// Confirm that the region exists
region = (LocalRegion) cacheHelper.getRegion(regionName);
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine("Region named " + regionName + " does not exist");
}
return;
}
// Verify that the region in question should respond to this message
if (region.hasServerProxy()) {
// Locally destroy the region
region.localDestroyRegion(callbackArgument);
if (logger.fineEnabled()) {
logger.fine("Destroyed region: " + regionName
+ " callbackArgument: " + callbackArgument);
}
}
} catch (RegionDestroyedException e) { // already destroyed
if (logger.fineEnabled()) {
logger.fine("region already destroyed: " + regionName);
}
} catch (Exception e) {
String message = LocalizedStrings.CacheClientUpdater_CAUGHT_AN_EXCEPTION_WHILE_ATTEMPTING_TO_DESTROY_REGION_0.toLocalizedString(regionName);
handleException(message, e);
}
}
/**
* Locally clear a region
*
* @param m
* message describing the region to clear
*/
private void handleClearRegion(Message m) {
String regionName = null;
int partCnt = 0;
try {
// Retrieve the data from the clear-region message parts
if (logger.fineEnabled()) {
logger.fine(toString()
+ ": Received clear region message of length ("
+ m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part callbackArgumentPart = m.getPart(partCnt++);
Part hasCqsPart = m.getPart(partCnt++);
regionName = regionNamePart.getString();
Object callbackArgument = callbackArgumentPart.getObject();
if (logger.fineEnabled()) {
logger.fine("Clearing region: " + regionName
+ " callbackArgument: " + callbackArgument);
}
if (((Boolean) hasCqsPart.getObject()).booleanValue()) {
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger
.fine("Received message has CQ Event. Number of cqs interested in the event : "
+ numCqsPart.getInt() / 2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), m
.getMessageType(), null, null);
}
// Confirm that the region exists
LocalRegion region = (LocalRegion) cacheHelper.getRegion(regionName);
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine("Region named " + regionName
+ " does not exist");
}
return;
}
// Verify that the region in question should respond to this
// message
if (region.hasServerProxy()) {
// Locally clear the region
region.basicBridgeClientClear(callbackArgument, qManager.getState()
.getProcessedMarker() || !this.isDurableClient);
if (logger.fineEnabled()) {
logger.fine("Cleared region: " + regionName
+ " callbackArgument: " + callbackArgument);
}
}
}
catch (Exception e) {
String message = LocalizedStrings.CacheClientUpdater_CAUGHT_THE_FOLLOWING_EXCEPTION_WHILE_ATTEMPTING_TO_CLEAR_REGION_0.toLocalizedString(regionName);
handleException(message, e);
}
}
/**
* Locally invalidate a region
* NOTE: Added as part of bug#38048. The code only takes care of CQ processing.
* Support needs to be added for local region invalidate.
* @param m message describing the region to clear
*/
private void handleInvalidateRegion(Message m) {
String regionName = null;
int partCnt = 0;
try {
// Retrieve the data from the invalidate-region message parts
if (logger.fineEnabled()) {
logger.fine(toString()
+ ": Received invalidate region message of length ("
+ m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
partCnt ++; // Part callbackArgumentPart = m.getPart(partCnt++);
Part hasCqsPart = m.getPart(partCnt++);
regionName = regionNamePart.getString();
// Object callbackArgument = callbackArgumentPart.getObject();
if (((Boolean) hasCqsPart.getObject()).booleanValue()) {
Part numCqsPart = m.getPart(partCnt++);
if (logger.fineEnabled()) {
logger
.fine("Received message has CQ Event. Number of cqs interested in the event : "
+ numCqsPart.getInt() / 2);
}
partCnt = processCqs(m, partCnt, numCqsPart.getInt(), m.getMessageType(), null, null);
}
// Confirm that the region exists
LocalRegion region = (LocalRegion) cacheHelper.getRegion(regionName);
if (region == null) {
if (logger.fineEnabled() && !quitting()) {
logger.fine("Region named " + regionName
+ " does not exist");
}
return;
}
// Verify that the region in question should respond to this
// message
if (region.hasServerProxy()){
return;
// NOTE:
// As explained in the method description, this code is added as part
// of CQ bug fix. Cache server team needs to look into changes relating
// to local region.
//
// Locally invalidate the region
// region.basicBridgeClientInvalidate(callbackArgument,
// proxy.getProcessedMarker());
//if (logger.fineEnabled()) {
// logger.fine(toString() + ": Cleared region: " + regionName
// + " callbackArgument: " + callbackArgument);
//}
}
}
catch (Exception e) {
String message =
LocalizedStrings.CacheClientUpdater_CAUGHT_THE_FOLLOWING_EXCEPTION_WHILE_ATTEMPTING_TO_INVALIDATE_REGION_0.toLocalizedString(regionName);
handleException(message, e);
}
}
/**
* Register instantiators locally
*
* @param msg
* message describing the new instantiators
* @param eventId
* eventId of the instantiators
*/
private void handleRegisterInstantiator(Message msg, EventID eventId) {
String instantiatorClassName = null;
try {
int noOfParts = msg.getNumberOfParts();
if (logger.fineEnabled()) {
logger.fine(getName() + ": Received register instantiators message of parts" + noOfParts);
}
Assert.assertTrue((noOfParts - 1) % 3 == 0);
for (int i = 0; i < noOfParts - 1; i = i + 3) {
instantiatorClassName = (String) CacheServerHelper
.deserialize(msg.getPart(i).getSerializedForm());
String instantiatedClassName = (String) CacheServerHelper
.deserialize(msg.getPart(i + 1).getSerializedForm());
int id = msg.getPart(i + 2).getInt();
InternalInstantiator.register(instantiatorClassName, instantiatedClassName, id,
false, eventId, null/* context */);
// distribute is false because we don't want to propagate this to
// servers recursively
}
// // CALLBACK TESTING PURPOSE ONLY ////
if (PoolImpl.IS_INSTANTIATOR_CALLBACK) {
BridgeObserver bo = BridgeObserverHolder.getInstance();
bo.afterReceivingFromServer(eventId);
}
// /////////////////////////////////////
}
// TODO bug: can the following catch be more specific?
catch (Exception e) {
if(logger.fineEnabled()){
logger.fine(this + ": Caught following exception while attempting to read Instantiator : " + instantiatorClassName, e);
}
}
}
private void handleRegisterDataSerializer(Message msg, EventID eventId) {
Class dataSerializerClass = null ;
try {
int noOfParts = msg.getNumberOfParts();
// int numOfClasses = noOfParts - 3; // 1 for ds classname, 1 for ds id and 1 for eventId.
if (logger.fineEnabled()) {
logger.fine(getName() + ": Received register dataserializer message of parts" + noOfParts);
}
for (int i = 0; i < noOfParts - 1;) {
try {
String dataSerializerClassName = (String) CacheServerHelper
.deserialize(msg.getPart(i).getSerializedForm());
int id = msg.getPart(i + 1).getInt();
InternalDataSerializer.register(dataSerializerClassName, false, eventId, null/* context */, id);
// distribute is false because we don't want to propagate this to
// servers recursively
int numOfClasses = msg.getPart(i + 2).getInt();
int j = 0;
for (; j < numOfClasses; j++) {
String className = (String)CacheServerHelper.deserialize(msg
.getPart(i + 3 + j).getSerializedForm());
InternalDataSerializer.updateSupportedClassesMap(
dataSerializerClassName, className);
}
i = i + 3 + j;
} catch (ClassNotFoundException e) {
if(logger.fineEnabled()){
logger.fine(this + ": Caught following exception while attempting to read DataSerializer : " + dataSerializerClass, e);
}
}
}
// // CALLBACK TESTING PURPOSE ONLY ////
if (PoolImpl.IS_INSTANTIATOR_CALLBACK) {
BridgeObserver bo = BridgeObserverHolder.getInstance();
bo.afterReceivingFromServer(eventId);
}
///////////////////////////////////////
}
// TODO bug: can the following catch be more specific?
catch (Exception e) {
if(logger.fineEnabled()){
logger.fine(this + ": Caught following exception while attempting to read DataSerializer : " + dataSerializerClass, e);
}
}
}
/**
* Processes message to invoke CQ listeners.
*
* @param startMessagePart
* @param numCqParts
* @param messageType
* @param key
* @param value
*/
private int processCqs(Message m, int startMessagePart, int numCqParts,
int messageType, Object key, Object value) {
return processCqs(m, startMessagePart, numCqParts, messageType, key, value,
null, null/* eventId */);
}
private int processCqs(Message m, int startMessagePart, int numCqParts,
int messageType, Object key, Object value, byte[] delta, EventID eventId) {
//String[] cqs = new String[numCqs/2];
HashMap cqs = new HashMap();
for (int cqCnt=0; cqCnt < numCqParts;) {
StringBuilder str = null;
if (logger.fineEnabled()) {
str = new StringBuilder(100);
str.append("found these queries: ");
}
try {
// Get CQ Name.
Part cqNamePart = m.getPart(startMessagePart + (cqCnt++));
// Get CQ Op.
Part cqOpPart = m.getPart(startMessagePart + (cqCnt++));
cqs.put(cqNamePart.getString(), Integer.valueOf(cqOpPart.getInt()));
if (str != null) {
str.append(cqNamePart.getString())
.append(" op=").append(cqOpPart.getInt()).append(" ");
}
} catch (Exception ex) {
if (logger.warningEnabled()) { // this use to be fine, changed it to warning.
logger.warning(
LocalizedStrings.CacheClientUpdater_ERROR_WHILE_PROCESSING_THE_CQ_MESSAGE_PROBLEM_WITH_READING_MESSAGE_FOR_CQ_0, cqCnt);
}
}
if (str != null) {
logger.fine(str.toString());
}
}
{
CqService cqService = CqService.getCqService(this.cacheHelper.getCache());
try {
cqService.dispatchCqListeners(cqs, messageType, key, value, delta,
qManager, eventId);
}
catch (Exception ex) {
if (logger.warningEnabled()) {
logger.warning(LocalizedStrings.CacheClientUpdater_FAILED_TO_INVOKE_CQ_DISPATCHER_ERROR___0, ex.getMessage());
}
if (logger.fineEnabled()) {
logger.fine("Failed to invoke CQ Dispatcher. ", ex);
}
}
}
return (startMessagePart + numCqParts);
}
private void handleRegisterInterest(Message m) {
String regionName = null;
Object key = null;
int interestType;
byte interestResultPolicy;
boolean isDurable;
boolean receiveUpdatesAsInvalidates;
int partCnt = 0;
try {
// Retrieve the data from the add interest message parts
if (getLogger().fineEnabled()) {
getLogger().fine(toString() + ": Received add interest message of length (" + m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part keyPart = m.getPart(partCnt++);
Part interestTypePart = m.getPart(partCnt++);
Part interestResultPolicyPart = m.getPart(partCnt++);
Part isDurablePart = m.getPart(partCnt++);
Part receiveUpdatesAsInvalidatesPart = m.getPart(partCnt++);
regionName = regionNamePart.getString();
key = keyPart.getStringOrObject();
interestType = ((Integer) interestTypePart.getObject()).intValue();
interestResultPolicy = ((Byte) interestResultPolicyPart.getObject()).byteValue();
isDurable = ((Boolean) isDurablePart.getObject()).booleanValue();
receiveUpdatesAsInvalidates = ((Boolean) receiveUpdatesAsInvalidatesPart.getObject()).booleanValue();
// Confirm that region exists
LocalRegion region = (LocalRegion)cacheHelper.getRegion(regionName);
if (region == null) {
if (getLogger().fineEnabled() && !quitting()) {
getLogger().fine(toString()+": Region named " + regionName + " does not exist");
}
return;
}
// Verify that the region in question should respond to this message
if (!region.hasServerProxy()) {
return;
}
if (key instanceof List) {
region.getServerProxy().addListInterest((List) key,
InterestResultPolicy.fromOrdinal(interestResultPolicy), isDurable,
receiveUpdatesAsInvalidates);
} else {
region.getServerProxy().addSingleInterest(key, interestType,
InterestResultPolicy.fromOrdinal(interestResultPolicy), isDurable,
receiveUpdatesAsInvalidates);
}
}
catch (Exception e) {
String message = ": The following exception occurred while attempting to add interest (region: " + regionName
+ " key: " + key + "): ";
handleException(message, e);
}
}
private void handleUnregisterInterest(Message m) {
String regionName = null;
Object key = null;
int interestType;
boolean isDurable;
boolean receiveUpdatesAsInvalidates;
int partCnt = 0;
try {
// Retrieve the data from the remove interest message parts
if (getLogger().fineEnabled()) {
getLogger().fine(toString() + ": Received remove interest message of length (" + m.getPayloadLength() + " bytes)");
}
Part regionNamePart = m.getPart(partCnt++);
Part keyPart = m.getPart(partCnt++);
Part interestTypePart = m.getPart(partCnt++);
Part isDurablePart = m.getPart(partCnt++);
Part receiveUpdatesAsInvalidatesPart = m.getPart(partCnt++);
// Not reading the eventId part
regionName = regionNamePart.getString();
key = keyPart.getStringOrObject();
interestType = ((Integer) interestTypePart.getObject()).intValue();
isDurable = ((Boolean) isDurablePart.getObject()).booleanValue();
receiveUpdatesAsInvalidates =
((Boolean) receiveUpdatesAsInvalidatesPart.getObject()).booleanValue();
// Confirm that region exists
LocalRegion region = (LocalRegion)cacheHelper.getRegion(regionName);
if (region == null) {
if (getLogger().fineEnabled() && !quitting()) {
getLogger().fine(toString()+": Region named " + regionName + " does not exist");
}
return;
}
// Verify that the region in question should respond to this message
if (!region.hasServerProxy()) {
return;
}
if (key instanceof List) {
region.getServerProxy().removeListInterest((List) key, isDurable,
receiveUpdatesAsInvalidates);
} else {
region.getServerProxy().removeSingleInterest(key, interestType,
isDurable, receiveUpdatesAsInvalidates);
}
}
catch (Exception e) {
String message = ": The following exception occurred while attempting to add interest (region: " + regionName
+ " key: " + key + "): ";
handleException(message, e);
}
}
private void handleTombstoneOperation(Message msg) {
String regionName = "unknown";
try { // not sure why this isn't done by the caller
int partIdx = 0;
// see ClientTombstoneMessage.getGFE70Message
regionName = msg.getPart(partIdx++).getString();
int op = msg.getPart(partIdx++).getInt();
LocalRegion region = (LocalRegion)cacheHelper.getRegion(regionName);
if (region == null) {
if (getLogger().fineEnabled() && !quitting()) {
getLogger().fine(toString()+": Region named " + regionName + " does not exist");
}
return;
}
if (getLogger().fineEnabled()) {
getLogger().fine(toString() + ": Received tombstone operation for region " + region + " with operation=" + op);
}
if (!region.getConcurrencyChecksEnabled()) {
return;
}
switch (op) {
case 0:
Map regionGCVersions =
(Map)msg.getPart(partIdx++).getObject();
EventID eventID = (EventID)msg.getPart(partIdx++).getObject();
region.expireTombstones(regionGCVersions, eventID, null);
break;
case 1:
Set