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]>

Reply via email to