com.gemstone.gemfire.cache.client.internal.ExecuteFunctionOp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
The 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.client.internal;
import com.gemstone.gemfire.InternalGemFireError;
import com.gemstone.gemfire.cache.client.ServerConnectivityException;
import com.gemstone.gemfire.cache.client.ServerOperationException;
import com.gemstone.gemfire.cache.execute.Function;
import com.gemstone.gemfire.cache.execute.FunctionException;
import com.gemstone.gemfire.cache.execute.ResultCollector;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.ServerLocation;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.cache.execute.AbstractExecution;
import com.gemstone.gemfire.internal.cache.execute.FunctionStats;
import com.gemstone.gemfire.internal.cache.execute.InternalFunctionException;
import com.gemstone.gemfire.internal.cache.execute.InternalFunctionInvocationTargetException;
import com.gemstone.gemfire.internal.cache.execute.MemberMappedArgument;
import com.gemstone.gemfire.internal.cache.execute.ServerFunctionExecutor;
import com.gemstone.gemfire.internal.cache.tier.MessageType;
import com.gemstone.gemfire.internal.cache.tier.sockets.ChunkedMessage;
import com.gemstone.gemfire.internal.cache.tier.sockets.Message;
import com.gemstone.gemfire.internal.cache.tier.sockets.Part;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.shared.Version;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Executes the function on server (possibly without region/cache).
* Also gets the result back from the server
* @author Suranjan Kumar
* @since 5.8
*/
public class ExecuteFunctionOp {
/** index of allMembers in flags[] */
public static final int ALL_MEMBERS_INDEX = 0;
/** index of ignoreFailedMembers in flags[] */
public static final int IGNORE_FAILED_MEMBERS_INDEX = 1;
private ExecuteFunctionOp() {
// no instances allowed
}
static LogWriterI18n logger = null ;
/**
* Does a execute Function on a server using connections from the given pool
* to communicate with the server.
* @param pool the pool to use to communicate with the server.
* @param function of the function to be executed
* @param args specified arguments to the application function
*/
public static void execute(final PoolImpl pool, Function function,
ServerFunctionExecutor executor, Object args,
MemberMappedArgument memberMappedArg, boolean allServers, byte hasResult,
ResultCollector rc, boolean isFnSerializationReqd,
UserAttributes attributes, String[] groups) {
logger = pool.getLoggerI18n();
final AbstractOp op = new ExecuteFunctionOpImpl(logger, function, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd, (byte)0, groups, allServers, executor.isIgnoreDepartedMembers());
if (allServers && groups.length == 0) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Sending Function Execution Message:"
+ op.getMessage() + " to all servers using pool: " + pool);
}
List callableTasks = constructAndGetFunctionTasks(pool, function, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd, attributes);
SingleHopClientExecutor.submitAll(callableTasks);
} else {
boolean reexecuteForServ = false;
AbstractOp reexecOp = null;
int retryAttempts = 0;
boolean reexecute = false;
int maxRetryAttempts = 0;
if(function.isHA())
maxRetryAttempts = pool.getRetryAttempts();
do {
try {
if (reexecuteForServ) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute.reexecuteForServ : Sending Function Execution Message:"
+ op.getMessage() + " to server using pool: " + pool + " with groups:"
+ Arrays.toString(groups) + " all members:" + allServers + " ignoreFailedMembers:"+executor.isIgnoreDepartedMembers());
}
reexecOp = new ExecuteFunctionOpImpl(logger, function, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd,
(byte)1/* isReExecute */, groups, allServers, executor.isIgnoreDepartedMembers());
pool.execute(reexecOp, 0);
} else {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Sending Function Execution Message:"
+ op.getMessage() + " to server using pool: " + pool + " with groups:"
+ Arrays.toString(groups) + " all members:" + allServers + " ignoreFailedMembers:"+executor.isIgnoreDepartedMembers());
}
pool.execute(op, 0);
}
reexecute = false;
reexecuteForServ = false;
} catch (InternalFunctionInvocationTargetException e) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Received InternalFunctionInvocationTargetException. The failed node is "
+ e.getFailedNodeSet());
}
reexecute = true;
rc.clearResults();
} catch (ServerConnectivityException se) {
retryAttempts++;
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Received ServerConnectivityException. The exception is "
+ se
+ " The retryattempt is : "
+ retryAttempts
+ " maxRetryAttempts " + maxRetryAttempts);
}
if (se instanceof ServerOperationException) {
throw se;
}
if ((retryAttempts > maxRetryAttempts && maxRetryAttempts != -1))
throw se;
reexecuteForServ = true;
rc.clearResults();
}
} while (reexecuteForServ);
if (reexecute && function.isHA()) {
ExecuteFunctionOp.reexecute(pool, function,
executor, rc, hasResult, isFnSerializationReqd, maxRetryAttempts - 1, groups, allServers);
}
}
}
public static void execute(final PoolImpl pool, String functionId,
ServerFunctionExecutor executor, Object args,
MemberMappedArgument memberMappedArg, boolean allServers, byte hasResult,
ResultCollector rc, boolean isFnSerializationReqd, boolean isHA,
boolean optimizeForWrite, UserAttributes properties, String[] groups) {
logger = pool.getLoggerI18n();
final AbstractOp op = new ExecuteFunctionOpImpl(logger, functionId, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd, isHA,
optimizeForWrite, (byte)0, groups, allServers, executor.isIgnoreDepartedMembers());
if (allServers && groups.length == 0) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Sending Function Execution Message:"
+ op.getMessage() + " to all servers using pool: " + pool);
}
List callableTasks = constructAndGetFunctionTasks(pool, functionId, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd, isHA,
optimizeForWrite, properties);
SingleHopClientExecutor.submitAll(callableTasks);
} else {
boolean reexecuteForServ = false;
AbstractOp reexecOp = null;
int retryAttempts = 0;
boolean reexecute = false;
int maxRetryAttempts = 0;
if(isHA){
maxRetryAttempts = pool.getRetryAttempts();
}
do {
try {
if (reexecuteForServ) {
reexecOp = new ExecuteFunctionOpImpl(logger, functionId, args,
memberMappedArg, hasResult, rc, isFnSerializationReqd, isHA,
optimizeForWrite, (byte)1, groups, allServers, executor.isIgnoreDepartedMembers());
pool.execute(reexecOp, 0);
} else {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Sending Function Execution Message:"
+ op.getMessage() + " to server using pool: " + pool + " with groups:"
+ Arrays.toString(groups) + " all members:" + allServers + " ignoreFailedMembers:"+executor.isIgnoreDepartedMembers());
}
pool.execute(op, 0);
}
reexecute = false;
reexecuteForServ = false;
} catch (InternalFunctionInvocationTargetException e) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Received InternalFunctionInvocationTargetException. The failed node is "
+ e.getFailedNodeSet());
}
reexecute = true;
rc.clearResults();
} catch (ServerConnectivityException se) {
retryAttempts++;
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#execute : Received ServerConnectivityException. The exception is "
+ se
+ " The retryattempt is : "
+ retryAttempts
+ " maxRetryAttempts " + maxRetryAttempts);
}
if (se instanceof ServerOperationException) {
throw se;
}
if ((retryAttempts > maxRetryAttempts && maxRetryAttempts != -1))
throw se;
reexecuteForServ = true;
rc.clearResults();
}
} while (reexecuteForServ);
if (reexecute && isHA) {
ExecuteFunctionOp.reexecute(pool, functionId, executor, rc, hasResult,
isFnSerializationReqd, maxRetryAttempts - 1, args, isHA,
optimizeForWrite, groups, allServers);
}
}
}
public static void reexecute(ExecutablePool pool, Function function,
ServerFunctionExecutor serverExecutor, ResultCollector resultCollector,
byte hasResult, boolean isFnSerializationReqd, int maxRetryAttempts, String[] groups, boolean allMembers) {
boolean reexecute = true;
int retryAttempts = 0;
do {
reexecute = false;
AbstractOp reExecuteOp = new ExecuteFunctionOpImpl(logger, function, serverExecutor.getArguments(),
serverExecutor.getMemberMappedArgument(), hasResult, resultCollector, isFnSerializationReqd, (byte)1, groups, allMembers, serverExecutor.isIgnoreDepartedMembers());
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunction#reexecute : Sending Function Execution Message:"
+ reExecuteOp.getMessage() + " to Server using pool: " + pool + " with groups:"
+ Arrays.toString(groups) + " all members:" + allMembers + " ignoreFailedMembers:"+serverExecutor.isIgnoreDepartedMembers());
}
try {
pool.execute(reExecuteOp,0);
}
catch (InternalFunctionInvocationTargetException e) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#reexecute : Recieved InternalFunctionInvocationTargetException. The failed nodes are "
+ e.getFailedNodeSet());
}
reexecute = true;
resultCollector.clearResults();
}
catch (ServerConnectivityException se) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#reexecute : Received ServerConnectivity Exception.");
}
if(se instanceof ServerOperationException){
throw se;
}
retryAttempts++;
if (retryAttempts > maxRetryAttempts && maxRetryAttempts != -2)
throw se;
reexecute = true;
resultCollector.clearResults();
}
} while (reexecute);
}
public static void reexecute(ExecutablePool pool, String functionId,
ServerFunctionExecutor serverExecutor, ResultCollector resultCollector,
byte hasResult, boolean isFnSerializationReqd, int maxRetryAttempts,
Object args, boolean isHA, boolean optimizeForWrite, String[] groups, boolean allMembers) {
boolean reexecute = true;
int retryAttempts = 0;
do {
reexecute = false;
final AbstractOp op = new ExecuteFunctionOpImpl(logger, functionId, args,
serverExecutor.getMemberMappedArgument(), hasResult, resultCollector, isFnSerializationReqd, isHA, optimizeForWrite, (byte)1, groups, allMembers, serverExecutor.isIgnoreDepartedMembers());
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunction#reexecute : Sending Function Execution Message:"
+ op.getMessage() + " to Server using pool: " + pool + " with groups:"
+ Arrays.toString(groups) + " all members:" + allMembers + " ignoreFailedMembers:"+serverExecutor.isIgnoreDepartedMembers());
}
try {
pool.execute(op,0);
}
catch (InternalFunctionInvocationTargetException e) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#reexecute : Recieved InternalFunctionInvocationTargetException. The failed nodes are "
+ e.getFailedNodeSet());
}
reexecute = true;
resultCollector.clearResults();
}
catch (ServerConnectivityException se) {
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOp#reexecute : Received ServerConnectivity Exception.");
}
if(se instanceof ServerOperationException){
throw se;
}
retryAttempts++;
if (retryAttempts > maxRetryAttempts && maxRetryAttempts != -2)
throw se;
reexecute = true;
resultCollector.clearResults();
}
} while (reexecute);
}
static List constructAndGetFunctionTasks(final PoolImpl pool,
final Function function, Object args,
MemberMappedArgument memberMappedArg, byte hasResult, ResultCollector rc,
boolean isFnSerializationReqd, UserAttributes attributes) {
final List tasks = new ArrayList();
ArrayList servers = null;
if (pool.getLocators() == null || pool.getLocators().isEmpty()) {
servers = ((ExplicitConnectionSourceImpl)pool.getConnectionSource())
.getAllServers();
}
else {
servers = ((AutoConnectionSourceImpl)pool.getConnectionSource())
.findAllServers(); // n/w call on locator
}
for (ServerLocation server : servers) {
final AbstractOp op = new ExecuteFunctionOpImpl(pool.getLoggerI18n(),
function, args, memberMappedArg, hasResult, rc, isFnSerializationReqd, (byte)0, null/*onGroups does not use single-hop for now*/, false, false);
SingleHopOperationCallable task = new SingleHopOperationCallable(server, pool, op, attributes);
tasks.add(task);
}
return tasks;
}
static List constructAndGetFunctionTasks(final PoolImpl pool,
final String functionId, Object args,
MemberMappedArgument memberMappedArg, byte hasResult, ResultCollector rc,
boolean isFnSerializationReqd, boolean isHA, boolean optimizeForWrite, UserAttributes properties) {
final List tasks = new ArrayList();
ArrayList servers = null;
if (pool.getLocators() == null || pool.getLocators().isEmpty()) {
servers = ((ExplicitConnectionSourceImpl)pool.getConnectionSource())
.getAllServers();
}
else {
servers = ((AutoConnectionSourceImpl)pool.getConnectionSource())
.findAllServers(); // n/w call on locator
}
for (ServerLocation server : servers) {
final AbstractOp op = new ExecuteFunctionOpImpl(pool.getLoggerI18n(),
functionId, args, memberMappedArg, hasResult, rc, isFnSerializationReqd, isHA, optimizeForWrite,(byte)0, null/*onGroups does not use single-hop for now*/, false, false);
SingleHopOperationCallable task = new SingleHopOperationCallable(server, pool, op, properties);
tasks.add(task);
}
return tasks;
}
static byte[] getByteArrayForFlags(boolean... flags) {
byte[] retVal = null;
if (flags.length > 0) {
retVal = new byte[flags.length];
for (int i=0; i 1) {
if (this.flags[IGNORE_FAILED_MEMBERS_INDEX] == 1) {
ignoreFailedMembers = true;
}
}
return ignoreFailedMembers;
}
@Override
protected Object processResponse(Message msg) throws Exception {
ChunkedMessage executeFunctionResponseMsg = (ChunkedMessage)msg;
try {
// Read the header which describes the type of message following
executeFunctionResponseMsg.readHeader();
switch (executeFunctionResponseMsg.getMessageType()) {
case MessageType.EXECUTE_FUNCTION_RESULT:
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOpImpl#processResponse: received message of type EXECUTE_FUNCTION_RESULT.");
}
// Read the chunk
do{
executeFunctionResponseMsg.receiveChunk();
Object resultResponse = executeFunctionResponseMsg.getPart(0)
.getObject();
Object result;
if (resultResponse instanceof ArrayList) {
result = ((ArrayList)resultResponse).get(0);
}
else {
result = resultResponse;
}
if (result instanceof FunctionException) {
//String s = "While performing a remote " + getOpName();
FunctionException ex = ((FunctionException)result);
if (ex instanceof InternalFunctionException || getIgnoreFailedMembers()) {
Throwable cause = ex.getCause() == null ? ex : ex.getCause();
DistributedMember memberID = (DistributedMember)((ArrayList)resultResponse)
.get(1);
this.resultCollector.addResult(memberID, cause);
FunctionStats.getFunctionStats(this.functionId, null)
.incResultsReceived();
continue;
}
else {
throw ex;
}
}else if (result instanceof Throwable) {
String s = "While performing a remote " + getOpName();
throw new ServerOperationException(s, (Throwable)result);
// Get the exception toString part.
// This was added for c++ thin client and not used in java
//Part exceptionToStringPart = msg.getPart(1);
}
else {
DistributedMember memberID = (DistributedMember)((ArrayList)resultResponse)
.get(1);
synchronized (resultCollector) {
resultCollector.addResult(memberID, result);
}
FunctionStats.getFunctionStats(this.functionId, null)
.incResultsReceived();
}
}while(!executeFunctionResponseMsg.isLastChunk());
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOpImpl#processResponse: received all the results from server successfully.");
}
return null;
case MessageType.EXCEPTION:
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOpImpl#processResponse: received message of type EXCEPTION");
}
// Read the chunk
executeFunctionResponseMsg.receiveChunk();
Part part0 = executeFunctionResponseMsg.getPart(0);
Object obj = part0.getObject();
if (obj instanceof FunctionException) {
FunctionException ex = ((FunctionException)obj);
throw ex;
}
else {
String s = ": While performing a remote execute Function" + ((Throwable)obj).getMessage();
throw new ServerOperationException(s, (Throwable)obj);
}
case MessageType.EXECUTE_FUNCTION_ERROR:
if (logger.fineEnabled()) {
logger
.fine("ExecuteFunctionOpImpl#processResponse: received message of type EXECUTE_FUNCTION_ERROR");
}
// Read the chunk
executeFunctionResponseMsg.receiveChunk();
String errorMessage = executeFunctionResponseMsg.getPart(0)
.getString();
throw new ServerOperationException(errorMessage);
default:
throw new InternalGemFireError(
LocalizedStrings.Op_UNKNOWN_MESSAGE_TYPE_0
.toLocalizedString(
Integer.valueOf(executeFunctionResponseMsg.getMessageType())));
}
}
finally {
executeFunctionResponseMsg.clear();
}
}
@Override
protected boolean isErrorResponse(int msgType) {
return msgType == MessageType.EXECUTE_FUNCTION_ERROR;
}
@Override
protected long startAttempt(ConnectionStats stats) {
return stats.startExecuteFunction();
}
protected String getOpName() {
return "executeFunction";
}
@Override
protected void endSendAttempt(ConnectionStats stats, long start) {
stats.endExecuteFunctionSend(start, hasFailed());
}
@Override
protected void endAttempt(ConnectionStats stats, long start) {
stats.endExecuteFunction(start, hasTimedOut(), hasFailed());
}
@Override
protected Message createResponseMessage() {
return new ChunkedMessage(1, Version.CURRENT);
}
}
public static final int MAX_FE_THREADS = Integer.getInteger(
"DistributionManager.MAX_FE_THREADS",
Math.max(Runtime.getRuntime().availableProcessors() * 4, 16)).intValue();
}