Michael Blow has uploaded a new change for review.
https://asterix-gerrit.ics.uci.edu/1785
Change subject: Enable Adding Nodes to Running *DB Cluster
......................................................................
Enable Adding Nodes to Running *DB Cluster
Also ability to configure unique partition ids without having access to
all NC configuration, with new nc config option
Change-Id: If978442a95687c00ef78c89ed1b4440f5e308b99
---
M
asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
M
asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
M
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/NodeProperties.java
M
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/PropertiesAccessor.java
M
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
M
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
M
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/utils/ClusterStateManager.java
M
hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
8 files changed, 75 insertions(+), 44 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/85/1785/1
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..6f6a55f 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,12 +21,20 @@
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;
import java.util.logging.Logger;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.asterix.algebra.base.ILangExtension;
import org.apache.asterix.api.http.servlet.ServletConstants;
import org.apache.asterix.common.api.IApplicationContext;
@@ -55,17 +63,6 @@
import org.apache.hyracks.http.api.IServletResponse;
import org.apache.hyracks.http.server.utils.HttpUtil;
import org.apache.hyracks.util.JSONUtil;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpResponseStatus;
public class QueryServiceServlet extends AbstractQueryApiServlet {
private static final Logger LOGGER =
Logger.getLogger(QueryServiceServlet.class.getName());
@@ -320,7 +317,7 @@
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 +330,7 @@
} 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()));
@@ -341,10 +338,6 @@
param.clientContextID =
request.getParameter(Parameter.CLIENT_ID.str());
}
return param;
- }
-
- private static String getRequestBody(IServletRequest request) throws
IOException {
- return
request.getHttpRequest().content().toString(StandardCharsets.UTF_8);
}
private static ResultDelivery parseResultDelivery(String mode) {
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..d655c94 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,12 +22,16 @@
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;
import java.util.logging.Logger;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.asterix.app.result.ResultReader;
import org.apache.asterix.app.translator.QueryTranslator;
import org.apache.asterix.common.config.GlobalConfig;
@@ -53,13 +57,6 @@
import org.apache.hyracks.http.api.IServletResponse;
import org.apache.hyracks.http.server.AbstractServlet;
import org.apache.hyracks.http.server.utils.HttpUtil;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import io.netty.handler.codec.http.HttpMethod;
-import io.netty.handler.codec.http.HttpResponseStatus;
public abstract class RestApiServlet extends AbstractServlet {
private static final Logger LOGGER =
Logger.getLogger(RestApiServlet.class.getName());
@@ -222,7 +219,7 @@
//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);
}
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..432e219 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 @@
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"),
+ 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 @@
@Override
public boolean hidden() {
- return this == INITIAL_RUN;
+ return this == INITIAL_RUN || this == PARTITION_ID;
}
}
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..26c714d 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
@@ -92,14 +92,14 @@
// 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
}
@@ -153,8 +153,8 @@
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 +175,12 @@
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 +230,20 @@
extensions.add(new AsterixExtension(className, kvs));
}
- private void configureNc(String ncId, MutableInt uniquePartitionId) {
+ private void configureNc(ConfigManager configManager, String ncId,
MutableInt uniquePartitionId) {
// 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.PARTITION_ID);
+ if (partitionId != -1) {
+ uniquePartitionId.setValue(partitionId);
+ } else {
+ configManager.set(ncId, NodeProperties.Option.PARTITION_ID,
uniquePartitionId.getValue());
+ }
// Now we create an array of ClusterPartitions for all the partitions
// on this NC.
diff --git
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
index b647bb7..49b32c0 100644
---
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
+++
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataManagerUtil.java
@@ -124,6 +124,11 @@
return new DefaultNodeGroupDomain(partitions);
}
+ public static List<String> findNodes(MetadataTransactionContext mdTxnCtx,
String nodeGroupName)
+ throws AlgebricksException {
+ return MetadataManager.INSTANCE.getNodegroup(mdTxnCtx,
nodeGroupName).getNodeNames();
+ }
+
public static Feed findFeed(MetadataTransactionContext mdTxnCtx, String
dataverse, String feedName)
throws AlgebricksException {
try {
diff --git
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
index 69f4e03..8ca1c96 100644
---
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
+++
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
@@ -302,6 +302,10 @@
return MetadataManagerUtil.findNodeDomain(mdTxnCtx, nodeGroupName);
}
+ public List<String> findNodes(String nodeGroupName) throws
AlgebricksException {
+ return MetadataManagerUtil.findNodes(mdTxnCtx, nodeGroupName);
+ }
+
public IAType findType(String dataverse, String typeName) throws
AlgebricksException {
return MetadataManagerUtil.findType(mdTxnCtx, dataverse, typeName);
}
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..2b5a8c3 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
@@ -18,6 +18,8 @@
*/
package org.apache.asterix.runtime.utils;
+import static
org.apache.hyracks.control.common.controllers.NCConfig.Option.IODEVICES;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -26,6 +28,7 @@
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
+import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@@ -35,6 +38,7 @@
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.config.NodeProperties;
import org.apache.asterix.common.replication.IFaultToleranceStrategy;
import org.apache.asterix.event.schema.cluster.Cluster;
import org.apache.asterix.event.schema.cluster.Node;
@@ -86,8 +90,8 @@
public void setCcAppCtx(CcApplicationContext appCtx) {
this.appCtx = appCtx;
- node2PartitionsMap =
appCtx.getMetadataProperties().getNodePartitions();
- clusterPartitions =
appCtx.getMetadataProperties().getClusterPartitions();
+ node2PartitionsMap = new HashMap<>();
+ clusterPartitions = new TreeMap<>();
currentMetadataNode =
appCtx.getMetadataProperties().getMetadataNodeName();
ftStrategy = appCtx.getFaultToleranceStrategy();
ftStrategy.bindTo(this);
@@ -109,6 +113,20 @@
activeNcConfiguration.put(nodeId, configuration);
failedNodes.remove(nodeId);
ftStrategy.notifyNodeJoin(nodeId);
+
+ // Now we create an array of ClusterPartitions for all the partitions
+ // on this NC.
+ String[] iodevices = (String[]) configuration.get(IODEVICES);
+ int partitionId = (int)
configuration.get(NodeProperties.Option.PARTITION_ID);
+ ClusterPartition[] nodePartitions = new
ClusterPartition[iodevices.length];
+ for (int i = 0; i < nodePartitions.length; i++) {
+ // Create ClusterPartition instances for this NC.
+ ClusterPartition partition = new ClusterPartition(partitionId++,
nodeId, i);
+ clusterPartitions.put(partition.getPartitionId(), partition);
+ nodePartitions[i] = partition;
+ }
+ node2PartitionsMap.put(nodeId, nodePartitions);
+
}
@Override
@@ -249,8 +267,8 @@
clusterActiveLocations.add(p.getActiveNodeId());
}
}
- clusterPartitionConstraint =
- new
AlgebricksAbsolutePartitionConstraint(clusterActiveLocations.toArray(new
String[] {}));
+ clusterPartitionConstraint = new AlgebricksAbsolutePartitionConstraint(
+ clusterActiveLocations.toArray(new String[] {}));
}
public boolean isGlobalRecoveryCompleted() {
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 @@
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);
}
--
To view, visit https://asterix-gerrit.ics.uci.edu/1785
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If978442a95687c00ef78c89ed1b4440f5e308b99
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Michael Blow <[email protected]>