Repository: asterixdb Updated Branches: refs/heads/master 249be53bb -> ae50ba3fc
Enable Adding Nodes to Running *DB Cluster Also ability to configure unique partition ids without having access to complete cluster topology Change-Id: If978442a95687c00ef78c89ed1b4440f5e308b99 Reviewed-on: https://asterix-gerrit.ics.uci.edu/1785 Sonar-Qube: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> BAD: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Yingyi Bu <buyin...@gmail.com> Reviewed-by: Till Westmann <ti...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/ae50ba3f Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/ae50ba3f Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/ae50ba3f Branch: refs/heads/master Commit: ae50ba3fcc46c7968153f2069953fed9997354a6 Parents: 249be53 Author: Michael Blow <mb...@apache.org> Authored: Thu Jun 1 13:51:40 2017 -0400 Committer: Michael Blow <mb...@apache.org> Committed: Thu Jun 1 14:36:49 2017 -0700 ---------------------------------------------------------------------- .../api/http/server/ConnectorApiServlet.java | 10 ++-- .../api/http/server/QueryServiceServlet.java | 9 +--- .../asterix/api/http/server/RestApiServlet.java | 3 +- .../app/replication/NodeFailbackPlan.java | 1 + .../bootstrap/GlobalRecoveryManager.java | 11 ----- .../common/api/IClusterEventsSubscriber.java | 24 +++++++--- .../common/cluster/IClusterStateManager.java | 10 ++++ .../asterix/common/config/NodeProperties.java | 8 +++- .../common/config/PropertiesAccessor.java | 49 +++++++++++++------- .../asterix/common/exceptions/ErrorCode.java | 3 ++ .../main/resources/asx_errormsg/en.properties | 5 +- .../asterix/test/base/RetainLogsRule.java | 32 +++++++++++-- .../installer/test/AbstractExecutionIT.java | 2 +- .../test/AsterixExternalLibraryIT.java | 2 +- .../installer/test/AsterixRestartIT.java | 2 +- .../installer/test/MetadataReplicationIT.java | 7 ++- .../asterix/installer/test/ReplicationIT.java | 5 +- .../installer/transaction/DmlRecoveryIT.java | 2 +- .../installer/transaction/RecoveryIT.java | 2 +- .../runtime/utils/ClusterStateManager.java | 37 ++++++++++++++- .../common/exceptions/AlgebricksException.java | 47 ++++++++----------- .../hyracks/api/util/ErrorMessageUtil.java | 3 -- .../hyracks/control/cc/cluster/NodeManager.java | 9 +--- .../hyracks/http/server/utils/HttpUtil.java | 5 ++ 24 files changed, 180 insertions(+), 108 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java index 396665e..f1a123c 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java @@ -69,10 +69,11 @@ public class ConnectorApiServlet extends AbstractServlet { protected void get(IServletRequest request, IServletResponse response) { response.setStatus(HttpResponseStatus.OK); try { - HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8); + HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8); } catch (IOException e) { LOGGER.log(Level.WARNING, "Failure setting content type", e); response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); + response.writer().write(e.toString()); return; } PrintWriter out = response.writer(); @@ -84,7 +85,6 @@ public class ConnectorApiServlet extends AbstractServlet { if (dataverseName == null || datasetName == null) { jsonResponse.put("error", "Parameter dataverseName or datasetName is null,"); out.write(jsonResponse.toString()); - out.flush(); return; } @@ -127,15 +127,15 @@ public class ConnectorApiServlet extends AbstractServlet { MetadataManager.INSTANCE.commitTransaction(mdTxnCtx); // Writes file splits. out.write(jsonResponse.toString()); - out.flush(); } finally { metadataProvider.getLocks().unlock(); } } catch (Exception e) { LOGGER.log(Level.WARNING, "Failure handling a request", e); - out.println(e.getMessage()); + response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); + out.write(e.toString()); + } finally { out.flush(); - e.printStackTrace(out); } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java index 479c8b0..da04c52 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java @@ -21,7 +21,6 @@ package org.apache.asterix.api.http.server; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; @@ -320,7 +319,7 @@ public class QueryServiceServlet extends AbstractQueryApiServlet { param.path = servletPath(request); if (HttpUtil.ContentType.APPLICATION_JSON.equals(contentType)) { try { - JsonNode jsonRequest = new ObjectMapper().readTree(getRequestBody(request)); + JsonNode jsonRequest = new ObjectMapper().readTree(HttpUtil.getRequestBody(request)); param.statement = jsonRequest.get(Parameter.STATEMENT.str()).asText(); param.format = toLower(getOptText(jsonRequest, Parameter.FORMAT.str())); param.pretty = getOptBoolean(jsonRequest, Parameter.PRETTY.str(), false); @@ -333,7 +332,7 @@ public class QueryServiceServlet extends AbstractQueryApiServlet { } else { param.statement = request.getParameter(Parameter.STATEMENT.str()); if (param.statement == null) { - param.statement = getRequestBody(request); + param.statement = HttpUtil.getRequestBody(request); } param.format = toLower(request.getParameter(Parameter.FORMAT.str())); param.pretty = Boolean.parseBoolean(request.getParameter(Parameter.PRETTY.str())); @@ -343,10 +342,6 @@ public class QueryServiceServlet extends AbstractQueryApiServlet { return param; } - private static String getRequestBody(IServletRequest request) throws IOException { - return request.getHttpRequest().content().toString(StandardCharsets.UTF_8); - } - private static ResultDelivery parseResultDelivery(String mode) { if ("async".equals(mode)) { return ResultDelivery.ASYNC; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java index 6b1e408..18aae8e 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java @@ -22,7 +22,6 @@ import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_CONNE import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_DATASET_ATTR; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; @@ -222,7 +221,7 @@ public abstract class RestApiServlet extends AbstractServlet { //TODO: Both Get and Post of this API must use the same parameter names private String query(IServletRequest request) { if (request.getHttpRequest().method() == HttpMethod.POST) { - return request.getHttpRequest().content().toString(StandardCharsets.UTF_8); + return HttpUtil.getRequestBody(request); } else { return getQueryParameter(request); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/replication/NodeFailbackPlan.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/replication/NodeFailbackPlan.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/replication/NodeFailbackPlan.java index 1abc3f0..bc069b9 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/replication/NodeFailbackPlan.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/replication/NodeFailbackPlan.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.asterix.app.replication.message.CompleteFailbackRequestMessage; import org.apache.asterix.app.replication.message.PreparePartitionsFailbackRequestMessage; +import org.apache.asterix.app.replication.message.PreparePartitionsFailbackResponseMessage; public class NodeFailbackPlan { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java index 1816a25..2a1fd0b 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/GlobalRecoveryManager.java @@ -27,7 +27,6 @@ import java.util.logging.Logger; import org.apache.asterix.common.api.IClusterManagementWork; import org.apache.asterix.common.api.IClusterManagementWork.ClusterState; -import org.apache.asterix.common.api.IClusterManagementWorkResponse; import org.apache.asterix.common.cluster.IGlobalRecoveryManager; import org.apache.asterix.common.config.DatasetConfig.DatasetType; import org.apache.asterix.common.config.DatasetConfig.ExternalFilePendingOp; @@ -86,16 +85,6 @@ public class GlobalRecoveryManager implements IGlobalRecoveryManager { } @Override - public void notifyRequestCompletion(IClusterManagementWorkResponse response) { - // Do nothing - } - - @Override - public void notifyStateChange(ClusterState previousState, ClusterState newState) { - // Do nothing? - } - - @Override public void startGlobalRecovery(ICcApplicationContext appCtx) { // perform global recovery if state changed to active final ClusterState newState = ClusterStateManager.INSTANCE.getState(); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterEventsSubscriber.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterEventsSubscriber.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterEventsSubscriber.java index fef4e31..c3cf86b 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterEventsSubscriber.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterEventsSubscriber.java @@ -19,6 +19,7 @@ package org.apache.asterix.common.api; * under the License. */ import java.util.Collection; +import java.util.Collections; import java.util.Set; import org.apache.asterix.common.api.IClusterManagementWork.ClusterState; @@ -27,26 +28,35 @@ public interface IClusterEventsSubscriber { /** * @param deadNodeIds - * @return + * @return set of work to execute as a result of this node failure */ - public Set<IClusterManagementWork> notifyNodeFailure(Collection<String> deadNodeIds); + default Set<IClusterManagementWork> notifyNodeFailure(Collection<String> deadNodeIds) { + // default is no-op + return Collections.emptySet(); + } /** * @param joinedNodeId - * @return + * @return set of work to execute as a result of this node join */ - public Set<IClusterManagementWork> notifyNodeJoin(String joinedNodeId); + default Set<IClusterManagementWork> notifyNodeJoin(String joinedNodeId) { + // default is no-op + return Collections.emptySet(); + } /** * @param response */ - public void notifyRequestCompletion(IClusterManagementWorkResponse response); + default void notifyRequestCompletion(IClusterManagementWorkResponse response) { + // default is no-op + } /** * @param previousState * @param newState */ - public void notifyStateChange(ClusterState previousState, ClusterState newState); - + default void notifyStateChange(ClusterState previousState, ClusterState newState) { + // default is no-op + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/cluster/IClusterStateManager.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/cluster/IClusterStateManager.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/cluster/IClusterStateManager.java index a753db3..a5686fd 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/cluster/IClusterStateManager.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/cluster/IClusterStateManager.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.asterix.common.api.IClusterManagementWork.ClusterState; +import org.apache.asterix.common.exceptions.AsterixException; import org.apache.hyracks.api.config.IOption; import org.apache.hyracks.api.exceptions.HyracksDataException; @@ -97,4 +98,13 @@ public interface IClusterStateManager { boolean waitForState(ClusterState waitForState, long timeout, TimeUnit unit) throws HyracksDataException, InterruptedException; + /** + * Register the specified node partitions with the specified nodeId with this cluster state manager + */ + void registerNodePartitions(String nodeId, ClusterPartition[] nodePartitions) throws AsterixException; + + /** + * De-register the specified node's partitions from this cluster state manager + */ + void deregisterNodePartitions(String nodeId); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java index 1d09fff..7f09b98 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java @@ -43,7 +43,11 @@ public class NodeProperties extends AbstractProperties { appConfig -> FileUtil.joinPath(appConfig.getString(ControllerConfig.Option.DEFAULT_DIR), "txn-log"), "The directory where transaction logs should be stored", "<value of " + ControllerConfig.Option.DEFAULT_DIR.cmdline() + ">/txn-log"), - STORAGE_SUBDIR(OptionTypes.STRING, "storage", "The subdirectory name under each iodevice used for storage"),; + STORAGE_SUBDIR(OptionTypes.STRING, "storage", "The subdirectory name under each iodevice used for storage"), + STARTING_PARTITION_ID( + OptionTypes.INTEGER, + -1, + "The first partition id to assign to iodevices on this node (-1 == auto-assign)"); private final IOptionType type; private final Object defaultValue; @@ -92,7 +96,7 @@ public class NodeProperties extends AbstractProperties { @Override public boolean hidden() { - return this == INITIAL_RUN; + return this == INITIAL_RUN || this == STARTING_PARTITION_ID; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java index c5ec1c0..d011864 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,6 +57,7 @@ import org.apache.asterix.common.configuration.Property; import org.apache.asterix.common.configuration.Store; import org.apache.asterix.common.configuration.TransactionLogDir; import org.apache.asterix.common.exceptions.AsterixException; +import org.apache.asterix.common.exceptions.ErrorCode; import org.apache.asterix.common.utils.ConfigUtil; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.hyracks.algebricks.common.utils.Pair; @@ -78,7 +80,7 @@ public class PropertiesAccessor implements IApplicationConfig { private final Map<String, String> transactionLogDirs = new HashMap<>(); private final Map<String, String> asterixBuildProperties = new HashMap<>(); private final Map<String, ClusterPartition[]> nodePartitionsMap; - private final SortedMap<Integer, ClusterPartition> clusterPartitions = new TreeMap<>(); + private final SortedMap<Integer, ClusterPartition> clusterPartitions; // For extensions private final List<AsterixExtension> extensions; @@ -87,19 +89,20 @@ public class PropertiesAccessor implements IApplicationConfig { */ private PropertiesAccessor(IApplicationConfig cfg) throws AsterixException, IOException { this.cfg = cfg; - nodePartitionsMap = new HashMap<>(); + nodePartitionsMap = new ConcurrentHashMap<>(); + clusterPartitions = Collections.synchronizedSortedMap(new TreeMap<>()); extensions = new ArrayList<>(); // Determine whether to use old-style asterix-configuration.xml or new-style configuration. // QQQ strip this out eventually // QQQ this is NOT a good way to determine whether to use config file - ConfigManager configManager = ((ConfigManagerApplicationConfig)cfg).getConfigManager(); + ConfigManager configManager = ((ConfigManagerApplicationConfig) cfg).getConfigManager(); boolean usingConfigFile = Stream .of((IOption) ControllerConfig.Option.CONFIG_FILE, ControllerConfig.Option.CONFIG_FILE_URL) .map(configManager::get).anyMatch(Objects::nonNull); AsterixConfiguration asterixConfiguration = null; try { - asterixConfiguration = configure(System.getProperty(GlobalConfig.CONFIG_FILE_PROPERTY, - GlobalConfig.DEFAULT_CONFIG_FILE_NAME)); + asterixConfiguration = configure( + System.getProperty(GlobalConfig.CONFIG_FILE_PROPERTY, GlobalConfig.DEFAULT_CONFIG_FILE_NAME)); } catch (Exception e) { // cannot load config file, assume new-style config } @@ -123,6 +126,7 @@ public class PropertiesAccessor implements IApplicationConfig { // partition directory (as formed by appending the <store> subdirectory to // each <iodevices> path from the user's original cluster.xml). for (Store store : configuredStores) { + configManager.set(store.getNcId(), NodeProperties.Option.STARTING_PARTITION_ID, uniquePartitionId); String trimmedStoreDirs = store.getStoreDirs().trim(); String[] nodeStores = trimmedStoreDirs.split(","); ClusterPartition[] nodePartitions = new ClusterPartition[nodeStores.length]; @@ -153,8 +157,8 @@ public class PropertiesAccessor implements IApplicationConfig { continue; } if (option != null) { - throw new IllegalStateException("ERROR: option found in multiple sections: " + - Arrays.asList(option, optionTemp)); + throw new IllegalStateException( + "ERROR: option found in multiple sections: " + Arrays.asList(option, optionTemp)); } option = optionTemp; } @@ -175,12 +179,12 @@ public class PropertiesAccessor implements IApplicationConfig { MutableInt uniquePartitionId = new MutableInt(0); // Iterate through each configured NC. for (String ncName : cfg.getNCNames()) { - configureNc(ncName, uniquePartitionId); + configureNc(configManager, ncName, uniquePartitionId); } for (String section : cfg.getSectionNames()) { if (section.startsWith(AsterixProperties.SECTION_PREFIX_EXTENSION)) { - String className = AsterixProperties.getSectionId( - AsterixProperties.SECTION_PREFIX_EXTENSION, section); + String className = AsterixProperties.getSectionId(AsterixProperties.SECTION_PREFIX_EXTENSION, + section); configureExtension(className, section); } } @@ -230,15 +234,21 @@ public class PropertiesAccessor implements IApplicationConfig { extensions.add(new AsterixExtension(className, kvs)); } - private void configureNc(String ncId, MutableInt uniquePartitionId) { + private void configureNc(ConfigManager configManager, String ncId, MutableInt uniquePartitionId) + throws AsterixException { // Now we assign the coredump and txnlog directories for this node. // QQQ Default values? Should they be specified here? Or should there // be a default.ini? Certainly wherever they are, they should be platform-dependent. IApplicationConfig nodeCfg = cfg.getNCEffectiveConfig(ncId); coredumpConfig.put(ncId, nodeCfg.getString(NodeProperties.Option.CORE_DUMP_DIR)); - transactionLogDirs.put(ncId, - nodeCfg.getString(NodeProperties.Option.TXN_LOG_DIR)); + transactionLogDirs.put(ncId, nodeCfg.getString(NodeProperties.Option.TXN_LOG_DIR)); + int partitionId = nodeCfg.getInt(NodeProperties.Option.STARTING_PARTITION_ID); + if (partitionId != -1) { + uniquePartitionId.setValue(partitionId); + } else { + configManager.set(ncId, NodeProperties.Option.STARTING_PARTITION_ID, uniquePartitionId.getValue()); + } // Now we create an array of ClusterPartitions for all the partitions // on this NC. @@ -250,9 +260,12 @@ public class PropertiesAccessor implements IApplicationConfig { // Construct final storage path from iodevice dir + storage subdirs nodeStores[i] = iodevices[i] + File.separator + storageSubdir; // Create ClusterPartition instances for this NC. - ClusterPartition partition = new ClusterPartition(uniquePartitionId.getValue(), ncId, i); - uniquePartitionId.increment(); - clusterPartitions.put(partition.getPartitionId(), partition); + ClusterPartition partition = new ClusterPartition(uniquePartitionId.getAndIncrement(), ncId, i); + ClusterPartition orig = clusterPartitions.put(partition.getPartitionId(), partition); + if (orig != null) { + throw AsterixException.create(ErrorCode.DUPLICATE_PARTITION_ID, partition.getPartitionId(), ncId, + orig.getNodeId()); + } nodePartitions[i] = partition; } stores.put(ncId, nodeStores); @@ -302,8 +315,8 @@ public class PropertiesAccessor implements IApplicationConfig { return value == null ? defaultValue : interpreter.parse(value); } catch (IllegalArgumentException e) { if (LOGGER.isLoggable(Level.SEVERE)) { - LOGGER.severe("Invalid property value '" + value + "' for property '" + property + "'.\n" + - "Default = " + defaultValue); + LOGGER.severe("Invalid property value '" + value + "' for property '" + property + "'.\n" + "Default = " + + defaultValue); } throw e; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java index 35b7d4c..eb73e5e 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java @@ -187,6 +187,9 @@ public class ErrorCode { public static final int PROVIDER_STREAM_RECORD_READER_WRONG_CONFIGURATION = 3086; public static final int FEED_CONNECT_FEED_APPLIED_INVALID_FUNCTION = 3087; + // Lifecycle management errors + public static final int DUPLICATE_PARTITION_ID = 4000; + private ErrorCode() { } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties index 1f80fad..026f71a 100644 --- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties +++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties @@ -174,4 +174,7 @@ 3084 = Duplicate record reader format: %1$s 3085 = Unknown Adapter Name. 3086 = Cannot find record reader %1$s with specified configuration. -3087 = Cannot find function %1$s \ No newline at end of file +3087 = Cannot find function %1$s + +# Lifecycle management errors +4000 = Partition id %1$d for node %2$s already in use by node %3$s \ No newline at end of file http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/base/RetainLogsRule.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/base/RetainLogsRule.java b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/base/RetainLogsRule.java index 39bd5e7..2077ad5 100644 --- a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/base/RetainLogsRule.java +++ b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/base/RetainLogsRule.java @@ -19,6 +19,9 @@ package org.apache.asterix.test.base; import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; import org.junit.rules.TestWatcher; import org.junit.runner.Description; @@ -26,15 +29,17 @@ import org.junit.runner.Description; public class RetainLogsRule extends TestWatcher { private final File baseDir; private final File destDir; + private final Object instance; private long startTime; - public RetainLogsRule(File baseDir, File destDir) { + public RetainLogsRule(File baseDir, File destDir, Object instance) { this.baseDir = baseDir; this.destDir = destDir; + this.instance = instance; } - public RetainLogsRule(String baseDir, String destDir) { - this(new File(baseDir), new File(destDir)); + public RetainLogsRule(String baseDir, String destDir, Object instance) { + this(new File(baseDir), new File(destDir), instance); } @Override @@ -44,7 +49,7 @@ public class RetainLogsRule extends TestWatcher { @Override protected void failed(Throwable e, Description description) { - File reportDir = new File(destDir, description.getTestClass().getName() + "." + description.getMethodName()); + File reportDir = new File(destDir, description.getTestClass().getSimpleName() + "." + description.getMethodName()); reportDir.mkdirs(); try { AsterixTestHelper.deepSelectiveCopy(baseDir, reportDir, @@ -54,4 +59,23 @@ public class RetainLogsRule extends TestWatcher { e1.printStackTrace(); } } + + @Override + protected void finished(Description description) { + if (instance != null) { + for (Method m : instance.getClass().getMethods()) { + if (m.isAnnotationPresent(After.class)) { + try { + m.invoke(instance); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface After { + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AbstractExecutionIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AbstractExecutionIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AbstractExecutionIT.java index 9d0a1db..06e5aed 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AbstractExecutionIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AbstractExecutionIT.java @@ -67,7 +67,7 @@ public abstract class AbstractExecutionIT { @Rule public TestRule retainLogs = new RetainLogsRule( - AsterixInstallerIntegrationUtil.getManagixHome(), reportPath); + AsterixInstallerIntegrationUtil.getManagixHome(), reportPath, this); @BeforeClass public static void setUp() throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixExternalLibraryIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixExternalLibraryIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixExternalLibraryIT.java index 6e9dd44..c379517 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixExternalLibraryIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixExternalLibraryIT.java @@ -50,7 +50,7 @@ public class AsterixExternalLibraryIT { @Rule public TestRule retainLogs = new RetainLogsRule( - AsterixInstallerIntegrationUtil.getManagixHome(), reportPath); + AsterixInstallerIntegrationUtil.getManagixHome(), reportPath, this); @BeforeClass public static void setUp() throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixRestartIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixRestartIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixRestartIT.java index ce4de7c..d3fdc4a 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixRestartIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/AsterixRestartIT.java @@ -63,7 +63,7 @@ public class AsterixRestartIT { } @Rule - public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath); + public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath, this); @BeforeClass public static void setUp() throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java index 7a0a797..7fe156a 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java @@ -26,11 +26,10 @@ import java.util.Map; import java.util.logging.Logger; import org.apache.asterix.event.model.AsterixInstance.State; -import org.apache.asterix.test.common.TestExecutor; import org.apache.asterix.test.base.RetainLogsRule; +import org.apache.asterix.test.common.TestExecutor; import org.apache.asterix.testframework.context.TestCaseContext; import org.apache.commons.lang3.StringUtils; -import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -62,7 +61,7 @@ public class MetadataReplicationIT { } @Rule - public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath); + public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath, this); @BeforeClass public static void setUp() throws Exception { @@ -89,7 +88,7 @@ public class MetadataReplicationIT { LOGGER.info("Instance is in ACTIVE state."); } - @After + @RetainLogsRule.After public void after() throws Exception { LOGGER.info("Destroying instance..."); AsterixInstallerIntegrationUtil.deinit(); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/ReplicationIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/ReplicationIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/ReplicationIT.java index 44ce7f8..21f382b 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/ReplicationIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/ReplicationIT.java @@ -29,7 +29,6 @@ import org.apache.asterix.test.base.RetainLogsRule; import org.apache.asterix.test.common.TestExecutor; import org.apache.asterix.testframework.context.TestCaseContext; import org.apache.hyracks.util.file.FileUtil; -import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -60,7 +59,7 @@ public class ReplicationIT { } @Rule - public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath); + public TestRule retainLogs = new RetainLogsRule(AsterixInstallerIntegrationUtil.getManagixHome(), reportPath, this); @BeforeClass public static void setUp() throws Exception { @@ -86,7 +85,7 @@ public class ReplicationIT { LOGGER.info("Instance is in ACTIVE state."); } - @After + @RetainLogsRule.After public void after() throws Exception { LOGGER.info("Destroying instance..."); AsterixInstallerIntegrationUtil.deinit(); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/DmlRecoveryIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/DmlRecoveryIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/DmlRecoveryIT.java index a2968a5..4f04e79 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/DmlRecoveryIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/DmlRecoveryIT.java @@ -60,7 +60,7 @@ public class DmlRecoveryIT { private final TestExecutor testExecutor = new TestExecutor(); @Rule - public TestRule retainLogs = new RetainLogsRule(managixHomePath, reportPath); + public TestRule retainLogs = new RetainLogsRule(managixHomePath, reportPath, this); @BeforeClass public static void setUp() throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/RecoveryIT.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/RecoveryIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/RecoveryIT.java index a0612cc..0e7ac8b 100644 --- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/RecoveryIT.java +++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/transaction/RecoveryIT.java @@ -58,7 +58,7 @@ public class RecoveryIT { private final TestExecutor testExecutor = new TestExecutor(); @Rule - public TestRule retainLogs = new RetainLogsRule(managixHomePath, reportPath); + public TestRule retainLogs = new RetainLogsRule(managixHomePath, reportPath, this); @BeforeClass public static void setUp() throws Exception { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java index 48937f8..64ef5c2 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java @@ -19,6 +19,7 @@ package org.apache.asterix.runtime.utils; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -35,6 +36,8 @@ import org.apache.asterix.common.api.IClusterManagementWork.ClusterState; import org.apache.asterix.common.cluster.ClusterPartition; import org.apache.asterix.common.cluster.IClusterStateManager; import org.apache.asterix.common.config.ClusterProperties; +import org.apache.asterix.common.exceptions.AsterixException; +import org.apache.asterix.common.exceptions.ErrorCode; import org.apache.asterix.common.replication.IFaultToleranceStrategy; import org.apache.asterix.event.schema.cluster.Cluster; import org.apache.asterix.event.schema.cluster.Node; @@ -249,8 +252,8 @@ public class ClusterStateManager implements IClusterStateManager { clusterActiveLocations.add(p.getActiveNodeId()); } } - clusterPartitionConstraint = - new AlgebricksAbsolutePartitionConstraint(clusterActiveLocations.toArray(new String[] {})); + clusterPartitionConstraint = new AlgebricksAbsolutePartitionConstraint( + clusterActiveLocations.toArray(new String[] {})); } public boolean isGlobalRecoveryCompleted() { @@ -350,4 +353,34 @@ public class ClusterStateManager implements IClusterStateManager { public String getCurrentMetadataNodeId() { return currentMetadataNode; } + + @Override + public synchronized void registerNodePartitions(String nodeId, ClusterPartition[] nodePartitions) + throws AsterixException { + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Registering node partitions for node " + nodeId + ": " + Arrays.toString(nodePartitions)); + } + // We want to make sure there are no conflicts; make two passes for simplicity... + for (ClusterPartition nodePartition : nodePartitions) { + if (clusterPartitions.containsKey(nodePartition.getPartitionId())) { + throw AsterixException.create(ErrorCode.DUPLICATE_PARTITION_ID, nodePartition.getPartitionId(), nodeId, + clusterPartitions.get(nodePartition.getPartitionId()).getNodeId()); + } + } + for (ClusterPartition nodePartition : nodePartitions) { + clusterPartitions.put(nodePartition.getPartitionId(), nodePartition); + } + node2PartitionsMap.put(nodeId, nodePartitions); + } + + @Override + public synchronized void deregisterNodePartitions(String nodeId) { + ClusterPartition [] nodePartitions = node2PartitionsMap.remove(nodeId); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("Deegistering node partitions for node " + nodeId + ": " + Arrays.toString(nodePartitions)); + } + for (ClusterPartition nodePartition : nodePartitions) { + clusterPartitions.remove(nodePartition.getPartitionId()); + } + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java b/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java index b1f0892..64e328a 100644 --- a/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java +++ b/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java @@ -31,7 +31,9 @@ public class AlgebricksException extends Exception { private final int errorCode; private final Serializable[] params; private final String nodeId; - private transient volatile String msgCache; + + @SuppressWarnings("squid:S1165") // exception class not final + private transient CachedMessage msgCache; public AlgebricksException(String component, int errorCode, String message, Throwable cause, String nodeId, Serializable... params) { @@ -42,16 +44,12 @@ public class AlgebricksException extends Exception { this.params = params; } - public static AlgebricksException create(int errorCode, Serializable... params) { - return new AlgebricksException(ErrorCode.HYRACKS, errorCode, ErrorCode.getErrorMessage(errorCode), params); - } - /** * @deprecated Error code is needed. */ @Deprecated public AlgebricksException(String message) { - this(ErrorMessageUtil.NONE, UNKNOWN, message, null, null); + this(ErrorMessageUtil.NONE, UNKNOWN, message, null, (Serializable[]) null); } /** @@ -59,23 +57,7 @@ public class AlgebricksException extends Exception { */ @Deprecated public AlgebricksException(Throwable cause) { - this(ErrorMessageUtil.NONE, UNKNOWN, cause.getMessage(), cause, null); - } - - /** - * @deprecated Error code is needed. - */ - @Deprecated - public AlgebricksException(Throwable cause, String nodeId) { - this(ErrorMessageUtil.NONE, UNKNOWN, cause.getMessage(), cause, nodeId); - } - - /** - * @deprecated Error code is needed. - */ - @Deprecated - public AlgebricksException(String message, Throwable cause, String nodeId) { - this(ErrorMessageUtil.NONE, UNKNOWN, message, cause, nodeId); + this(ErrorMessageUtil.NONE, UNKNOWN, cause.getMessage(), cause, (Serializable[]) null); } /** @@ -107,6 +89,10 @@ public class AlgebricksException extends Exception { this(component, errorCode, message, cause, null, params); } + public static AlgebricksException create(int errorCode, Serializable... params) { + return new AlgebricksException(ErrorCode.HYRACKS, errorCode, ErrorCode.getErrorMessage(errorCode), params); + } + public String getComponent() { return component; } @@ -122,10 +108,17 @@ public class AlgebricksException extends Exception { @Override public String getMessage() { if (msgCache == null) { - synchronized (this) { - msgCache = ErrorMessageUtil.formatMessage(component, errorCode, super.getMessage(), params); - } + msgCache = new CachedMessage( + ErrorMessageUtil.formatMessage(component, errorCode, super.getMessage(), params)); + } + return msgCache.message; + } + + private static class CachedMessage { + private final String message; + + private CachedMessage(String message) { + this.message = message; } - return msgCache; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java index 390e2b5..467d148 100644 --- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java +++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java @@ -19,7 +19,6 @@ package org.apache.hyracks.api.util; -import java.io.IOError; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -30,8 +29,6 @@ import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.hyracks.api.exceptions.ErrorCode; - public class ErrorMessageUtil { private static final Logger LOGGER = Logger.getLogger(ErrorMessageUtil.class.getName()); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java index d6d8bc4..47e78a3 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java @@ -84,19 +84,14 @@ public class NodeManager implements INodeManager { } // Updates the node registry. if (nodeRegistry.containsKey(nodeId)) { - LOGGER.warning("Node with name " + nodeId + " has already registered."); - return; + LOGGER.warning("Node with name " + nodeId + " has already registered; re-registering"); } nodeRegistry.put(nodeId, ncState); // Updates the IP address to node names map. try { InetAddress ipAddress = getIpAddress(ncState); - Set<String> nodes = ipAddressNodeNameMap.get(ipAddress); - if (nodes == null) { - nodes = new HashSet<>(); - ipAddressNodeNameMap.put(ipAddress, nodes); - } + Set<String> nodes = ipAddressNodeNameMap.computeIfAbsent(ipAddress, k -> new HashSet<>()); nodes.add(nodeId); } catch (HyracksException e) { // If anything fails, we ignore the node. http://git-wip-us.apache.org/repos/asf/asterixdb/blob/ae50ba3f/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java index 45763fa..c11deef 100644 --- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java +++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java @@ -19,6 +19,7 @@ package org.apache.hyracks.http.server.utils; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -74,6 +75,10 @@ public class HttpUtil { return request.method() == HttpMethod.POST ? PostRequest.create(request) : BaseRequest.create(request); } + public static String getRequestBody(IServletRequest request) { + return request.getHttpRequest().content().toString(StandardCharsets.UTF_8); + } + public static void setContentType(IServletResponse response, String type, String charset) throws IOException { response.setHeader(HttpHeaderNames.CONTENT_TYPE, type + "; charset=" + charset); }