From 2b69b853d0d9f163fc30de20b3e27df1ebeee7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Fri, 25 Sep 2020 01:48:04 +0800 Subject: [PATCH 01/22] feature. add update and delete operation on instance's metadata 90% --- .../nacos/api/naming/utils/NamingUtils.java | 21 +++++ .../controllers/InstanceController.java | 37 ++------ .../controllers/OperatorController.java | 85 ++++++++++++++++++- .../nacos/naming/core/ServiceManager.java | 57 +++++++++++++ .../nacos/naming/misc/UtilsAndCommons.java | 4 + .../controllers/InstanceControllerTest.java | 7 ++ 6 files changed, 180 insertions(+), 31 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java index 9faa8b40bf9..5e3941fed88 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java @@ -54,4 +54,25 @@ public static String getGroupName(final String serviceNameWithGroup) { } return serviceNameWithGroup.split(Constants.SERVICE_INFO_SPLITER)[0]; } + + /** + * check combineServiceName format. the serviceName can't be blank. some relational logic in + * com.alibaba.nacos.naming.web.DistroFilter#doFilter, it will handle combineServiceName in some case, you should + * know it. + *
+     * serviceName = "@@"; the length = 0; illegal
+     * serviceName = "group@@"; the length = 1; illegal
+     * serviceName = "@@serviceName"; the length = 2; legal
+     * serviceName = "group@@serviceName"; the length = 2; legal
+     * 
+ * + * @param combineServiceName such as: groupName@@serviceName + */ + public static void checkServiceNameFormat(String combineServiceName) { + String[] split = combineServiceName.split(Constants.SERVICE_INFO_SPLITER); + if (split.length <= 1) { + throw new IllegalArgumentException( + "Param 'serviceName' is illegal, it should be format as 'groupName@@serviceName"); + } + } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index 5f1ae15a362..cf79e985272 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -38,7 +38,6 @@ import com.alibaba.nacos.naming.push.DataSource; import com.alibaba.nacos.naming.push.PushService; import com.alibaba.nacos.naming.web.CanDistro; -import com.alibaba.nacos.naming.web.DistroFilter; import com.alibaba.nacos.naming.web.NamingResourceParser; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -119,7 +118,7 @@ public String register(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); final Instance instance = parseInstance(request); @@ -141,7 +140,7 @@ public String deregister(HttpServletRequest request) throws Exception { Instance instance = getIpAddress(request); String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { @@ -167,7 +166,7 @@ public String update(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); final Instance instance = parseInstance(request); String agent = WebUtils.getUserAgent(request); @@ -196,7 +195,7 @@ public String update(HttpServletRequest request) throws Exception { public String patch(HttpServletRequest request) throws Exception { String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); String ip = WebUtils.required(request, "ip"); String port = WebUtils.required(request, "port"); String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY); @@ -248,7 +247,7 @@ public ObjectNode list(HttpServletRequest request) throws Exception { String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); String agent = WebUtils.getUserAgent(request); String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY); @@ -280,7 +279,7 @@ public ObjectNode detail(HttpServletRequest request) throws Exception { String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME); String ip = WebUtils.required(request, "ip"); int port = Integer.parseInt(WebUtils.required(request, "port")); @@ -353,7 +352,7 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { } String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}", clientBeat, serviceName); Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port); @@ -421,7 +420,7 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc namespaceId = Constants.DEFAULT_NAMESPACE_ID; serviceName = key; } - checkServiceNameFormat(serviceName); + NamingUtils.checkServiceNameFormat(serviceName); Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { @@ -441,26 +440,6 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc return result; } - /** - * check combineServiceName format. the serviceName can't be blank. some relational logic in {@link - * DistroFilter#doFilter}, it will handle combineServiceName in some case, you should know it. - *
-     * serviceName = "@@"; the length = 0; illegal
-     * serviceName = "group@@"; the length = 1; illegal
-     * serviceName = "@@serviceName"; the length = 2; legal
-     * serviceName = "group@@serviceName"; the length = 2; legal
-     * 
- * - * @param combineServiceName such as: groupName@@serviceName - */ - private void checkServiceNameFormat(String combineServiceName) { - String[] split = combineServiceName.split(Constants.SERVICE_INFO_SPLITER); - if (split.length <= 1) { - throw new IllegalArgumentException( - "Param 'serviceName' is illegal, it should be format as 'groupName@@serviceName"); - } - } - private Instance parseInstance(HttpServletRequest request) throws Exception { String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java index 180c931415f..be2c40f3691 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java @@ -17,17 +17,20 @@ package com.alibaba.nacos.naming.controllers; import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.naming.CommonParams; +import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.auth.annotation.Secured; import com.alibaba.nacos.auth.common.ActionTypes; import com.alibaba.nacos.common.utils.JacksonUtils; import com.alibaba.nacos.core.cluster.Member; import com.alibaba.nacos.core.cluster.NodeState; import com.alibaba.nacos.core.cluster.ServerMemberManager; -import com.alibaba.nacos.sys.utils.ApplicationUtils; +import com.alibaba.nacos.core.utils.WebUtils; import com.alibaba.nacos.naming.cluster.ServerListManager; import com.alibaba.nacos.naming.cluster.ServerStatusManager; import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore; import com.alibaba.nacos.naming.core.DistroMapper; +import com.alibaba.nacos.naming.core.Instance; import com.alibaba.nacos.naming.core.Service; import com.alibaba.nacos.naming.core.ServiceManager; import com.alibaba.nacos.naming.misc.Loggers; @@ -36,11 +39,15 @@ import com.alibaba.nacos.naming.misc.SwitchManager; import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.naming.push.PushService; +import com.alibaba.nacos.naming.web.CanDistro; +import com.alibaba.nacos.naming.web.NamingResourceParser; +import com.alibaba.nacos.sys.utils.ApplicationUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; - +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -53,6 +60,9 @@ import java.util.ArrayList; import java.util.List; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE; + /** * Operation for operators. * @@ -284,4 +294,75 @@ public String setLogLevel(@RequestParam String logName, @RequestParam String log public JsonNode getClusterStates() { return JacksonUtils.transferToJsonNode(serviceManager.getMySelfClusterState()); } + + /** + * Update instance's metadata. old key exist = update, old key not exist = add. + * + * @param request http request + * @return 'ok' if success + * @throws Exception any error during update + */ + @CanDistro + @PutMapping(value = "/instance/metadata") + @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) + public String updateInstanceMatadata(HttpServletRequest request) throws Exception { + final String namespaceId = WebUtils + .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); + NamingUtils.checkServiceNameFormat(serviceName); + + Instance instance = parseMetaInstance(request); + + serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_UPDATE); + return "ok"; + } + + + /** + * delete instance's metadata. old key exist = delete, old key not exist = not operate + * + * @param request http request + * @return 'ok' if success + * @throws Exception any error during update + */ + @CanDistro + @DeleteMapping("/instance/metadata") + @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) + public String deleteInstanceMatadata(HttpServletRequest request) throws Exception { + final String namespaceId = WebUtils + .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); + NamingUtils.checkServiceNameFormat(serviceName); + + Instance instance = parseMetaInstance(request); + + serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_REMOVE); + return "ok"; + } + + private Instance parseMetaInstance(HttpServletRequest request) throws Exception { + + final String ip = WebUtils.required(request, "ip"); + final String port = WebUtils.required(request, "port"); + String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY); + if (StringUtils.isBlank(cluster)) { + cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME); + } + boolean ephemeral = BooleanUtils.toBoolean( + WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral()))); + Instance instance = new Instance(); + instance.setPort(Integer.parseInt(port)); + instance.setIp(ip); + instance.setEphemeral(ephemeral); + instance.setClusterName(cluster); + + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); + instance.setServiceName(serviceName); + String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY); + if (StringUtils.isNotEmpty(metadata)) { + instance.setMetadata(UtilsAndCommons.parseMetadata(metadata)); + } + return instance; + } + } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index e5d82c89ab5..574af1cb928 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -64,6 +64,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE; + /** * Core manager storing all services in Nacos. * @@ -524,6 +527,60 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); } + /** + * Update instance's metadata. + * + * @param namespaceId namespace + * @param serviceName service name + * @param instance instance + * @throws NacosException nacos exception + */ + public void updateMetadata(String namespaceId, String serviceName, Instance instance, String action) + throws NacosException { + + Service service = getService(namespaceId, serviceName); + + if (service == null) { + throw new NacosException(NacosException.INVALID_PARAM, + "service not found, namespace: " + namespaceId + ", service: " + serviceName); + } + + //need the newest data, + Datum datum = consistencyService.get(KeyBuilder + .buildInstanceListKey(service.getNamespaceId(), service.getName(), instance.isEphemeral())); + Instance oldInstance = locateInstance(((Instances) datum.value).getInstanceList(), instance); + + if (oldInstance == null) { + throw new NacosException(NacosException.INVALID_PARAM, "instance not exist: " + instance); + } + + if (UPDATE_INSTANCE_METADATA_ACTION_UPDATE.equals(action)) { + oldInstance.getMetadata().putAll(instance.getMetadata()); + } else if (UPDATE_INSTANCE_METADATA_ACTION_REMOVE.equals(action)) { + Set keys = instance.getMetadata().keySet(); + for (String key : keys) { + oldInstance.getMetadata().remove(key); + } + } + + addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); + } + + private Instance locateInstance(List instances, Instance instance) { + int target = 0; + while (target >= 0) { + target = instances.indexOf(instance); + if (target > 0) { + Instance result = instances.get(target); + if (result.getClusterName().equals(instance.getClusterName())) { + return result; + } + instances.remove(target); + } + } + return null; + } + /** * Add instance to service. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java index bc973da4c8d..14055ea8d01 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java @@ -115,6 +115,10 @@ public class UtilsAndCommons { public static final String UPDATE_INSTANCE_ACTION_REMOVE = "remove"; + public static final String UPDATE_INSTANCE_METADATA_ACTION_UPDATE = "update"; + + public static final String UPDATE_INSTANCE_METADATA_ACTION_REMOVE = "remove"; + public static final String DATA_BASE_DIR = ApplicationUtils.getNacosHome() + File.separator + "data" + File.separator + "naming"; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java index d8b859c0b54..7996e84ef97 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java @@ -156,4 +156,11 @@ public void getNullServiceInstances() throws Exception { JsonNode hosts = result.get("hosts"); Assert.assertEquals(hosts.size(), 0); } + + @Test + public void updateMetaData() throws Exception { + + registerInstance(); + + } } From 43c63ff012aa7c3ed77cc2b05880b1f81bc420a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Fri, 25 Sep 2020 11:30:55 +0800 Subject: [PATCH 02/22] 1.add unit test 2.fix-locateInstance error --- .../nacos/naming/core/ServiceManager.java | 14 ++--- .../nacos/naming/core/ServiceManagerTest.java | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index 574af1cb928..a82164134ee 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -545,32 +545,32 @@ public void updateMetadata(String namespaceId, String serviceName, Instance inst "service not found, namespace: " + namespaceId + ", service: " + serviceName); } - //need the newest data, + //need the newest data from consistencyService Datum datum = consistencyService.get(KeyBuilder .buildInstanceListKey(service.getNamespaceId(), service.getName(), instance.isEphemeral())); - Instance oldInstance = locateInstance(((Instances) datum.value).getInstanceList(), instance); + Instance updateInstance = locateInstance(((Instances) datum.value).getInstanceList(), instance); - if (oldInstance == null) { + if (updateInstance == null) { throw new NacosException(NacosException.INVALID_PARAM, "instance not exist: " + instance); } if (UPDATE_INSTANCE_METADATA_ACTION_UPDATE.equals(action)) { - oldInstance.getMetadata().putAll(instance.getMetadata()); + updateInstance.getMetadata().putAll(instance.getMetadata()); } else if (UPDATE_INSTANCE_METADATA_ACTION_REMOVE.equals(action)) { Set keys = instance.getMetadata().keySet(); for (String key : keys) { - oldInstance.getMetadata().remove(key); + updateInstance.getMetadata().remove(key); } } - addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); + addInstance(namespaceId, serviceName, instance.isEphemeral(), updateInstance); } private Instance locateInstance(List instances, Instance instance) { int target = 0; while (target >= 0) { target = instances.indexOf(instance); - if (target > 0) { + if (target >= 0) { Instance result = instances.get(target); if (result.getClusterName().equals(instance.getClusterName())) { return result; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java index d51bb4bffda..961e7b3ad9c 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java @@ -38,10 +38,14 @@ import org.springframework.test.util.ReflectionTestUtils; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -97,6 +101,9 @@ private void mockCluster() { private void mockInstance() { instance = new Instance("1.1.1.1", 1, TEST_CLUSTER_NAME); + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + instance.setMetadata(metadata); instance2 = new Instance("2.2.2.2", 2); } @@ -214,6 +221,57 @@ public void testUpdateInstance() throws NacosException { verify(consistencyService).put(eq(instanceListKey), any(Instances.class)); } + @Test + public void testUpdateMetadata() throws NacosException { + + serviceManager.createEmptyService(TEST_NAMESPACE, TEST_SERVICE_NAME, true); + + List instanceList = new LinkedList<>(); + Datum datam = new Datum(); + datam.key = KeyBuilder.buildInstanceListKey(TEST_NAMESPACE, TEST_SERVICE_NAME, true); + Instances instances = new Instances(); + instanceList.add(instance); + instances.setInstanceList(instanceList); + datam.value = instances; + when(consistencyService.get(KeyBuilder.buildInstanceListKey(TEST_NAMESPACE, TEST_SERVICE_NAME, true))) + .thenReturn(datam); + + Instance updateMetadataInstance = new Instance(); + updateMetadataInstance.setIp(instance.getIp()); + updateMetadataInstance.setPort(instance.getPort()); + updateMetadataInstance.setClusterName(cluster.getName()); + updateMetadataInstance.setEphemeral(instance.isEphemeral()); + Map updateMetadata = new HashMap<>(16); + updateMetadata.put("key1", "new-value1"); + updateMetadata.put("key2", "value2"); + updateMetadataInstance.setMetadata(updateMetadata); + + serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance, + UPDATE_INSTANCE_METADATA_ACTION_UPDATE); + + assertEquals(instance.getMetadata().get("key1"), "new-value1"); + assertEquals(instance.getMetadata().get("key2"), "value2"); + + Instance deleteMetadataInstance = new Instance(); + deleteMetadataInstance.setIp(instance.getIp()); + deleteMetadataInstance.setPort(instance.getPort()); + deleteMetadataInstance.setClusterName(cluster.getName()); + deleteMetadataInstance.setEphemeral(instance.isEphemeral()); + Map deleteMetadata = new HashMap<>(16); + deleteMetadata.put("key2", null); + deleteMetadata.put("key3", null); + updateMetadataInstance.setMetadata(deleteMetadata); + + serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance, + UPDATE_INSTANCE_METADATA_ACTION_REMOVE); + + assertEquals(instance.getMetadata().get("key1"), "new-value1"); + assertNull(instance.getMetadata().get("key2")); + assertNull(instance.getMetadata().get("key3")); + + + } + @Test public void testRemoveInstance() throws NacosException { serviceManager.createEmptyService(TEST_NAMESPACE, TEST_SERVICE_NAME, true); From 21ae919c8ca9cebc5dddcb29b044a976aaeb3e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Fri, 25 Sep 2020 12:36:36 +0800 Subject: [PATCH 03/22] format code style --- .../java/com/alibaba/nacos/naming/core/ServiceManagerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java index 961e7b3ad9c..3eebe8151f5 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java @@ -268,8 +268,6 @@ public void testUpdateMetadata() throws NacosException { assertEquals(instance.getMetadata().get("key1"), "new-value1"); assertNull(instance.getMetadata().get("key2")); assertNull(instance.getMetadata().get("key3")); - - } @Test From 5224bdecaf795113434c82352e9639a79f7125cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Fri, 25 Sep 2020 13:53:35 +0800 Subject: [PATCH 04/22] add @link on class --- .../java/com/alibaba/nacos/api/naming/utils/NamingUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java index 5e3941fed88..2f0d6e26246 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java @@ -56,8 +56,8 @@ public static String getGroupName(final String serviceNameWithGroup) { } /** - * check combineServiceName format. the serviceName can't be blank. some relational logic in - * com.alibaba.nacos.naming.web.DistroFilter#doFilter, it will handle combineServiceName in some case, you should + * check combineServiceName format. the serviceName can't be blank. some relational logic in {@link + * com.alibaba.nacos.naming.web.DistroFilter#doFilter}, it will handle combineServiceName in some case, you should * know it. *
      * serviceName = "@@"; the length = 0; illegal

From 52c8c91da5864387ac7df2b3e591ecd0195574cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Sat, 26 Sep 2020 16:43:32 +0800
Subject: [PATCH 05/22] move metadata operate to InstanceController.

---
 .../controllers/InstanceController.java       | 115 ++++++++++++++++--
 .../controllers/OperatorController.java       |  82 -------------
 2 files changed, 106 insertions(+), 91 deletions(-)

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index cf79e985272..5994cc71148 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -64,6 +64,9 @@
 import java.util.List;
 import java.util.Map;
 
+import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE;
+import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE;
+
 /**
  * Instance operation controller.
  *
@@ -182,6 +185,78 @@ public String update(HttpServletRequest request) throws Exception {
         return "ok";
     }
     
+    /**
+     * Update instance's metadata. old key exist = update, old key not exist = add.
+     *
+     * @param request http request
+     * @return 'ok' if success
+     * @throws Exception any error during update
+     */
+    @CanDistro
+    @PutMapping(value = "/metadata")
+    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
+    public String updateInstanceMatadata(HttpServletRequest request) throws Exception {
+        final String namespaceId = WebUtils
+                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
+        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
+        NamingUtils.checkServiceNameFormat(serviceName);
+        
+        Instance instance = parseMetaInstance(request);
+        
+        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
+        return "ok";
+    }
+    
+    /**
+     * Batch update instance's metadata. old key exist = update, old key not exist = add.
+     *
+     * @param request http request
+     * @return 'ok' if success
+     * @throws Exception any error during update
+     */
+    @CanDistro
+    @PutMapping(value = "/metadata/batch")
+    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
+    public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exception {
+        return "ok";
+    }
+    
+    /**
+     * Delete instance's metadata. old key exist = delete, old key not exist = not operate
+     *
+     * @param request http request
+     * @return 'ok' if success
+     * @throws Exception any error during update
+     */
+    @CanDistro
+    @DeleteMapping("/metadata")
+    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
+    public String deleteInstanceMatadata(HttpServletRequest request) throws Exception {
+        final String namespaceId = WebUtils
+                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
+        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
+        NamingUtils.checkServiceNameFormat(serviceName);
+        
+        Instance instance = parseMetaInstance(request);
+        
+        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
+        return "ok";
+    }
+    
+    /**
+     * Batch delete instance's metadata. old key exist = delete, old key not exist = not operate
+     *
+     * @param request http request
+     * @return 'ok' if success
+     * @throws Exception any error during update
+     */
+    @CanDistro
+    @DeleteMapping("/metadata/batch")
+    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
+    public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exception {
+        return "ok";
+    }
+    
     /**
      * Patch instance.
      *
@@ -440,6 +515,20 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc
         return result;
     }
     
+    private Instance parseMetaInstance(HttpServletRequest request) throws Exception {
+        
+        Instance basicInstance = getBasicIpAddress(request);
+        
+        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
+        basicInstance.setServiceName(serviceName);
+        
+        String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
+        if (StringUtils.isNotEmpty(metadata)) {
+            basicInstance.setMetadata(UtilsAndCommons.parseMetadata(metadata));
+        }
+        return basicInstance;
+    }
+    
     private Instance parseInstance(HttpServletRequest request) throws Exception {
         
         String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
@@ -461,13 +550,28 @@ private Instance parseInstance(HttpServletRequest request) throws Exception {
         return instance;
     }
     
-    private Instance getIpAddress(HttpServletRequest request) {
+    private Instance getBasicIpAddress(HttpServletRequest request) {
+        
         final String ip = WebUtils.required(request, "ip");
         final String port = WebUtils.required(request, "port");
         String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
         if (StringUtils.isBlank(cluster)) {
             cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
         }
+        boolean ephemeral = BooleanUtils.toBoolean(
+                WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
+        
+        Instance instance = new Instance();
+        instance.setPort(Integer.parseInt(port));
+        instance.setIp(ip);
+        instance.setEphemeral(ephemeral);
+        instance.setClusterName(cluster);
+        
+        return instance;
+    }
+    
+    private Instance getIpAddress(HttpServletRequest request) {
+        
         String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY);
         boolean enabled;
         if (StringUtils.isBlank(enabledString)) {
@@ -476,20 +580,13 @@ private Instance getIpAddress(HttpServletRequest request) {
             enabled = BooleanUtils.toBoolean(enabledString);
         }
         
-        boolean ephemeral = BooleanUtils.toBoolean(
-                WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
-        
         String weight = WebUtils.optional(request, "weight", "1");
         boolean healthy = BooleanUtils.toBoolean(WebUtils.optional(request, "healthy", "true"));
         
-        Instance instance = new Instance();
-        instance.setPort(Integer.parseInt(port));
-        instance.setIp(ip);
+        Instance instance = getBasicIpAddress(request);
         instance.setWeight(Double.parseDouble(weight));
-        instance.setClusterName(cluster);
         instance.setHealthy(healthy);
         instance.setEnabled(enabled);
-        instance.setEphemeral(ephemeral);
         
         return instance;
     }
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java
index be2c40f3691..d67a46c7f4c 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/OperatorController.java
@@ -17,20 +17,16 @@
 package com.alibaba.nacos.naming.controllers;
 
 import com.alibaba.nacos.api.common.Constants;
-import com.alibaba.nacos.api.naming.CommonParams;
-import com.alibaba.nacos.api.naming.utils.NamingUtils;
 import com.alibaba.nacos.auth.annotation.Secured;
 import com.alibaba.nacos.auth.common.ActionTypes;
 import com.alibaba.nacos.common.utils.JacksonUtils;
 import com.alibaba.nacos.core.cluster.Member;
 import com.alibaba.nacos.core.cluster.NodeState;
 import com.alibaba.nacos.core.cluster.ServerMemberManager;
-import com.alibaba.nacos.core.utils.WebUtils;
 import com.alibaba.nacos.naming.cluster.ServerListManager;
 import com.alibaba.nacos.naming.cluster.ServerStatusManager;
 import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore;
 import com.alibaba.nacos.naming.core.DistroMapper;
-import com.alibaba.nacos.naming.core.Instance;
 import com.alibaba.nacos.naming.core.Service;
 import com.alibaba.nacos.naming.core.ServiceManager;
 import com.alibaba.nacos.naming.misc.Loggers;
@@ -39,15 +35,11 @@
 import com.alibaba.nacos.naming.misc.SwitchManager;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
 import com.alibaba.nacos.naming.push.PushService;
-import com.alibaba.nacos.naming.web.CanDistro;
-import com.alibaba.nacos.naming.web.NamingResourceParser;
 import com.alibaba.nacos.sys.utils.ApplicationUtils;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -60,9 +52,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE;
-import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE;
-
 /**
  * Operation for operators.
  *
@@ -294,75 +283,4 @@ public String setLogLevel(@RequestParam String logName, @RequestParam String log
     public JsonNode getClusterStates() {
         return JacksonUtils.transferToJsonNode(serviceManager.getMySelfClusterState());
     }
-    
-    /**
-     * Update instance's metadata. old key exist = update, old key not exist = add.
-     *
-     * @param request http request
-     * @return 'ok' if success
-     * @throws Exception any error during update
-     */
-    @CanDistro
-    @PutMapping(value = "/instance/metadata")
-    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String updateInstanceMatadata(HttpServletRequest request) throws Exception {
-        final String namespaceId = WebUtils
-                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        NamingUtils.checkServiceNameFormat(serviceName);
-        
-        Instance instance = parseMetaInstance(request);
-        
-        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
-        return "ok";
-    }
-    
-    
-    /**
-     * delete instance's metadata. old key exist = delete, old key not exist = not operate
-     *
-     * @param request http request
-     * @return 'ok' if success
-     * @throws Exception any error during update
-     */
-    @CanDistro
-    @DeleteMapping("/instance/metadata")
-    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String deleteInstanceMatadata(HttpServletRequest request) throws Exception {
-        final String namespaceId = WebUtils
-                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        NamingUtils.checkServiceNameFormat(serviceName);
-        
-        Instance instance = parseMetaInstance(request);
-        
-        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
-        return "ok";
-    }
-    
-    private Instance parseMetaInstance(HttpServletRequest request) throws Exception {
-        
-        final String ip = WebUtils.required(request, "ip");
-        final String port = WebUtils.required(request, "port");
-        String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
-        if (StringUtils.isBlank(cluster)) {
-            cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
-        }
-        boolean ephemeral = BooleanUtils.toBoolean(
-                WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
-        Instance instance = new Instance();
-        instance.setPort(Integer.parseInt(port));
-        instance.setIp(ip);
-        instance.setEphemeral(ephemeral);
-        instance.setClusterName(cluster);
-        
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        instance.setServiceName(serviceName);
-        String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
-        if (StringUtils.isNotEmpty(metadata)) {
-            instance.setMetadata(UtilsAndCommons.parseMetadata(metadata));
-        }
-        return instance;
-    }
-    
 }

From ba7df4ae388b34d4f972a1052447f4186b629010 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Sun, 27 Sep 2020 23:39:24 +0800
Subject: [PATCH 06/22] format code 50%

---
 .../nacos/api/naming/utils/NamingUtils.java   |  36 ++-
 .../controllers/InstanceController.java       | 255 ++++++++++++++----
 .../nacos/naming/core/ServiceManager.java     |  61 +++--
 .../nacos/naming/misc/UtilsAndCommons.java    |   2 +-
 .../nacos/naming/core/ServiceManagerTest.java |  11 +-
 5 files changed, 293 insertions(+), 72 deletions(-)

diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
index 2f0d6e26246..66d0a794970 100644
--- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
+++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
@@ -19,6 +19,8 @@
 import com.alibaba.nacos.api.common.Constants;
 import com.alibaba.nacos.api.utils.StringUtils;
 
+import java.util.Map;
+
 /**
  * NamingUtils.
  *
@@ -72,7 +74,39 @@ public static void checkServiceNameFormat(String combineServiceName) {
         String[] split = combineServiceName.split(Constants.SERVICE_INFO_SPLITER);
         if (split.length <= 1) {
             throw new IllegalArgumentException(
-                    "Param 'serviceName' is illegal, it should be format as 'groupName@@serviceName");
+                    "Param 'serviceName' is illegal, it should be format as 'groupName@@serviceName'");
+        }
+    }
+    
+    /**
+     * get target value from param, if not found will throw {@link IllegalArgumentException}.
+     *
+     * @param param param
+     * @param key   key
+     * @return value
+     */
+    public static String required(final Map param, final String key) {
+        String value = param.get(key);
+        if (StringUtils.isEmpty(value)) {
+            throw new IllegalArgumentException("Param '" + key + "' is required.");
         }
+        return value;
     }
+    
+    /**
+     * get target value from param, if not found will return default value.
+     *
+     * @param param        param
+     * @param key          key
+     * @param defaultValue default value
+     * @return value
+     */
+    public static String optional(final Map param, final String key, final String defaultValue) {
+        String value = param.get(key);
+        if (StringUtils.isBlank(value)) {
+            return defaultValue;
+        }
+        return value;
+    }
+    
 }
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index 5994cc71148..814b002bf3e 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -39,9 +39,9 @@
 import com.alibaba.nacos.naming.push.PushService;
 import com.alibaba.nacos.naming.web.CanDistro;
 import com.alibaba.nacos.naming.web.NamingResourceParser;
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -63,6 +63,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE;
 import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE;
@@ -186,75 +188,189 @@ public String update(HttpServletRequest request) throws Exception {
     }
     
     /**
-     * Update instance's metadata. old key exist = update, old key not exist = add.
+     * Batch update instance's metadata. old key exist = update, old key not exist = add.
      *
      * @param request http request
      * @return 'ok' if success
      * @throws Exception any error during update
      */
     @CanDistro
-    @PutMapping(value = "/metadata")
+    @PutMapping(value = "/metadata/batch")
     @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String updateInstanceMatadata(HttpServletRequest request) throws Exception {
+    public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exception {
         final String namespaceId = WebUtils
                 .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        NamingUtils.checkServiceNameFormat(serviceName);
         
-        Instance instance = parseMetaInstance(request);
+        String targetInstances = WebUtils.required(request, "target");
+        
+        List services = parseBatchInstances(targetInstances);
+        
+        String metadata = WebUtils.required(request, "metadata");
+        Map targetMetadata = UtilsAndCommons.parseMetadata(metadata);
+        
+        batchOperateMetadata(namespaceId, services, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
         
-        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
         return "ok";
     }
     
+    private List parseInstances(List instances) {
+        List instanceList = new ArrayList<>();
+        for (Map map : instances) {
+            Instance basicIpAddress = getBasicIpAddress(map);
+            instanceList.add(basicIpAddress);
+        }
+        return instanceList;
+    }
+    
     /**
-     * Batch update instance's metadata. old key exist = update, old key not exist = add.
+     * parse batch instance str, it should be as '[{"serviceName":"xxxx@@xxxx","instances":[{"ip":"127.0.0.1","port":
+     * 8080,"ephemeral":"true","clusterName":"xxx-cluster"}], "all":"false"}]'.
      *
-     * @param request http request
-     * @return 'ok' if success
-     * @throws Exception any error during update
+     * @param instances instances str
+     * @return instances as List
      */
-    @CanDistro
-    @PutMapping(value = "/metadata/batch")
-    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exception {
-        return "ok";
+    private List parseBatchInstances(String instances) {
+        try {
+            return JacksonUtils.toObj(instances, new TypeReference>() {
+            });
+        } catch (Exception e) {
+            Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal");
+        }
+        return new ArrayList<>();
     }
     
     /**
-     * Delete instance's metadata. old key exist = delete, old key not exist = not operate
+     * Batch delete instance's metadata. old key exist = delete, old key not exist = not operate
      *
      * @param request http request
      * @return 'ok' if success
      * @throws Exception any error during update
      */
     @CanDistro
-    @DeleteMapping("/metadata")
+    @DeleteMapping("/metadata/batch")
     @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String deleteInstanceMatadata(HttpServletRequest request) throws Exception {
+    public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exception {
         final String namespaceId = WebUtils
                 .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        NamingUtils.checkServiceNameFormat(serviceName);
         
-        Instance instance = parseMetaInstance(request);
+        String targetInstances = WebUtils.required(request, "target");
+        
+        List services = parseBatchInstances(targetInstances);
+        
+        String metadata = WebUtils.required(request, "metadata");
+        Map targetMetadata = UtilsAndCommons.parseMetadata(metadata);
+        
+        batchOperateMetadata(namespaceId, services, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
         
-        serviceManager.updateMetadata(namespaceId, serviceName, instance, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
         return "ok";
     }
     
-    /**
-     * Batch delete instance's metadata. old key exist = delete, old key not exist = not operate
-     *
-     * @param request http request
-     * @return 'ok' if success
-     * @throws Exception any error during update
-     */
-    @CanDistro
-    @DeleteMapping("/metadata/batch")
-    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
-    public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exception {
-        return "ok";
+    static class OperateDTO {
+        
+        private String namespace;
+        
+        private String serviceName;
+        
+        private Boolean ephemeral;
+        
+        private List instances;
+    }
+    
+    private void batchOperateMetadata(String namespace, List services, Map metadata) {
+        Consumer updateAllEphemeral = dto -> {
+            try {
+                serviceManager.updateMetadata(namespace, dto.serviceName, dto.ephemeral,
+                        UPDATE_INSTANCE_METADATA_ACTION_UPDATE, true, dto.instances, metadata);
+            } catch (NacosException e) {
+                //ignore
+            }
+        };
+        batchOperate(namespace, services, );
+    }
+    
+    
+    private void batchOperate(String namespace, List services, Consumer consumer) {
+        for (Map service : services) {
+            try {
+                String serviceName = (String) service.get("serviceName");
+                NamingUtils.checkServiceNameFormat(serviceName);
+                // type: */ephemeral/persist
+                String type = (String) service.get("all");
+                OperateDTO operateDTO = new OperateDTO();
+                operateDTO.serviceName = serviceName;
+                if (type != null) {
+                    if ("*".equals(type)) {
+                        operateDTO.ephemeral = true;
+                        consumer.accept(operateDTO);
+                        operateDTO.ephemeral = false;
+                        consumer.accept(operateDTO);
+                    } else if ("ephemeral".equals(type)) {
+                        operateDTO.ephemeral = true;
+                        consumer.accept(operateDTO);
+                    } else if ("persist".equals(type)) {
+                        operateDTO.ephemeral = false;
+                        consumer.accept(operateDTO);
+                    } else {
+                        Loggers.SRV_LOG.warn("UPDATE-METADATA: services.all value is illegal, ignore the service '"
+                                + serviceName + "'");
+                    }
+                } else {
+                    List instances = parseInstances((List) service.get("instances"));
+                    //ephemeral:instances
+                    Map> instanceMap = instances.stream()
+                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+                    
+                    for (Map.Entry> entry : instanceMap.entrySet()) {
+                        serviceManager.updateMetadata(namespace, serviceName, entry.getKey(),
+                                UPDATE_INSTANCE_METADATA_ACTION_REMOVE, false, entry.getValue(), metadata);
+                    }
+                }
+            } catch (NacosException e) {
+                Loggers.SRV_LOG.warn("");
+            }
+        }
+    }
+    
+    
+    private void batchOperateMetadata(String namespace, List services, Map metadata,
+            String action) {
+        for (Map service : services) {
+            try {
+                String serviceName = (String) service.get("serviceName");
+                NamingUtils.checkServiceNameFormat(serviceName);
+                // type: */ephemeral/persist
+                String type = (String) service.get("all");
+                if (type != null) {
+                    if ("*".equals(type)) {
+                        serviceManager.updateMetadata(namespace, serviceName, true, action, true, new ArrayList<>(),
+                                metadata);
+                        serviceManager.updateMetadata(namespace, serviceName, false, action, true, new ArrayList<>(),
+                                metadata);
+                    } else if ("ephemeral".equals(type)) {
+                        serviceManager.updateMetadata(namespace, serviceName, true, action, true, new ArrayList<>(),
+                                metadata);
+                    } else if ("persist".equals(type)) {
+                        serviceManager.updateMetadata(namespace, serviceName, false, action, true, new ArrayList<>(),
+                                metadata);
+                    } else {
+                        Loggers.SRV_LOG.warn("UPDATE-METADATA: services.all value is illegal, ignore the service '"
+                                + serviceName + "'");
+                    }
+                } else {
+                    List instances = parseInstances((List) service.get("instances"));
+                    //ephemeral:instances
+                    Map> instanceMap = instances.stream()
+                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+                    
+                    for (Map.Entry> entry : instanceMap.entrySet()) {
+                        serviceManager.updateMetadata(namespace, serviceName, entry.getKey(),
+                                UPDATE_INSTANCE_METADATA_ACTION_REMOVE, false, entry.getValue(), metadata);
+                    }
+                }
+            } catch (NacosException e) {
+                Loggers.SRV_LOG.warn("");
+            }
+        }
     }
     
     /**
@@ -550,22 +666,23 @@ private Instance parseInstance(HttpServletRequest request) throws Exception {
         return instance;
     }
     
-    private Instance getBasicIpAddress(HttpServletRequest request) {
+    private Instance getIpAddress(Map param) {
         
-        final String ip = WebUtils.required(request, "ip");
-        final String port = WebUtils.required(request, "port");
-        String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
-        if (StringUtils.isBlank(cluster)) {
-            cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
+        String enabledString = NamingUtils.optional(param, "enabled", StringUtils.EMPTY);
+        boolean enabled;
+        if (StringUtils.isBlank(enabledString)) {
+            enabled = BooleanUtils.toBoolean(NamingUtils.optional(param, "enable", "true"));
+        } else {
+            enabled = BooleanUtils.toBoolean(enabledString);
         }
-        boolean ephemeral = BooleanUtils.toBoolean(
-                WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
         
-        Instance instance = new Instance();
-        instance.setPort(Integer.parseInt(port));
-        instance.setIp(ip);
-        instance.setEphemeral(ephemeral);
-        instance.setClusterName(cluster);
+        String weight = NamingUtils.optional(param, "weight", "1");
+        boolean healthy = BooleanUtils.toBoolean(NamingUtils.optional(param, "healthy", "true"));
+        
+        Instance instance = getBasicIpAddress(param);
+        instance.setWeight(Double.parseDouble(weight));
+        instance.setHealthy(healthy);
+        instance.setEnabled(enabled);
         
         return instance;
     }
@@ -591,6 +708,46 @@ private Instance getIpAddress(HttpServletRequest request) {
         return instance;
     }
     
+    private Instance getBasicIpAddress(Map param) {
+        
+        final String ip = NamingUtils.required(param, "ip");
+        final String port = NamingUtils.required(param, "port");
+        String cluster = NamingUtils.optional(param, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
+        if (StringUtils.isBlank(cluster)) {
+            cluster = NamingUtils.optional(param, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
+        }
+        boolean ephemeral = BooleanUtils.toBoolean(
+                NamingUtils.optional(param, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
+        
+        Instance instance = new Instance();
+        instance.setPort(Integer.parseInt(port));
+        instance.setIp(ip);
+        instance.setEphemeral(ephemeral);
+        instance.setClusterName(cluster);
+        
+        return instance;
+    }
+    
+    private Instance getBasicIpAddress(HttpServletRequest request) {
+        
+        final String ip = WebUtils.required(request, "ip");
+        final String port = WebUtils.required(request, "port");
+        String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
+        if (StringUtils.isBlank(cluster)) {
+            cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
+        }
+        boolean ephemeral = BooleanUtils.toBoolean(
+                WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
+        
+        Instance instance = new Instance();
+        instance.setPort(Integer.parseInt(port));
+        instance.setIp(ip);
+        instance.setEphemeral(ephemeral);
+        instance.setClusterName(cluster);
+        
+        return instance;
+    }
+    
     private void checkIfDisabled(Service service) throws Exception {
         if (!service.getEnabled()) {
             throw new Exception("service is disabled now.");
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
index a82164134ee..1a9a0e7925d 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
@@ -532,11 +532,13 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst
      *
      * @param namespaceId namespace
      * @param serviceName service name
-     * @param instance    instance
+     * @param action      update or remove
+     * @param ips         need update instances
+     * @param metadata    target metadata
      * @throws NacosException nacos exception
      */
-    public void updateMetadata(String namespaceId, String serviceName, Instance instance, String action)
-            throws NacosException {
+    public void updateMetadata(String namespaceId, String serviceName, boolean isEphemeral, String action, boolean all,
+            List ips, Map metadata) throws NacosException {
         
         Service service = getService(namespaceId, serviceName);
         
@@ -545,40 +547,65 @@ public void updateMetadata(String namespaceId, String serviceName, Instance inst
                     "service not found, namespace: " + namespaceId + ", service: " + serviceName);
         }
         
-        //need the newest data from consistencyService
-        Datum datum = consistencyService.get(KeyBuilder
-                .buildInstanceListKey(service.getNamespaceId(), service.getName(), instance.isEphemeral()));
-        Instance updateInstance = locateInstance(((Instances) datum.value).getInstanceList(), instance);
+        List locatedInstance = getLocatedInstance(namespaceId, serviceName, isEphemeral, all, ips);
         
-        if (updateInstance == null) {
-            throw new NacosException(NacosException.INVALID_PARAM, "instance not exist: " + instance);
+        if (CollectionUtils.isEmpty(locatedInstance)) {
+            throw new NacosException(NacosException.INVALID_PARAM, "instances not exist");
         }
         
         if (UPDATE_INSTANCE_METADATA_ACTION_UPDATE.equals(action)) {
-            updateInstance.getMetadata().putAll(instance.getMetadata());
+            locatedInstance.forEach(ele -> ele.getMetadata().putAll(metadata));
         } else if (UPDATE_INSTANCE_METADATA_ACTION_REMOVE.equals(action)) {
-            Set keys = instance.getMetadata().keySet();
-            for (String key : keys) {
-                updateInstance.getMetadata().remove(key);
+            Set removeKeys = metadata.keySet();
+            for (String removeKey : removeKeys) {
+                locatedInstance.forEach(ele -> ele.getMetadata().remove(removeKey));
             }
         }
+        addInstance(namespaceId, serviceName, isEphemeral, (Instance[]) locatedInstance.toArray());
+    }
+    
+    /**
+     * locate consistency's datum by all or instances provided.
+     *
+     * @param namespaceId        namespace
+     * @param serviceName        serviceName
+     * @param isEphemeral        isEphemeral
+     * @param all                get from consistencyService directly
+     * @param waitLocateInstance instances provided
+     * @return located instances
+     * @throws NacosException nacos exception
+     */
+    public List getLocatedInstance(String namespaceId, String serviceName, boolean isEphemeral, boolean all,
+            List waitLocateInstance) throws NacosException {
+        List locatedInstance;
+        
+        //need the newest data from consistencyService
+        Datum datum = consistencyService.get(KeyBuilder.buildInstanceListKey(namespaceId, serviceName, isEphemeral));
+        
+        if (all) {
+            locatedInstance = ((Instances) datum.value).getInstanceList();
+        } else {
+            locatedInstance = waitLocateInstance.stream()
+                    .filter(ele -> locateInstance(((Instances) datum.value).getInstanceList(), ele))
+                    .collect(Collectors.toList());
+        }
         
-        addInstance(namespaceId, serviceName, instance.isEphemeral(), updateInstance);
+        return locatedInstance;
     }
     
-    private Instance locateInstance(List instances, Instance instance) {
+    private boolean locateInstance(List instances, Instance instance) {
         int target = 0;
         while (target >= 0) {
             target = instances.indexOf(instance);
             if (target >= 0) {
                 Instance result = instances.get(target);
                 if (result.getClusterName().equals(instance.getClusterName())) {
-                    return result;
+                    return true;
                 }
                 instances.remove(target);
             }
         }
-        return null;
+        return false;
     }
     
     /**
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
index 14055ea8d01..7f6acd87237 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
@@ -20,9 +20,9 @@
 import com.alibaba.nacos.api.selector.SelectorType;
 import com.alibaba.nacos.common.utils.JacksonUtils;
 import com.alibaba.nacos.common.utils.VersionUtils;
-import com.alibaba.nacos.sys.utils.ApplicationUtils;
 import com.alibaba.nacos.naming.selector.LabelSelector;
 import com.alibaba.nacos.naming.selector.NoneSelector;
+import com.alibaba.nacos.sys.utils.ApplicationUtils;
 import com.fasterxml.jackson.core.type.TypeReference;
 import org.apache.commons.lang3.StringUtils;
 
diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
index 3eebe8151f5..8c22167a7dd 100644
--- a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
+++ b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
@@ -30,6 +30,7 @@
 import com.alibaba.nacos.naming.misc.Message;
 import com.alibaba.nacos.naming.misc.Synchronizer;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.junit.Assert;
 import org.junit.Before;
@@ -241,13 +242,15 @@ public void testUpdateMetadata() throws NacosException {
         updateMetadataInstance.setPort(instance.getPort());
         updateMetadataInstance.setClusterName(cluster.getName());
         updateMetadataInstance.setEphemeral(instance.isEphemeral());
+        
         Map updateMetadata = new HashMap<>(16);
         updateMetadata.put("key1", "new-value1");
         updateMetadata.put("key2", "value2");
         updateMetadataInstance.setMetadata(updateMetadata);
         
-        serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance,
-                UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
+        serviceManager
+                .updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, true, UPDATE_INSTANCE_METADATA_ACTION_UPDATE, false,
+                        Lists.newArrayList(updateMetadataInstance), updateMetadata);
         
         assertEquals(instance.getMetadata().get("key1"), "new-value1");
         assertEquals(instance.getMetadata().get("key2"), "value2");
@@ -262,8 +265,8 @@ public void testUpdateMetadata() throws NacosException {
         deleteMetadata.put("key3", null);
         updateMetadataInstance.setMetadata(deleteMetadata);
         
-        serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance,
-                UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
+        //        serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance,
+        //                UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
         
         assertEquals(instance.getMetadata().get("key1"), "new-value1");
         assertNull(instance.getMetadata().get("key2"));

From c213e82201b33b155a50ae5e55b5a5cf1cca541f Mon Sep 17 00:00:00 2001
From: bigbang555 <1060026287@qq.com>
Date: Mon, 28 Sep 2020 01:41:46 +0800
Subject: [PATCH 07/22] complete bacth operation of metadata

---
 .../controllers/InstanceController.java       | 173 ++++++------------
 .../nacos/naming/core/ServiceManager.java     |  22 ++-
 .../nacos/naming/pojo/OperationInfo.java      |  79 ++++++++
 .../nacos/naming/core/ServiceManagerTest.java |  23 ++-
 4 files changed, 171 insertions(+), 126 deletions(-)
 create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index 814b002bf3e..68a1eddc5f9 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -34,6 +34,7 @@
 import com.alibaba.nacos.naming.misc.SwitchDomain;
 import com.alibaba.nacos.naming.misc.SwitchEntry;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
+import com.alibaba.nacos.naming.pojo.OperationInfo;
 import com.alibaba.nacos.naming.push.ClientInfo;
 import com.alibaba.nacos.naming.push.DataSource;
 import com.alibaba.nacos.naming.push.PushService;
@@ -213,15 +214,6 @@ public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exc
         return "ok";
     }
     
-    private List parseInstances(List instances) {
-        List instanceList = new ArrayList<>();
-        for (Map map : instances) {
-            Instance basicIpAddress = getBasicIpAddress(map);
-            instanceList.add(basicIpAddress);
-        }
-        return instanceList;
-    }
-    
     /**
      * parse batch instance str, it should be as '[{"serviceName":"xxxx@@xxxx","instances":[{"ip":"127.0.0.1","port":
      * 8080,"ephemeral":"true","clusterName":"xxx-cluster"}], "all":"false"}]'.
@@ -265,110 +257,62 @@ public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exc
         return "ok";
     }
     
-    static class OperateDTO {
-        
-        private String namespace;
-        
-        private String serviceName;
-        
-        private Boolean ephemeral;
-        
-        private List instances;
-    }
-    
-    private void batchOperateMetadata(String namespace, List services, Map metadata) {
-        Consumer updateAllEphemeral = dto -> {
+    private void batchOperateMetadata(String namespace, List services, Map metadata,
+            String action) {
+        Consumer consumer = operationInfo -> {
             try {
-                serviceManager.updateMetadata(namespace, dto.serviceName, dto.ephemeral,
-                        UPDATE_INSTANCE_METADATA_ACTION_UPDATE, true, dto.instances, metadata);
+                serviceManager.updateMetadata(operationInfo.getNamespace(), operationInfo.getServiceName(),
+                        operationInfo.getEphemeral(), action, operationInfo.getAll(), operationInfo.getInstances(),
+                        metadata);
             } catch (NacosException e) {
-                //ignore
+                Loggers.SRV_LOG.warn("UPDATE-METADATA: updateMetadata failed", e);
             }
         };
-        batchOperate(namespace, services, );
+        batchOperate(namespace, services, consumer);
     }
     
-    
-    private void batchOperate(String namespace, List services, Consumer consumer) {
+    private void batchOperate(String namespace, List services, Consumer consumer) {
         for (Map service : services) {
-            try {
-                String serviceName = (String) service.get("serviceName");
-                NamingUtils.checkServiceNameFormat(serviceName);
-                // type: */ephemeral/persist
-                String type = (String) service.get("all");
-                OperateDTO operateDTO = new OperateDTO();
-                operateDTO.serviceName = serviceName;
-                if (type != null) {
-                    if ("*".equals(type)) {
-                        operateDTO.ephemeral = true;
-                        consumer.accept(operateDTO);
-                        operateDTO.ephemeral = false;
-                        consumer.accept(operateDTO);
-                    } else if ("ephemeral".equals(type)) {
-                        operateDTO.ephemeral = true;
-                        consumer.accept(operateDTO);
-                    } else if ("persist".equals(type)) {
-                        operateDTO.ephemeral = false;
-                        consumer.accept(operateDTO);
-                    } else {
-                        Loggers.SRV_LOG.warn("UPDATE-METADATA: services.all value is illegal, ignore the service '"
-                                + serviceName + "'");
-                    }
-                } else {
-                    List instances = parseInstances((List) service.get("instances"));
-                    //ephemeral:instances
-                    Map> instanceMap = instances.stream()
-                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+            String serviceName = (String) service.get("serviceName");
+            NamingUtils.checkServiceNameFormat(serviceName);
+            // type: */ephemeral/persist
+            String type = (String) service.get("all");
+            OperationInfo operateDto = new OperationInfo();
+            operateDto.setNamespace(namespace);
+            operateDto.setServiceName(serviceName);
+            if (type != null) {
+                if ("*".equals(type)) {
+                    operateDto.setAll(true);
+                    operateDto.setEphemeral(true);
+                    consumer.accept(operateDto);
                     
-                    for (Map.Entry> entry : instanceMap.entrySet()) {
-                        serviceManager.updateMetadata(namespace, serviceName, entry.getKey(),
-                                UPDATE_INSTANCE_METADATA_ACTION_REMOVE, false, entry.getValue(), metadata);
-                    }
-                }
-            } catch (NacosException e) {
-                Loggers.SRV_LOG.warn("");
-            }
-        }
-    }
-    
-    
-    private void batchOperateMetadata(String namespace, List services, Map metadata,
-            String action) {
-        for (Map service : services) {
-            try {
-                String serviceName = (String) service.get("serviceName");
-                NamingUtils.checkServiceNameFormat(serviceName);
-                // type: */ephemeral/persist
-                String type = (String) service.get("all");
-                if (type != null) {
-                    if ("*".equals(type)) {
-                        serviceManager.updateMetadata(namespace, serviceName, true, action, true, new ArrayList<>(),
-                                metadata);
-                        serviceManager.updateMetadata(namespace, serviceName, false, action, true, new ArrayList<>(),
-                                metadata);
-                    } else if ("ephemeral".equals(type)) {
-                        serviceManager.updateMetadata(namespace, serviceName, true, action, true, new ArrayList<>(),
-                                metadata);
-                    } else if ("persist".equals(type)) {
-                        serviceManager.updateMetadata(namespace, serviceName, false, action, true, new ArrayList<>(),
-                                metadata);
-                    } else {
-                        Loggers.SRV_LOG.warn("UPDATE-METADATA: services.all value is illegal, ignore the service '"
-                                + serviceName + "'");
-                    }
+                    operateDto.setEphemeral(false);
+                    consumer.accept(operateDto);
+                } else if ("ephemeral".equals(type)) {
+                    operateDto.setAll(true);
+                    operateDto.setEphemeral(true);
+                    consumer.accept(operateDto);
+                } else if ("persist".equals(type)) {
+                    operateDto.setAll(true);
+                    operateDto.setEphemeral(false);
+                    consumer.accept(operateDto);
                 } else {
-                    List instances = parseInstances((List) service.get("instances"));
-                    //ephemeral:instances
-                    Map> instanceMap = instances.stream()
-                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
-                    
-                    for (Map.Entry> entry : instanceMap.entrySet()) {
-                        serviceManager.updateMetadata(namespace, serviceName, entry.getKey(),
-                                UPDATE_INSTANCE_METADATA_ACTION_REMOVE, false, entry.getValue(), metadata);
-                    }
+                    Loggers.SRV_LOG
+                            .warn("UPDATE-METADATA: services.all value is illegal, ignore the service '" + serviceName
+                                    + "'");
+                }
+            } else {
+                List instances = parseInstances((List) service.get("instances"));
+                //ephemeral:instances
+                Map> instanceMap = instances.stream()
+                        .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+                
+                for (Map.Entry> entry : instanceMap.entrySet()) {
+                    operateDto.setAll(false);
+                    operateDto.setEphemeral(entry.getKey());
+                    operateDto.setInstances(entry.getValue());
+                    consumer.accept(operateDto);
                 }
-            } catch (NacosException e) {
-                Loggers.SRV_LOG.warn("");
             }
         }
     }
@@ -631,20 +575,6 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc
         return result;
     }
     
-    private Instance parseMetaInstance(HttpServletRequest request) throws Exception {
-        
-        Instance basicInstance = getBasicIpAddress(request);
-        
-        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
-        basicInstance.setServiceName(serviceName);
-        
-        String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY);
-        if (StringUtils.isNotEmpty(metadata)) {
-            basicInstance.setMetadata(UtilsAndCommons.parseMetadata(metadata));
-        }
-        return basicInstance;
-    }
-    
     private Instance parseInstance(HttpServletRequest request) throws Exception {
         
         String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
@@ -666,6 +596,15 @@ private Instance parseInstance(HttpServletRequest request) throws Exception {
         return instance;
     }
     
+    private List parseInstances(List instances) {
+        List instanceList = new ArrayList<>();
+        for (Map map : instances) {
+            Instance basicIpAddress = getBasicIpAddress(map);
+            instanceList.add(basicIpAddress);
+        }
+        return instanceList;
+    }
+    
     private Instance getIpAddress(Map param) {
         
         String enabledString = NamingUtils.optional(param, "enabled", StringUtils.EMPTY);
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
index 1a9a0e7925d..726ac64389a 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
@@ -561,7 +561,10 @@ public void updateMetadata(String namespaceId, String serviceName, boolean isEph
                 locatedInstance.forEach(ele -> ele.getMetadata().remove(removeKey));
             }
         }
-        addInstance(namespaceId, serviceName, isEphemeral, (Instance[]) locatedInstance.toArray());
+        Instance[] instances = new Instance[locatedInstance.size()];
+        locatedInstance.toArray(instances);
+        
+        addInstance(namespaceId, serviceName, isEphemeral, instances);
     }
     
     /**
@@ -585,27 +588,32 @@ public List getLocatedInstance(String namespaceId, String serviceName,
         if (all) {
             locatedInstance = ((Instances) datum.value).getInstanceList();
         } else {
-            locatedInstance = waitLocateInstance.stream()
-                    .filter(ele -> locateInstance(((Instances) datum.value).getInstanceList(), ele))
-                    .collect(Collectors.toList());
+            locatedInstance = new ArrayList<>();
+            for (Instance instance : waitLocateInstance) {
+                Instance located = locateInstance(((Instances) datum.value).getInstanceList(), instance);
+                if (located == null) {
+                    continue;
+                }
+                locatedInstance.add(located);
+            }
         }
         
         return locatedInstance;
     }
     
-    private boolean locateInstance(List instances, Instance instance) {
+    private Instance locateInstance(List instances, Instance instance) {
         int target = 0;
         while (target >= 0) {
             target = instances.indexOf(instance);
             if (target >= 0) {
                 Instance result = instances.get(target);
                 if (result.getClusterName().equals(instance.getClusterName())) {
-                    return true;
+                    return result;
                 }
                 instances.remove(target);
             }
         }
-        return false;
+        return null;
     }
     
     /**
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java
new file mode 100644
index 00000000000..53e4d3dbf87
--- /dev/null
+++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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.
+ */
+
+package com.alibaba.nacos.naming.pojo;
+
+import com.alibaba.nacos.naming.core.Instance;
+
+import java.util.List;
+
+/**
+ * OperationInfo. used in batch operation's consumer.
+ *
+ * @author horizonzy
+ */
+public class OperationInfo {
+    
+    private String namespace;
+    
+    private String serviceName;
+    
+    private Boolean ephemeral;
+    
+    private Boolean all;
+    
+    private List instances;
+    
+    public String getNamespace() {
+        return namespace;
+    }
+    
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+    
+    public String getServiceName() {
+        return serviceName;
+    }
+    
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+    
+    public Boolean getEphemeral() {
+        return ephemeral;
+    }
+    
+    public void setEphemeral(Boolean ephemeral) {
+        this.ephemeral = ephemeral;
+    }
+    
+    public Boolean getAll() {
+        return all;
+    }
+    
+    public void setAll(Boolean all) {
+        this.all = all;
+    }
+    
+    public List getInstances() {
+        return instances;
+    }
+    
+    public void setInstances(List instances) {
+        this.instances = instances;
+    }
+}
diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
index 8c22167a7dd..ff02d014829 100644
--- a/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
+++ b/naming/src/test/java/com/alibaba/nacos/naming/core/ServiceManagerTest.java
@@ -232,6 +232,7 @@ public void testUpdateMetadata() throws NacosException {
         datam.key = KeyBuilder.buildInstanceListKey(TEST_NAMESPACE, TEST_SERVICE_NAME, true);
         Instances instances = new Instances();
         instanceList.add(instance);
+        instanceList.add(instance2);
         instances.setInstanceList(instanceList);
         datam.value = instances;
         when(consistencyService.get(KeyBuilder.buildInstanceListKey(TEST_NAMESPACE, TEST_SERVICE_NAME, true)))
@@ -248,6 +249,7 @@ public void testUpdateMetadata() throws NacosException {
         updateMetadata.put("key2", "value2");
         updateMetadataInstance.setMetadata(updateMetadata);
         
+        //all=false, update input instances
         serviceManager
                 .updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, true, UPDATE_INSTANCE_METADATA_ACTION_UPDATE, false,
                         Lists.newArrayList(updateMetadataInstance), updateMetadata);
@@ -255,6 +257,14 @@ public void testUpdateMetadata() throws NacosException {
         assertEquals(instance.getMetadata().get("key1"), "new-value1");
         assertEquals(instance.getMetadata().get("key2"), "value2");
         
+        //all=true, update all instances
+        serviceManager
+                .updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, true, UPDATE_INSTANCE_METADATA_ACTION_UPDATE, true,
+                        null, updateMetadata);
+        
+        assertEquals(instance2.getMetadata().get("key1"), "new-value1");
+        assertEquals(instance2.getMetadata().get("key2"), "value2");
+        
         Instance deleteMetadataInstance = new Instance();
         deleteMetadataInstance.setIp(instance.getIp());
         deleteMetadataInstance.setPort(instance.getPort());
@@ -265,12 +275,21 @@ public void testUpdateMetadata() throws NacosException {
         deleteMetadata.put("key3", null);
         updateMetadataInstance.setMetadata(deleteMetadata);
         
-        //        serviceManager.updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, updateMetadataInstance,
-        //                UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
+        serviceManager
+                .updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, true, UPDATE_INSTANCE_METADATA_ACTION_REMOVE, false,
+                        Lists.newArrayList(deleteMetadataInstance), deleteMetadata);
         
         assertEquals(instance.getMetadata().get("key1"), "new-value1");
         assertNull(instance.getMetadata().get("key2"));
         assertNull(instance.getMetadata().get("key3"));
+        
+        serviceManager
+                .updateMetadata(TEST_NAMESPACE, TEST_SERVICE_NAME, true, UPDATE_INSTANCE_METADATA_ACTION_REMOVE, true,
+                        null, deleteMetadata);
+        
+        assertEquals(instance2.getMetadata().get("key1"), "new-value1");
+        assertNull(instance2.getMetadata().get("key2"));
+        assertNull(instance2.getMetadata().get("key3"));
     }
     
     @Test

From 9fa5a6c36a9a357a4da909cd13d2df6a075859fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 01:45:08 +0800
Subject: [PATCH 08/22] remove unnecessary test unit

---
 .../nacos/naming/controllers/InstanceControllerTest.java   | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java
index 7996e84ef97..d8b859c0b54 100644
--- a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java
+++ b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java
@@ -156,11 +156,4 @@ public void getNullServiceInstances() throws Exception {
         JsonNode hosts = result.get("hosts");
         Assert.assertEquals(hosts.size(), 0);
     }
-    
-    @Test
-    public void updateMetaData() throws Exception {
-        
-        registerInstance();
-        
-    }
 }

From ccf2366265adc31cd87dbd1e67bb0e7937621fd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 09:32:47 +0800
Subject: [PATCH 09/22] modify the variable name

---
 .../controllers/InstanceController.java       | 36 +++++++++----------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index 68a1eddc5f9..c24bd335763 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -277,25 +277,25 @@ private void batchOperate(String namespace, List services, Consumer services, Consumer ele.isEphemeral()));
                 
                 for (Map.Entry> entry : instanceMap.entrySet()) {
-                    operateDto.setAll(false);
-                    operateDto.setEphemeral(entry.getKey());
-                    operateDto.setInstances(entry.getValue());
-                    consumer.accept(operateDto);
+                    operationInfo.setAll(false);
+                    operationInfo.setEphemeral(entry.getKey());
+                    operationInfo.setInstances(entry.getValue());
+                    consumer.accept(operationInfo);
                 }
             }
         }

From 44e993cc8af663f306871b42c20590f7c4f022fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 10:31:13 +0800
Subject: [PATCH 10/22] perfect log info

---
 .../controllers/InstanceController.java       | 83 ++++++++++---------
 1 file changed, 44 insertions(+), 39 deletions(-)

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index c24bd335763..c19b18e1fbc 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -226,7 +226,7 @@ private List parseBatchInstances(String instances) {
             return JacksonUtils.toObj(instances, new TypeReference>() {
             });
         } catch (Exception e) {
-            Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal");
+            Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal, ignore this operation", e);
         }
         return new ArrayList<>();
     }
@@ -273,46 +273,51 @@ private void batchOperateMetadata(String namespace, List services, Map services, Consumer consumer) {
         for (Map service : services) {
-            String serviceName = (String) service.get("serviceName");
-            NamingUtils.checkServiceNameFormat(serviceName);
-            // type: */ephemeral/persist
-            String type = (String) service.get("all");
-            OperationInfo operationInfo = new OperationInfo();
-            operationInfo.setNamespace(namespace);
-            operationInfo.setServiceName(serviceName);
-            if (type != null) {
-                if ("*".equals(type)) {
-                    operationInfo.setAll(true);
-                    operationInfo.setEphemeral(true);
-                    consumer.accept(operationInfo);
-                    
-                    operationInfo.setEphemeral(false);
-                    consumer.accept(operationInfo);
-                } else if ("ephemeral".equals(type)) {
-                    operationInfo.setAll(true);
-                    operationInfo.setEphemeral(true);
-                    consumer.accept(operationInfo);
-                } else if ("persist".equals(type)) {
-                    operationInfo.setAll(true);
-                    operationInfo.setEphemeral(false);
-                    consumer.accept(operationInfo);
+            try {
+                String serviceName = (String) service.get("serviceName");
+                NamingUtils.checkServiceNameFormat(serviceName);
+                // type: */ephemeral/persist
+                String type = (String) service.get("all");
+                OperationInfo operationInfo = new OperationInfo();
+                operationInfo.setNamespace(namespace);
+                operationInfo.setServiceName(serviceName);
+                if (type != null) {
+                    if ("*".equals(type)) {
+                        operationInfo.setAll(true);
+                        operationInfo.setEphemeral(true);
+                        consumer.accept(operationInfo);
+                        
+                        operationInfo.setEphemeral(false);
+                        consumer.accept(operationInfo);
+                    } else if ("ephemeral".equals(type)) {
+                        operationInfo.setAll(true);
+                        operationInfo.setEphemeral(true);
+                        consumer.accept(operationInfo);
+                    } else if ("persist".equals(type)) {
+                        operationInfo.setAll(true);
+                        operationInfo.setEphemeral(false);
+                        consumer.accept(operationInfo);
+                    } else {
+                        Loggers.SRV_LOG
+                                .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '"
+                                        + serviceName + "'");
+                    }
                 } else {
-                    Loggers.SRV_LOG
-                            .warn("UPDATE-METADATA: services.all value is illegal, ignore the service '" + serviceName
-                                    + "'");
-                }
-            } else {
-                List instances = parseInstances((List) service.get("instances"));
-                //ephemeral:instances
-                Map> instanceMap = instances.stream()
-                        .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
-                
-                for (Map.Entry> entry : instanceMap.entrySet()) {
-                    operationInfo.setAll(false);
-                    operationInfo.setEphemeral(entry.getKey());
-                    operationInfo.setInstances(entry.getValue());
-                    consumer.accept(operationInfo);
+                    List instances = parseInstances((List) service.get("instances"));
+                    //ephemeral:instances
+                    Map> instanceMap = instances.stream()
+                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+                    
+                    for (Map.Entry> entry : instanceMap.entrySet()) {
+                        operationInfo.setAll(false);
+                        operationInfo.setEphemeral(entry.getKey());
+                        operationInfo.setInstances(entry.getValue());
+                        consumer.accept(operationInfo);
+                    }
                 }
+            } catch (Exception e) {
+                Loggers.SRV_LOG.warn("UPDATE-METADATA: update metadata failed, ignore the service '" + service
+                        .get("serviceName") + "'", e);
             }
         }
     }

From e2c3aacd54693c8187370779a06e682345510c74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 10:40:08 +0800
Subject: [PATCH 11/22] modify consumer's dto to match it's description

---
 .../controllers/InstanceController.java       | 46 +++++++++----------
 ...erationInfo.java => OperationContext.java} |  4 +-
 2 files changed, 25 insertions(+), 25 deletions(-)
 rename naming/src/main/java/com/alibaba/nacos/naming/pojo/{OperationInfo.java => OperationContext.java} (95%)

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index c19b18e1fbc..bcc1c7fba69 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -34,7 +34,7 @@
 import com.alibaba.nacos.naming.misc.SwitchDomain;
 import com.alibaba.nacos.naming.misc.SwitchEntry;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
-import com.alibaba.nacos.naming.pojo.OperationInfo;
+import com.alibaba.nacos.naming.pojo.OperationContext;
 import com.alibaba.nacos.naming.push.ClientInfo;
 import com.alibaba.nacos.naming.push.DataSource;
 import com.alibaba.nacos.naming.push.PushService;
@@ -259,10 +259,10 @@ public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exc
     
     private void batchOperateMetadata(String namespace, List services, Map metadata,
             String action) {
-        Consumer consumer = operationInfo -> {
+        Consumer consumer = operationContext -> {
             try {
-                serviceManager.updateMetadata(operationInfo.getNamespace(), operationInfo.getServiceName(),
-                        operationInfo.getEphemeral(), action, operationInfo.getAll(), operationInfo.getInstances(),
+                serviceManager.updateMetadata(operationContext.getNamespace(), operationContext.getServiceName(),
+                        operationContext.getEphemeral(), action, operationContext.getAll(), operationContext.getInstances(),
                         metadata);
             } catch (NacosException e) {
                 Loggers.SRV_LOG.warn("UPDATE-METADATA: updateMetadata failed", e);
@@ -271,32 +271,32 @@ private void batchOperateMetadata(String namespace, List services, Map services, Consumer consumer) {
+    private void batchOperate(String namespace, List services, Consumer consumer) {
         for (Map service : services) {
             try {
                 String serviceName = (String) service.get("serviceName");
                 NamingUtils.checkServiceNameFormat(serviceName);
                 // type: */ephemeral/persist
                 String type = (String) service.get("all");
-                OperationInfo operationInfo = new OperationInfo();
-                operationInfo.setNamespace(namespace);
-                operationInfo.setServiceName(serviceName);
+                OperationContext operationContext = new OperationContext();
+                operationContext.setNamespace(namespace);
+                operationContext.setServiceName(serviceName);
                 if (type != null) {
                     if ("*".equals(type)) {
-                        operationInfo.setAll(true);
-                        operationInfo.setEphemeral(true);
-                        consumer.accept(operationInfo);
+                        operationContext.setAll(true);
+                        operationContext.setEphemeral(true);
+                        consumer.accept(operationContext);
                         
-                        operationInfo.setEphemeral(false);
-                        consumer.accept(operationInfo);
+                        operationContext.setEphemeral(false);
+                        consumer.accept(operationContext);
                     } else if ("ephemeral".equals(type)) {
-                        operationInfo.setAll(true);
-                        operationInfo.setEphemeral(true);
-                        consumer.accept(operationInfo);
+                        operationContext.setAll(true);
+                        operationContext.setEphemeral(true);
+                        consumer.accept(operationContext);
                     } else if ("persist".equals(type)) {
-                        operationInfo.setAll(true);
-                        operationInfo.setEphemeral(false);
-                        consumer.accept(operationInfo);
+                        operationContext.setAll(true);
+                        operationContext.setEphemeral(false);
+                        consumer.accept(operationContext);
                     } else {
                         Loggers.SRV_LOG
                                 .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '"
@@ -309,10 +309,10 @@ private void batchOperate(String namespace, List services, Consumer ele.isEphemeral()));
                     
                     for (Map.Entry> entry : instanceMap.entrySet()) {
-                        operationInfo.setAll(false);
-                        operationInfo.setEphemeral(entry.getKey());
-                        operationInfo.setInstances(entry.getValue());
-                        consumer.accept(operationInfo);
+                        operationContext.setAll(false);
+                        operationContext.setEphemeral(entry.getKey());
+                        operationContext.setInstances(entry.getValue());
+                        consumer.accept(operationContext);
                     }
                 }
             } catch (Exception e) {
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java
similarity index 95%
rename from naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java
rename to naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java
index 53e4d3dbf87..ec93c782dc9 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationInfo.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java
@@ -21,11 +21,11 @@
 import java.util.List;
 
 /**
- * OperationInfo. used in batch operation's consumer.
+ * OperationContext. used in batch operation's consumer.
  *
  * @author horizonzy
  */
-public class OperationInfo {
+public class OperationContext {
     
     private String namespace;
     

From d262ed8f242f4188ff6d5cd7e72798ea3e34091f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 13:13:18 +0800
Subject: [PATCH 12/22] 1.rename class OperationContext ->
 InstanceOperationContext 2.move Map operation from NamingUtils to MapUtils

---
 .../nacos/api/naming/utils/NamingUtils.java   | 32 ----------------
 .../alibaba/nacos/common/utils/MapUtils.java  | 38 +++++++++++++++++--
 .../nacos/common/utils/MapUtilsTest.java      |  4 ++
 .../controllers/InstanceController.java       | 34 +++++++++--------
 ...ext.java => InstanceOperationContext.java} |  4 +-
 5 files changed, 58 insertions(+), 54 deletions(-)
 rename naming/src/main/java/com/alibaba/nacos/naming/pojo/{OperationContext.java => InstanceOperationContext.java} (93%)

diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
index 66d0a794970..99ca5a37ce4 100644
--- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
+++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
@@ -77,36 +77,4 @@ public static void checkServiceNameFormat(String combineServiceName) {
                     "Param 'serviceName' is illegal, it should be format as 'groupName@@serviceName'");
         }
     }
-    
-    /**
-     * get target value from param, if not found will throw {@link IllegalArgumentException}.
-     *
-     * @param param param
-     * @param key   key
-     * @return value
-     */
-    public static String required(final Map param, final String key) {
-        String value = param.get(key);
-        if (StringUtils.isEmpty(value)) {
-            throw new IllegalArgumentException("Param '" + key + "' is required.");
-        }
-        return value;
-    }
-    
-    /**
-     * get target value from param, if not found will return default value.
-     *
-     * @param param        param
-     * @param key          key
-     * @param defaultValue default value
-     * @return value
-     */
-    public static String optional(final Map param, final String key, final String defaultValue) {
-        String value = param.get(key);
-        if (StringUtils.isBlank(value)) {
-            return defaultValue;
-        }
-        return value;
-    }
-    
 }
diff --git a/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java b/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
index 9161bc10717..d13ecce6f97 100644
--- a/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
+++ b/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
@@ -129,11 +129,11 @@ public static void putIfValNoEmpty(Map target, Object key, Object value) {
     /**
      * ComputeIfAbsent lazy load.
      *
-     * @param target target Map data.
-     * @param key map key.
+     * @param target          target Map data.
+     * @param key             map key.
      * @param mappingFunction funtion which is need to be executed.
-     * @param param1 function's parameter value1.
-     * @param param2 function's parameter value1.
+     * @param param1          function's parameter value1.
+     * @param param2          function's parameter value1.
      * @return
      */
     @NotThreadSafe
@@ -154,4 +154,34 @@ public static Object computeIfAbsent(Map target, Object key, BiFunction mappingF
         return val;
     }
     
+    /**
+     * get target value from param, if not found will throw {@link IllegalArgumentException}.
+     *
+     * @param param param
+     * @param key   key
+     * @return value
+     */
+    public static String required(final Map param, final String key) {
+        String value = param.get(key);
+        if (StringUtils.isEmpty(value)) {
+            throw new IllegalArgumentException("Param '" + key + "' is required.");
+        }
+        return value;
+    }
+    
+    /**
+     * get target value from param, if not found will return default value.
+     *
+     * @param param        param
+     * @param key          key
+     * @param defaultValue default value
+     * @return value
+     */
+    public static String optional(final Map param, final String key, final String defaultValue) {
+        String value = param.get(key);
+        if (StringUtils.isBlank(value)) {
+            return defaultValue;
+        }
+        return value;
+    }
 }
diff --git a/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java b/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
index 483e5cae2d7..6b40ec0e2c5 100644
--- a/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
+++ b/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
@@ -61,6 +61,10 @@ public void testMap() {
         
         MapUtils.putIfValNoEmpty(map, "key-map", map1);
         Assert.assertTrue(map.containsKey("key-map"));
+        
+        Assert.assertEquals("123", MapUtils.required(map1, "1123"));
+        
+        Assert.assertEquals("456", MapUtils.optional(map1, "456", "456"));
     }
     
 }
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index bcc1c7fba69..7b19572a5f3 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -25,6 +25,7 @@
 import com.alibaba.nacos.auth.annotation.Secured;
 import com.alibaba.nacos.auth.common.ActionTypes;
 import com.alibaba.nacos.common.utils.JacksonUtils;
+import com.alibaba.nacos.common.utils.MapUtils;
 import com.alibaba.nacos.core.utils.WebUtils;
 import com.alibaba.nacos.naming.core.Instance;
 import com.alibaba.nacos.naming.core.Service;
@@ -34,7 +35,7 @@
 import com.alibaba.nacos.naming.misc.SwitchDomain;
 import com.alibaba.nacos.naming.misc.SwitchEntry;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
-import com.alibaba.nacos.naming.pojo.OperationContext;
+import com.alibaba.nacos.naming.pojo.InstanceOperationContext;
 import com.alibaba.nacos.naming.push.ClientInfo;
 import com.alibaba.nacos.naming.push.DataSource;
 import com.alibaba.nacos.naming.push.PushService;
@@ -216,7 +217,7 @@ public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exc
     
     /**
      * parse batch instance str, it should be as '[{"serviceName":"xxxx@@xxxx","instances":[{"ip":"127.0.0.1","port":
-     * 8080,"ephemeral":"true","clusterName":"xxx-cluster"}], "all":"false"}]'.
+     * 8080,"ephemeral":"true","clusterName":"xxx-cluster"}], "all":"ephemeral"}]'.
      *
      * @param instances instances str
      * @return instances as List
@@ -259,10 +260,11 @@ public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exc
     
     private void batchOperateMetadata(String namespace, List services, Map metadata,
             String action) {
-        Consumer consumer = operationContext -> {
+        Consumer consumer = instanceOperationContext -> {
             try {
-                serviceManager.updateMetadata(operationContext.getNamespace(), operationContext.getServiceName(),
-                        operationContext.getEphemeral(), action, operationContext.getAll(), operationContext.getInstances(),
+                serviceManager.updateMetadata(instanceOperationContext.getNamespace(), instanceOperationContext.getServiceName(),
+                        instanceOperationContext.getEphemeral(), action, instanceOperationContext.getAll(), instanceOperationContext
+                                .getInstances(),
                         metadata);
             } catch (NacosException e) {
                 Loggers.SRV_LOG.warn("UPDATE-METADATA: updateMetadata failed", e);
@@ -271,14 +273,14 @@ private void batchOperateMetadata(String namespace, List services, Map services, Consumer consumer) {
+    private void batchOperate(String namespace, List services, Consumer consumer) {
         for (Map service : services) {
             try {
                 String serviceName = (String) service.get("serviceName");
                 NamingUtils.checkServiceNameFormat(serviceName);
                 // type: */ephemeral/persist
                 String type = (String) service.get("all");
-                OperationContext operationContext = new OperationContext();
+                InstanceOperationContext operationContext = new InstanceOperationContext();
                 operationContext.setNamespace(namespace);
                 operationContext.setServiceName(serviceName);
                 if (type != null) {
@@ -612,16 +614,16 @@ private List parseInstances(List instances) {
     
     private Instance getIpAddress(Map param) {
         
-        String enabledString = NamingUtils.optional(param, "enabled", StringUtils.EMPTY);
+        String enabledString = MapUtils.optional(param, "enabled", StringUtils.EMPTY);
         boolean enabled;
         if (StringUtils.isBlank(enabledString)) {
-            enabled = BooleanUtils.toBoolean(NamingUtils.optional(param, "enable", "true"));
+            enabled = BooleanUtils.toBoolean(MapUtils.optional(param, "enable", "true"));
         } else {
             enabled = BooleanUtils.toBoolean(enabledString);
         }
         
-        String weight = NamingUtils.optional(param, "weight", "1");
-        boolean healthy = BooleanUtils.toBoolean(NamingUtils.optional(param, "healthy", "true"));
+        String weight = MapUtils.optional(param, "weight", "1");
+        boolean healthy = BooleanUtils.toBoolean(MapUtils.optional(param, "healthy", "true"));
         
         Instance instance = getBasicIpAddress(param);
         instance.setWeight(Double.parseDouble(weight));
@@ -654,14 +656,14 @@ private Instance getIpAddress(HttpServletRequest request) {
     
     private Instance getBasicIpAddress(Map param) {
         
-        final String ip = NamingUtils.required(param, "ip");
-        final String port = NamingUtils.required(param, "port");
-        String cluster = NamingUtils.optional(param, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
+        final String ip = MapUtils.required(param, "ip");
+        final String port = MapUtils.required(param, "port");
+        String cluster = MapUtils.optional(param, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
         if (StringUtils.isBlank(cluster)) {
-            cluster = NamingUtils.optional(param, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
+            cluster = MapUtils.optional(param, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
         }
         boolean ephemeral = BooleanUtils.toBoolean(
-                NamingUtils.optional(param, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
+                MapUtils.optional(param, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
         
         Instance instance = new Instance();
         instance.setPort(Integer.parseInt(port));
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
similarity index 93%
rename from naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java
rename to naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
index ec93c782dc9..919571121c8 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/OperationContext.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
@@ -21,11 +21,11 @@
 import java.util.List;
 
 /**
- * OperationContext. used in batch operation's consumer.
+ * InstanceOperationContext. used in instance batch operation's consumer.
  *
  * @author horizonzy
  */
-public class OperationContext {
+public class InstanceOperationContext {
     
     private String namespace;
     

From 65629aa3a8d7d599847b50a4b4ed73eae1620a94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 14:08:22 +0800
Subject: [PATCH 13/22] check datum is null

---
 .../java/com/alibaba/nacos/naming/core/ServiceManager.java     | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
index 726ac64389a..bc2e8653578 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
@@ -584,6 +584,9 @@ public List getLocatedInstance(String namespaceId, String serviceName,
         
         //need the newest data from consistencyService
         Datum datum = consistencyService.get(KeyBuilder.buildInstanceListKey(namespaceId, serviceName, isEphemeral));
+        if (datum == null) {
+            return null;
+        }
         
         if (all) {
             locatedInstance = ((Instances) datum.value).getInstanceList();

From 77059e822ffd4240d50d42160135698fdefea4d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com>
Date: Mon, 28 Sep 2020 20:37:35 +0800
Subject: [PATCH 14/22] code refactor.

---
 .../nacos/api/naming/utils/NamingUtils.java   |   2 -
 .../alibaba/nacos/common/utils/MapUtils.java  |  31 ----
 .../nacos/common/utils/MapUtilsTest.java      |   4 -
 .../controllers/InstanceController.java       | 154 +++---------------
 .../nacos/naming/core/ServiceManager.java     |  68 +++++++-
 .../nacos/naming/misc/UtilsAndCommons.java    |   6 +
 .../naming/pojo/InstanceOperationContext.java |  28 ++++
 .../naming/pojo/InstanceOperationInfo.java    |  71 ++++++++
 8 files changed, 193 insertions(+), 171 deletions(-)
 create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java

diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
index 99ca5a37ce4..94708e250d3 100644
--- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
+++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java
@@ -19,8 +19,6 @@
 import com.alibaba.nacos.api.common.Constants;
 import com.alibaba.nacos.api.utils.StringUtils;
 
-import java.util.Map;
-
 /**
  * NamingUtils.
  *
diff --git a/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java b/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
index d13ecce6f97..7febf7eda05 100644
--- a/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
+++ b/common/src/main/java/com/alibaba/nacos/common/utils/MapUtils.java
@@ -153,35 +153,4 @@ public static Object computeIfAbsent(Map target, Object key, BiFunction mappingF
         }
         return val;
     }
-    
-    /**
-     * get target value from param, if not found will throw {@link IllegalArgumentException}.
-     *
-     * @param param param
-     * @param key   key
-     * @return value
-     */
-    public static String required(final Map param, final String key) {
-        String value = param.get(key);
-        if (StringUtils.isEmpty(value)) {
-            throw new IllegalArgumentException("Param '" + key + "' is required.");
-        }
-        return value;
-    }
-    
-    /**
-     * get target value from param, if not found will return default value.
-     *
-     * @param param        param
-     * @param key          key
-     * @param defaultValue default value
-     * @return value
-     */
-    public static String optional(final Map param, final String key, final String defaultValue) {
-        String value = param.get(key);
-        if (StringUtils.isBlank(value)) {
-            return defaultValue;
-        }
-        return value;
-    }
 }
diff --git a/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java b/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
index 6b40ec0e2c5..483e5cae2d7 100644
--- a/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
+++ b/common/src/test/java/com/alibaba/nacos/common/utils/MapUtilsTest.java
@@ -61,10 +61,6 @@ public void testMap() {
         
         MapUtils.putIfValNoEmpty(map, "key-map", map1);
         Assert.assertTrue(map.containsKey("key-map"));
-        
-        Assert.assertEquals("123", MapUtils.required(map1, "1123"));
-        
-        Assert.assertEquals("456", MapUtils.optional(map1, "456", "456"));
     }
     
 }
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
index 7b19572a5f3..fd39bc09d8f 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java
@@ -25,7 +25,6 @@
 import com.alibaba.nacos.auth.annotation.Secured;
 import com.alibaba.nacos.auth.common.ActionTypes;
 import com.alibaba.nacos.common.utils.JacksonUtils;
-import com.alibaba.nacos.common.utils.MapUtils;
 import com.alibaba.nacos.core.utils.WebUtils;
 import com.alibaba.nacos.naming.core.Instance;
 import com.alibaba.nacos.naming.core.Service;
@@ -36,6 +35,7 @@
 import com.alibaba.nacos.naming.misc.SwitchEntry;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
 import com.alibaba.nacos.naming.pojo.InstanceOperationContext;
+import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
 import com.alibaba.nacos.naming.push.ClientInfo;
 import com.alibaba.nacos.naming.push.DataSource;
 import com.alibaba.nacos.naming.push.PushService;
@@ -66,7 +66,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 
 import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE;
 import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE;
@@ -205,33 +204,16 @@ public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exc
         
         String targetInstances = WebUtils.required(request, "target");
         
-        List services = parseBatchInstances(targetInstances);
+        List operationInfos = parseBatchInstances(targetInstances);
         
         String metadata = WebUtils.required(request, "metadata");
         Map targetMetadata = UtilsAndCommons.parseMetadata(metadata);
         
-        batchOperateMetadata(namespaceId, services, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
+        batchOperateMetadata(namespaceId, operationInfos, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_UPDATE);
         
         return "ok";
     }
     
-    /**
-     * parse batch instance str, it should be as '[{"serviceName":"xxxx@@xxxx","instances":[{"ip":"127.0.0.1","port":
-     * 8080,"ephemeral":"true","clusterName":"xxx-cluster"}], "all":"ephemeral"}]'.
-     *
-     * @param instances instances str
-     * @return instances as List
-     */
-    private List parseBatchInstances(String instances) {
-        try {
-            return JacksonUtils.toObj(instances, new TypeReference>() {
-            });
-        } catch (Exception e) {
-            Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal, ignore this operation", e);
-        }
-        return new ArrayList<>();
-    }
-    
     /**
      * Batch delete instance's metadata. old key exist = delete, old key not exist = not operate
      *
@@ -248,80 +230,38 @@ public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exc
         
         String targetInstances = WebUtils.required(request, "target");
         
-        List services = parseBatchInstances(targetInstances);
+        List operationInfos = parseBatchInstances(targetInstances);
         
         String metadata = WebUtils.required(request, "metadata");
         Map targetMetadata = UtilsAndCommons.parseMetadata(metadata);
         
-        batchOperateMetadata(namespaceId, services, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
+        batchOperateMetadata(namespaceId, operationInfos, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_REMOVE);
         
         return "ok";
     }
     
-    private void batchOperateMetadata(String namespace, List services, Map metadata,
-            String action) {
-        Consumer consumer = instanceOperationContext -> {
+    private List parseBatchInstances(String instances) {
+        try {
+            return JacksonUtils.toObj(instances, new TypeReference>() {
+            });
+        } catch (Exception e) {
+            Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal, ignore this operation", e);
+        }
+        return new ArrayList<>();
+    }
+    
+    private void batchOperateMetadata(String namespace, List operationInfos,
+            Map metadata, String action) {
+        Consumer operateConsumer = instanceOperationContext -> {
             try {
-                serviceManager.updateMetadata(instanceOperationContext.getNamespace(), instanceOperationContext.getServiceName(),
-                        instanceOperationContext.getEphemeral(), action, instanceOperationContext.getAll(), instanceOperationContext
-                                .getInstances(),
-                        metadata);
+                serviceManager.updateMetadata(instanceOperationContext.getNamespace(),
+                        instanceOperationContext.getServiceName(), instanceOperationContext.getEphemeral(), action,
+                        instanceOperationContext.getAll(), instanceOperationContext.getInstances(), metadata);
             } catch (NacosException e) {
                 Loggers.SRV_LOG.warn("UPDATE-METADATA: updateMetadata failed", e);
             }
         };
-        batchOperate(namespace, services, consumer);
-    }
-    
-    private void batchOperate(String namespace, List services, Consumer consumer) {
-        for (Map service : services) {
-            try {
-                String serviceName = (String) service.get("serviceName");
-                NamingUtils.checkServiceNameFormat(serviceName);
-                // type: */ephemeral/persist
-                String type = (String) service.get("all");
-                InstanceOperationContext operationContext = new InstanceOperationContext();
-                operationContext.setNamespace(namespace);
-                operationContext.setServiceName(serviceName);
-                if (type != null) {
-                    if ("*".equals(type)) {
-                        operationContext.setAll(true);
-                        operationContext.setEphemeral(true);
-                        consumer.accept(operationContext);
-                        
-                        operationContext.setEphemeral(false);
-                        consumer.accept(operationContext);
-                    } else if ("ephemeral".equals(type)) {
-                        operationContext.setAll(true);
-                        operationContext.setEphemeral(true);
-                        consumer.accept(operationContext);
-                    } else if ("persist".equals(type)) {
-                        operationContext.setAll(true);
-                        operationContext.setEphemeral(false);
-                        consumer.accept(operationContext);
-                    } else {
-                        Loggers.SRV_LOG
-                                .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '"
-                                        + serviceName + "'");
-                    }
-                } else {
-                    List instances = parseInstances((List) service.get("instances"));
-                    //ephemeral:instances
-                    Map> instanceMap = instances.stream()
-                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
-                    
-                    for (Map.Entry> entry : instanceMap.entrySet()) {
-                        operationContext.setAll(false);
-                        operationContext.setEphemeral(entry.getKey());
-                        operationContext.setInstances(entry.getValue());
-                        consumer.accept(operationContext);
-                    }
-                }
-            } catch (Exception e) {
-                Loggers.SRV_LOG.warn("UPDATE-METADATA: update metadata failed, ignore the service '" + service
-                        .get("serviceName") + "'", e);
-            }
-        }
+        serviceManager.batchOperate(namespace, operationInfos, operateConsumer);
     }
     
     /**
@@ -603,36 +543,6 @@ private Instance parseInstance(HttpServletRequest request) throws Exception {
         return instance;
     }
     
-    private List parseInstances(List instances) {
-        List instanceList = new ArrayList<>();
-        for (Map map : instances) {
-            Instance basicIpAddress = getBasicIpAddress(map);
-            instanceList.add(basicIpAddress);
-        }
-        return instanceList;
-    }
-    
-    private Instance getIpAddress(Map param) {
-        
-        String enabledString = MapUtils.optional(param, "enabled", StringUtils.EMPTY);
-        boolean enabled;
-        if (StringUtils.isBlank(enabledString)) {
-            enabled = BooleanUtils.toBoolean(MapUtils.optional(param, "enable", "true"));
-        } else {
-            enabled = BooleanUtils.toBoolean(enabledString);
-        }
-        
-        String weight = MapUtils.optional(param, "weight", "1");
-        boolean healthy = BooleanUtils.toBoolean(MapUtils.optional(param, "healthy", "true"));
-        
-        Instance instance = getBasicIpAddress(param);
-        instance.setWeight(Double.parseDouble(weight));
-        instance.setHealthy(healthy);
-        instance.setEnabled(enabled);
-        
-        return instance;
-    }
-    
     private Instance getIpAddress(HttpServletRequest request) {
         
         String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY);
@@ -654,26 +564,6 @@ private Instance getIpAddress(HttpServletRequest request) {
         return instance;
     }
     
-    private Instance getBasicIpAddress(Map param) {
-        
-        final String ip = MapUtils.required(param, "ip");
-        final String port = MapUtils.required(param, "port");
-        String cluster = MapUtils.optional(param, CommonParams.CLUSTER_NAME, StringUtils.EMPTY);
-        if (StringUtils.isBlank(cluster)) {
-            cluster = MapUtils.optional(param, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
-        }
-        boolean ephemeral = BooleanUtils.toBoolean(
-                MapUtils.optional(param, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral())));
-        
-        Instance instance = new Instance();
-        instance.setPort(Integer.parseInt(port));
-        instance.setIp(ip);
-        instance.setEphemeral(ephemeral);
-        instance.setClusterName(cluster);
-        
-        return instance;
-    }
-    
     private Instance getBasicIpAddress(HttpServletRequest request) {
         
         final String ip = WebUtils.required(request, "ip");
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
index bc2e8653578..2a72d15a2ab 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java
@@ -36,6 +36,8 @@
 import com.alibaba.nacos.naming.misc.SwitchDomain;
 import com.alibaba.nacos.naming.misc.Synchronizer;
 import com.alibaba.nacos.naming.misc.UtilsAndCommons;
+import com.alibaba.nacos.naming.pojo.InstanceOperationContext;
+import com.alibaba.nacos.naming.pojo.InstanceOperationInfo;
 import com.alibaba.nacos.naming.push.PushService;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -61,6 +63,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -550,7 +553,7 @@ public void updateMetadata(String namespaceId, String serviceName, boolean isEph
         List locatedInstance = getLocatedInstance(namespaceId, serviceName, isEphemeral, all, ips);
         
         if (CollectionUtils.isEmpty(locatedInstance)) {
-            throw new NacosException(NacosException.INVALID_PARAM, "instances not exist");
+            throw new NacosException(NacosException.INVALID_PARAM, "not locate instances, input instances: " + ips);
         }
         
         if (UPDATE_INSTANCE_METADATA_ACTION_UPDATE.equals(action)) {
@@ -585,7 +588,9 @@ public List getLocatedInstance(String namespaceId, String serviceName,
         //need the newest data from consistencyService
         Datum datum = consistencyService.get(KeyBuilder.buildInstanceListKey(namespaceId, serviceName, isEphemeral));
         if (datum == null) {
-            return null;
+            throw new NacosException(NacosException.NOT_FOUND,
+                    "instances from consistencyService not exist, namespace: " + namespaceId + ", service: "
+                            + serviceName + ", ephemeral: " + isEphemeral);
         }
         
         if (all) {
@@ -699,6 +704,65 @@ public Instance getInstance(String namespaceId, String serviceName, String clust
         return null;
     }
     
+    /**
+     * batch operate kinds of resources.
+     *
+     * @param namespace         namespace.
+     * @param operationInfoList operation resources description.
+     * @param consumer          some operation defined by kinds of situation.
+     */
+    public void batchOperate(String namespace, List operationInfoList,
+            Consumer consumer) {
+        for (InstanceOperationInfo operationInfo : operationInfoList) {
+            try {
+                String serviceName = operationInfo.getServiceName();
+                NamingUtils.checkServiceNameFormat(serviceName);
+                // type: */ephemeral/persist
+                String type = operationInfo.getAll();
+                InstanceOperationContext operationContext = new InstanceOperationContext();
+                operationContext.setNamespace(namespace);
+                operationContext.setServiceName(serviceName);
+                if (type != null) {
+                    switch (type) {
+                        case UtilsAndCommons.UNION:
+                            operationContext.allEphemeralOperate();
+                            consumer.accept(operationContext);
+                            
+                            operationContext.allPersistOperate();
+                            consumer.accept(operationContext);
+                            break;
+                        case UtilsAndCommons.EPHEMERAL:
+                            operationContext.allEphemeralOperate();
+                            consumer.accept(operationContext);
+                            break;
+                        case UtilsAndCommons.PERSIST:
+                            operationContext.allPersistOperate();
+                            consumer.accept(operationContext);
+                            break;
+                        default:
+                            Loggers.SRV_LOG
+                                    .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '"
+                                            + serviceName + "'");
+                            break;
+                    }
+                } else {
+                    List instances = operationInfo.getInstances();
+                    //ephemeral:instances
+                    Map> instanceMap = instances.stream()
+                            .collect(Collectors.groupingBy(ele -> ele.isEphemeral()));
+                    
+                    for (Map.Entry> entry : instanceMap.entrySet()) {
+                        operationContext.locateInstanceOperate(entry.getKey(), entry.getValue());
+                        consumer.accept(operationContext);
+                    }
+                }
+            } catch (Exception e) {
+                Loggers.SRV_LOG.warn("UPDATE-METADATA: update metadata failed, ignore the service '" + operationInfo
+                        .getServiceName() + "'", e);
+            }
+        }
+    }
+    
     /**
      * Compare and get new instance list.
      *
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
index 7f6acd87237..bbf43080042 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java
@@ -119,6 +119,12 @@ public class UtilsAndCommons {
     
     public static final String UPDATE_INSTANCE_METADATA_ACTION_REMOVE = "remove";
     
+    public static final String UNION = "*";
+    
+    public static final String EPHEMERAL = "ephemeral";
+    
+    public static final String PERSIST = "persist";
+    
     public static final String DATA_BASE_DIR =
             ApplicationUtils.getNacosHome() + File.separator + "data" + File.separator + "naming";
     
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
index 919571121c8..dba14edccc4 100644
--- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
+++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java
@@ -76,4 +76,32 @@ public List getInstances() {
     public void setInstances(List instances) {
         this.instances = instances;
     }
+    
+    /**
+     * to operate all ephemeral instances from consitencyService.
+     */
+    public void allEphemeralOperate() {
+        this.all = true;
+        this.ephemeral = true;
+    }
+    
+    /**
+     * to operate all persist instances from consitencyService.
+     */
+    public void allPersistOperate() {
+        this.all = true;
+        this.ephemeral = false;
+    }
+    
+    /**
+     * to operate locate instances from consistencySercice judged by ephemeral.
+     *
+     * @param ephemeral ephemeral
+     * @param instances need located instances.
+     */
+    public void locateInstanceOperate(Boolean ephemeral, List instances) {
+        this.all = false;
+        this.ephemeral = ephemeral;
+        this.instances = instances;
+    }
 }
diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java
new file mode 100644
index 00000000000..fbf15442407
--- /dev/null
+++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * 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.
+ */
+
+package com.alibaba.nacos.naming.pojo;
+
+import com.alibaba.nacos.naming.core.Instance;
+
+import java.util.List;
+
+/**
+ * InstanceOperationInfo. operation resources description
+ *
+ * @author horizonzy
+ */
+public class InstanceOperationInfo {
+    
+    /**
+     * serverName.
+     */
+    private String serviceName;
+    
+    /**
+     * instanceList which need operate.
+     */
+    private List instances;
+    
+    /**
+     * ephemeral/persist/*.
+     * 

ephemeral = all ephemeral instances in {@link com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl} + * persist = all persist instances in {@link com.alibaba.nacos.naming.consistency.persistent.raft.RaftConsistencyServiceImpl} + * * = persist union ephemeral

+ */ + private String all; + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public List getInstances() { + return instances; + } + + public void setInstances(List instances) { + this.instances = instances; + } + + public String getAll() { + return all; + } + + public void setAll(String all) { + this.all = all; + } +} From 1b053d857703628c17d815acdb46983fa038b608 Mon Sep 17 00:00:00 2001 From: horizonzy <1060026287@qq.com> Date: Wed, 30 Sep 2020 01:43:44 +0800 Subject: [PATCH 15/22] 1. code refactor 2. modify the batch operate http param. just support (1 services : n instance) --- .../controllers/InstanceController.java | 72 +++++++++--- .../nacos/naming/core/ServiceManager.java | 109 +++++++++--------- .../naming/pojo/InstanceOperationInfo.java | 36 +++--- 3 files changed, 133 insertions(+), 84 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index fd39bc09d8f..862bfcab012 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -65,8 +65,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.Function; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.EPHEMERAL; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.PERSIST; import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE; import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_UPDATE; @@ -198,20 +200,34 @@ public String update(HttpServletRequest request) throws Exception { @CanDistro @PutMapping(value = "/metadata/batch") @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) - public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exception { + public ObjectNode batchUpdateInstanceMatadata(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - String targetInstances = WebUtils.required(request, "target"); + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); + + String consistencyType = WebUtils.optional(request, "consistencyType", StringUtils.EMPTY); + + String instances = WebUtils.optional(request, "instances", StringUtils.EMPTY); - List operationInfos = parseBatchInstances(targetInstances); + List targetInstances = parseBatchInstances(instances); String metadata = WebUtils.required(request, "metadata"); Map targetMetadata = UtilsAndCommons.parseMetadata(metadata); - batchOperateMetadata(namespaceId, operationInfos, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_UPDATE); + List operatedInstances = batchOperateMetadata(namespaceId, + buildOperationInfo(serviceName, consistencyType, targetInstances), targetMetadata, + UPDATE_INSTANCE_METADATA_ACTION_UPDATE); - return "ok"; + ObjectNode result = JacksonUtils.createEmptyJsonNode(); + ArrayNode ipArray = JacksonUtils.createEmptyArrayNode(); + + for (Instance ip : operatedInstances) { + ipArray.add(ip.getDatumKey() + ":" + (ip.isEphemeral() ? EPHEMERAL : PERSIST)); + } + + result.replace("updated", ipArray); + return result; } /** @@ -224,44 +240,64 @@ public String batchUpdateInstanceMatadata(HttpServletRequest request) throws Exc @CanDistro @DeleteMapping("/metadata/batch") @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) - public String batchDeleteInstanceMatadata(HttpServletRequest request) throws Exception { + public ObjectNode batchDeleteInstanceMatadata(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - String targetInstances = WebUtils.required(request, "target"); + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); + + String consistencyType = WebUtils.optional(request, "consistencyType", StringUtils.EMPTY); + + String instances = WebUtils.optional(request, "instances", StringUtils.EMPTY); - List operationInfos = parseBatchInstances(targetInstances); + List targetInstances = parseBatchInstances(instances); String metadata = WebUtils.required(request, "metadata"); Map targetMetadata = UtilsAndCommons.parseMetadata(metadata); - batchOperateMetadata(namespaceId, operationInfos, targetMetadata, UPDATE_INSTANCE_METADATA_ACTION_REMOVE); + List operatedInstances = batchOperateMetadata(namespaceId, + buildOperationInfo(serviceName, consistencyType, targetInstances), targetMetadata, + UPDATE_INSTANCE_METADATA_ACTION_REMOVE); - return "ok"; + ObjectNode result = JacksonUtils.createEmptyJsonNode(); + ArrayNode ipArray = JacksonUtils.createEmptyArrayNode(); + + for (Instance ip : operatedInstances) { + ipArray.add(ip.getDatumKey() + ":" + (ip.isEphemeral() ? EPHEMERAL : PERSIST)); + } + + result.replace("updated", ipArray); + return result; + } + + private InstanceOperationInfo buildOperationInfo(String serviceName, String consistencyType, + List instances) { + return new InstanceOperationInfo(serviceName, consistencyType, instances); } - private List parseBatchInstances(String instances) { + private List parseBatchInstances(String instances) { try { - return JacksonUtils.toObj(instances, new TypeReference>() { + return JacksonUtils.toObj(instances, new TypeReference>() { }); } catch (Exception e) { Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal, ignore this operation", e); } - return new ArrayList<>(); + return null; } - private void batchOperateMetadata(String namespace, List operationInfos, + private List batchOperateMetadata(String namespace, InstanceOperationInfo instanceOperationInfo, Map metadata, String action) { - Consumer operateConsumer = instanceOperationContext -> { + Function> operateFunction = instanceOperationContext -> { try { - serviceManager.updateMetadata(instanceOperationContext.getNamespace(), + return serviceManager.updateMetadata(instanceOperationContext.getNamespace(), instanceOperationContext.getServiceName(), instanceOperationContext.getEphemeral(), action, instanceOperationContext.getAll(), instanceOperationContext.getInstances(), metadata); } catch (NacosException e) { Loggers.SRV_LOG.warn("UPDATE-METADATA: updateMetadata failed", e); } + return new ArrayList<>(); }; - serviceManager.batchOperate(namespace, operationInfos, operateConsumer); + return serviceManager.batchOperate(namespace, instanceOperationInfo, operateFunction); } /** diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index 2a72d15a2ab..259fe80c865 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -63,7 +63,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -538,10 +538,11 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst * @param action update or remove * @param ips need update instances * @param metadata target metadata + * @return update succeed instances * @throws NacosException nacos exception */ - public void updateMetadata(String namespaceId, String serviceName, boolean isEphemeral, String action, boolean all, - List ips, Map metadata) throws NacosException { + public List updateMetadata(String namespaceId, String serviceName, boolean isEphemeral, String action, + boolean all, List ips, Map metadata) throws NacosException { Service service = getService(namespaceId, serviceName); @@ -568,6 +569,8 @@ public void updateMetadata(String namespaceId, String serviceName, boolean isEph locatedInstance.toArray(instances); addInstance(namespaceId, serviceName, isEphemeral, instances); + + return locatedInstance; } /** @@ -707,60 +710,60 @@ public Instance getInstance(String namespaceId, String serviceName, String clust /** * batch operate kinds of resources. * - * @param namespace namespace. - * @param operationInfoList operation resources description. - * @param consumer some operation defined by kinds of situation. + * @param namespace namespace. + * @param operationInfo operation resources description. + * @param operateFunction some operation defined by kinds of situation. */ - public void batchOperate(String namespace, List operationInfoList, - Consumer consumer) { - for (InstanceOperationInfo operationInfo : operationInfoList) { - try { - String serviceName = operationInfo.getServiceName(); - NamingUtils.checkServiceNameFormat(serviceName); - // type: */ephemeral/persist - String type = operationInfo.getAll(); - InstanceOperationContext operationContext = new InstanceOperationContext(); - operationContext.setNamespace(namespace); - operationContext.setServiceName(serviceName); - if (type != null) { - switch (type) { - case UtilsAndCommons.UNION: - operationContext.allEphemeralOperate(); - consumer.accept(operationContext); - - operationContext.allPersistOperate(); - consumer.accept(operationContext); - break; - case UtilsAndCommons.EPHEMERAL: - operationContext.allEphemeralOperate(); - consumer.accept(operationContext); - break; - case UtilsAndCommons.PERSIST: - operationContext.allPersistOperate(); - consumer.accept(operationContext); - break; - default: - Loggers.SRV_LOG - .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '" - + serviceName + "'"); - break; - } - } else { - List instances = operationInfo.getInstances(); - //ephemeral:instances - Map> instanceMap = instances.stream() - .collect(Collectors.groupingBy(ele -> ele.isEphemeral())); - - for (Map.Entry> entry : instanceMap.entrySet()) { - operationContext.locateInstanceOperate(entry.getKey(), entry.getValue()); - consumer.accept(operationContext); - } + public List batchOperate(String namespace, InstanceOperationInfo operationInfo, + Function> operateFunction) { + List operatedInstances = new ArrayList<>(); + try { + String serviceName = operationInfo.getServiceName(); + NamingUtils.checkServiceNameFormat(serviceName); + // type: */ephemeral/persist + String type = operationInfo.getConsistencyType(); + InstanceOperationContext operationContext = new InstanceOperationContext(); + operationContext.setNamespace(namespace); + operationContext.setServiceName(serviceName); + if (!StringUtils.isEmpty(type)) { + switch (type) { + case UtilsAndCommons.UNION: + operationContext.allEphemeralOperate(); + operatedInstances.addAll(operateFunction.apply(operationContext)); + + operationContext.allPersistOperate(); + operatedInstances.addAll(operateFunction.apply(operationContext)); + break; + case UtilsAndCommons.EPHEMERAL: + operationContext.allEphemeralOperate(); + operatedInstances.addAll(operateFunction.apply(operationContext)); + break; + case UtilsAndCommons.PERSIST: + operationContext.allPersistOperate(); + operatedInstances.addAll(operateFunction.apply(operationContext)); + break; + default: + Loggers.SRV_LOG + .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '" + + serviceName + "'"); + break; + } + } else { + List instances = operationInfo.getInstances(); + //ephemeral:instances + Map> instanceMap = instances.stream() + .collect(Collectors.groupingBy(ele -> ele.isEphemeral())); + + for (Map.Entry> entry : instanceMap.entrySet()) { + operationContext.locateInstanceOperate(entry.getKey(), entry.getValue()); + operatedInstances.addAll(operateFunction.apply(operationContext)); } - } catch (Exception e) { - Loggers.SRV_LOG.warn("UPDATE-METADATA: update metadata failed, ignore the service '" + operationInfo - .getServiceName() + "'", e); } + } catch (Exception e) { + Loggers.SRV_LOG.warn("UPDATE-METADATA: update metadata failed, ignore the service '" + operationInfo + .getServiceName() + "'", e); } + return operatedInstances; } /** diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java index fbf15442407..5c068e0397f 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java @@ -27,23 +27,32 @@ */ public class InstanceOperationInfo { + public InstanceOperationInfo() { + } + + public InstanceOperationInfo(String serviceName, String consistencyType, List instances) { + this.serviceName = serviceName; + this.consistencyType = consistencyType; + this.instances = instances; + } + /** * serverName. */ private String serviceName; - /** - * instanceList which need operate. - */ - private List instances; - /** * ephemeral/persist/*. *

ephemeral = all ephemeral instances in {@link com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl} * persist = all persist instances in {@link com.alibaba.nacos.naming.consistency.persistent.raft.RaftConsistencyServiceImpl} * * = persist union ephemeral

*/ - private String all; + private String consistencyType; + + /** + * instances which need operate. + */ + private List instances; public String getServiceName() { return serviceName; @@ -53,6 +62,14 @@ public void setServiceName(String serviceName) { this.serviceName = serviceName; } + public String getConsistencyType() { + return consistencyType; + } + + public void setConsistencyType(String consistencyType) { + this.consistencyType = consistencyType; + } + public List getInstances() { return instances; } @@ -61,11 +78,4 @@ public void setInstances(List instances) { this.instances = instances; } - public String getAll() { - return all; - } - - public void setAll(String all) { - this.all = all; - } } From 6d81919e6c8437fb22b6fdc40cfd2a06713b5266 Mon Sep 17 00:00:00 2001 From: horizonzy <1060026287@qq.com> Date: Wed, 30 Sep 2020 02:17:28 +0800 Subject: [PATCH 16/22] 1.set default clusterName if instance not set 2.fix client params not set instances bug --- .../naming/controllers/InstanceController.java | 6 ++++++ .../nacos/naming/core/ServiceManager.java | 16 +++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index 862bfcab012..c888e387b31 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -67,6 +67,7 @@ import java.util.Map; import java.util.function.Function; +import static com.alibaba.nacos.naming.misc.UtilsAndCommons.DEFAULT_CLUSTER_NAME; import static com.alibaba.nacos.naming.misc.UtilsAndCommons.EPHEMERAL; import static com.alibaba.nacos.naming.misc.UtilsAndCommons.PERSIST; import static com.alibaba.nacos.naming.misc.UtilsAndCommons.UPDATE_INSTANCE_METADATA_ACTION_REMOVE; @@ -272,6 +273,11 @@ public ObjectNode batchDeleteInstanceMatadata(HttpServletRequest request) throws private InstanceOperationInfo buildOperationInfo(String serviceName, String consistencyType, List instances) { + for (Instance instance : instances) { + if (StringUtils.isBlank(instance.getClusterName())) { + instance.setClusterName(DEFAULT_CLUSTER_NAME); + } + } return new InstanceOperationInfo(serviceName, consistencyType, instances); } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index 259fe80c865..ecce01c5685 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -750,13 +750,15 @@ public List batchOperate(String namespace, InstanceOperationInfo opera } } else { List instances = operationInfo.getInstances(); - //ephemeral:instances - Map> instanceMap = instances.stream() - .collect(Collectors.groupingBy(ele -> ele.isEphemeral())); - - for (Map.Entry> entry : instanceMap.entrySet()) { - operationContext.locateInstanceOperate(entry.getKey(), entry.getValue()); - operatedInstances.addAll(operateFunction.apply(operationContext)); + if (!CollectionUtils.isEmpty(instances)) { + //ephemeral:instances or persist:instances + Map> instanceMap = instances.stream() + .collect(Collectors.groupingBy(ele -> ele.isEphemeral())); + + for (Map.Entry> entry : instanceMap.entrySet()) { + operationContext.locateInstanceOperate(entry.getKey(), entry.getValue()); + operatedInstances.addAll(operateFunction.apply(operationContext)); + } } } } catch (Exception e) { From 8fc887e1d8199130bc995e3704efac5fd56fa022 Mon Sep 17 00:00:00 2001 From: horizonzy <1060026287@qq.com> Date: Wed, 30 Sep 2020 02:33:14 +0800 Subject: [PATCH 17/22] npe fix --- .../nacos/naming/controllers/InstanceController.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index c888e387b31..936e4d9e8a7 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -273,9 +273,11 @@ public ObjectNode batchDeleteInstanceMatadata(HttpServletRequest request) throws private InstanceOperationInfo buildOperationInfo(String serviceName, String consistencyType, List instances) { - for (Instance instance : instances) { - if (StringUtils.isBlank(instance.getClusterName())) { - instance.setClusterName(DEFAULT_CLUSTER_NAME); + if (!CollectionUtils.isEmpty(instances)) { + for (Instance instance : instances) { + if (StringUtils.isBlank(instance.getClusterName())) { + instance.setClusterName(DEFAULT_CLUSTER_NAME); + } } } return new InstanceOperationInfo(serviceName, consistencyType, instances); From a53eca41c1dbedbd9e34f30103cc32632a2848a0 Mon Sep 17 00:00:00 2001 From: horizonzy <1060026287@qq.com> Date: Wed, 30 Sep 2020 21:36:21 +0800 Subject: [PATCH 18/22] 1.remove consistencyType *, just support ephemeral or persist. 2.remove moditfy property method in InstanceOperationContext and InstanceOperationInfo, it just defined by constructor. --- .../nacos/naming/core/ServiceManager.java | 22 ++---- .../nacos/naming/misc/UtilsAndCommons.java | 2 - .../naming/pojo/InstanceOperationContext.java | 67 ++++++------------- .../naming/pojo/InstanceOperationInfo.java | 21 ++---- 4 files changed, 31 insertions(+), 81 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index ecce01c5685..859c8fb3ea4 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -720,31 +720,22 @@ public List batchOperate(String namespace, InstanceOperationInfo opera try { String serviceName = operationInfo.getServiceName(); NamingUtils.checkServiceNameFormat(serviceName); - // type: */ephemeral/persist + // type: ephemeral/persist + InstanceOperationContext operationContext; String type = operationInfo.getConsistencyType(); - InstanceOperationContext operationContext = new InstanceOperationContext(); - operationContext.setNamespace(namespace); - operationContext.setServiceName(serviceName); if (!StringUtils.isEmpty(type)) { switch (type) { - case UtilsAndCommons.UNION: - operationContext.allEphemeralOperate(); - operatedInstances.addAll(operateFunction.apply(operationContext)); - - operationContext.allPersistOperate(); - operatedInstances.addAll(operateFunction.apply(operationContext)); - break; case UtilsAndCommons.EPHEMERAL: - operationContext.allEphemeralOperate(); + operationContext = new InstanceOperationContext(namespace, serviceName, true, true); operatedInstances.addAll(operateFunction.apply(operationContext)); break; case UtilsAndCommons.PERSIST: - operationContext.allPersistOperate(); + operationContext = new InstanceOperationContext(namespace, serviceName, false, true); operatedInstances.addAll(operateFunction.apply(operationContext)); break; default: Loggers.SRV_LOG - .warn("UPDATE-METADATA: services.all value is illegal, it should be */ephemeral/persist. ignore the service '" + .warn("UPDATE-METADATA: services.all value is illegal, it should be ephemeral/persist. ignore the service '" + serviceName + "'"); break; } @@ -756,7 +747,8 @@ public List batchOperate(String namespace, InstanceOperationInfo opera .collect(Collectors.groupingBy(ele -> ele.isEphemeral())); for (Map.Entry> entry : instanceMap.entrySet()) { - operationContext.locateInstanceOperate(entry.getKey(), entry.getValue()); + operationContext = new InstanceOperationContext(namespace, serviceName, entry.getKey(), false, + entry.getValue()); operatedInstances.addAll(operateFunction.apply(operationContext)); } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java index bbf43080042..c3399b93ce8 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/misc/UtilsAndCommons.java @@ -119,8 +119,6 @@ public class UtilsAndCommons { public static final String UPDATE_INSTANCE_METADATA_ACTION_REMOVE = "remove"; - public static final String UNION = "*"; - public static final String EPHEMERAL = "ephemeral"; public static final String PERSIST = "persist"; diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java index dba14edccc4..1e31338f9a8 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java @@ -27,6 +27,25 @@ */ public class InstanceOperationContext { + public InstanceOperationContext() { + } + + public InstanceOperationContext(String namespace, String serviceName, Boolean ephemeral, Boolean all) { + this.namespace = namespace; + this.serviceName = serviceName; + this.ephemeral = ephemeral; + this.all = all; + } + + public InstanceOperationContext(String namespace, String serviceName, Boolean ephemeral, Boolean all, + List instances) { + this.namespace = namespace; + this.serviceName = serviceName; + this.ephemeral = ephemeral; + this.all = all; + this.instances = instances; + } + private String namespace; private String serviceName; @@ -41,67 +60,19 @@ public String getNamespace() { return namespace; } - public void setNamespace(String namespace) { - this.namespace = namespace; - } - public String getServiceName() { return serviceName; } - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - public Boolean getEphemeral() { return ephemeral; } - public void setEphemeral(Boolean ephemeral) { - this.ephemeral = ephemeral; - } - public Boolean getAll() { return all; } - public void setAll(Boolean all) { - this.all = all; - } - public List getInstances() { return instances; } - - public void setInstances(List instances) { - this.instances = instances; - } - - /** - * to operate all ephemeral instances from consitencyService. - */ - public void allEphemeralOperate() { - this.all = true; - this.ephemeral = true; - } - - /** - * to operate all persist instances from consitencyService. - */ - public void allPersistOperate() { - this.all = true; - this.ephemeral = false; - } - - /** - * to operate locate instances from consistencySercice judged by ephemeral. - * - * @param ephemeral ephemeral - * @param instances need located instances. - */ - public void locateInstanceOperate(Boolean ephemeral, List instances) { - this.all = false; - this.ephemeral = ephemeral; - this.instances = instances; - } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java index 5c068e0397f..e61d79787c4 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java @@ -21,7 +21,7 @@ import java.util.List; /** - * InstanceOperationInfo. operation resources description + * InstanceOperationInfo. operation resources's description * * @author horizonzy */ @@ -42,10 +42,11 @@ public InstanceOperationInfo(String serviceName, String consistencyType, Listephemeral = all ephemeral instances in {@link com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl} + * consistencyType. it helps to operate all instances from consistencyService, value = ephemeral or persist. + *

+ * ephemeral = all ephemeral instances in {@link com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl} * persist = all persist instances in {@link com.alibaba.nacos.naming.consistency.persistent.raft.RaftConsistencyServiceImpl} - * * = persist union ephemeral

+ *

*/ private String consistencyType; @@ -58,24 +59,12 @@ public String getServiceName() { return serviceName; } - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - public String getConsistencyType() { return consistencyType; } - public void setConsistencyType(String consistencyType) { - this.consistencyType = consistencyType; - } - public List getInstances() { return instances; } - public void setInstances(List instances) { - this.instances = instances; - } - } From 0f83c62e64a334202e6e710983d4a0bf8728b7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Wed, 7 Oct 2020 15:08:55 +0800 Subject: [PATCH 19/22] add instance controller test --- .../com/alibaba/nacos/naming/BaseTest.java | 4 +- .../controllers/InstanceControllerTest.java | 98 ++++++++++++++++++- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/naming/src/test/java/com/alibaba/nacos/naming/BaseTest.java b/naming/src/test/java/com/alibaba/nacos/naming/BaseTest.java index a81502b5b06..8b32f7c2eaa 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/BaseTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/BaseTest.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.naming; -import com.alibaba.nacos.sys.utils.ApplicationUtils; import com.alibaba.nacos.naming.consistency.persistent.raft.RaftCore; import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeer; import com.alibaba.nacos.naming.consistency.persistent.raft.RaftPeerSet; @@ -26,6 +25,7 @@ import com.alibaba.nacos.naming.misc.NetUtils; import com.alibaba.nacos.naming.misc.SwitchDomain; import com.alibaba.nacos.naming.push.PushService; +import com.alibaba.nacos.sys.utils.ApplicationUtils; import org.junit.Before; import org.junit.Rule; import org.junit.rules.ExpectedException; @@ -44,7 +44,7 @@ public class BaseTest { protected static final String TEST_CLUSTER_NAME = "test-cluster"; - protected static final String TEST_SERVICE_NAME = "test-service"; + protected static final String TEST_SERVICE_NAME = "DEFAULT_GROUP@@test-service"; protected static final String TEST_GROUP_NAME = "test-group-name"; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java index d8b859c0b54..092156ba7f3 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java @@ -24,12 +24,13 @@ import com.alibaba.nacos.naming.core.Instance; import com.alibaba.nacos.naming.core.Service; import com.alibaba.nacos.naming.misc.UtilsAndCommons; +import com.alibaba.nacos.naming.pojo.InstanceOperationInfo; import com.fasterxml.jackson.databind.JsonNode; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -44,7 +45,11 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.function.Function; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = MockServletContext.class) @@ -62,6 +67,7 @@ public class InstanceControllerTest extends BaseTest { @Before public void before() { super.before(); + mockInjectPushServer(); mockmvc = MockMvcBuilders.standaloneSetup(instanceController).build(); } @@ -84,7 +90,7 @@ public void registerInstance() throws Exception { Mockito.when(serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, TEST_SERVICE_NAME)).thenReturn(service); MockHttpServletRequestBuilder builder = MockMvcRequestBuilders - .put(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance").param("serviceName", TEST_SERVICE_NAME) + .post(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance").param("serviceName", TEST_SERVICE_NAME) .param("ip", "1.1.1.1").param("port", "9999"); String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); @@ -156,4 +162,92 @@ public void getNullServiceInstances() throws Exception { JsonNode hosts = result.get("hosts"); Assert.assertEquals(hosts.size(), 0); } + + @Test + public void batchUpdateMetadata() throws Exception { + Instance instance = new Instance("1.1.1.1", 8080, TEST_CLUSTER_NAME); + instance.setServiceName(TEST_SERVICE_NAME); + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + instance.setMetadata(metadata); + + Instance instance2 = new Instance("2.2.2.2", 8080, TEST_CLUSTER_NAME); + instance2.setServiceName(TEST_SERVICE_NAME); + + List instanceList = new LinkedList<>(); + instanceList.add(instance); + instanceList.add(instance2); + + Mockito.when(serviceManager + .batchOperate(ArgumentMatchers.anyString(), ArgumentMatchers.any(InstanceOperationInfo.class), + ArgumentMatchers.any(Function.class))).thenReturn(instanceList); + + MockHttpServletRequestBuilder builder = MockMvcRequestBuilders + .put(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance/metadata/batch").param("namespace", "public") + .param("serviceName", TEST_SERVICE_NAME).param("instances", + "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"},{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") + .param("metadata", "{\"age\":\"20\",\"name\":\"horizon\"}"); + + String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); + + JsonNode result = JacksonUtils.toObj(actualValue); + + JsonNode updated = result.get("updated"); + + Assert.assertEquals(updated.size(), 2); + + Assert.assertTrue(updated.get(0).asText().contains("1.1.1.1")); + Assert.assertTrue(updated.get(0).asText().contains("8080")); + Assert.assertTrue(updated.get(0).asText().contains(TEST_CLUSTER_NAME)); + Assert.assertTrue(updated.get(0).asText().contains("ephemeral")); + + Assert.assertTrue(updated.get(1).asText().contains("2.2.2.2")); + Assert.assertTrue(updated.get(1).asText().contains("8080")); + Assert.assertTrue(updated.get(1).asText().contains(TEST_CLUSTER_NAME)); + Assert.assertTrue(updated.get(1).asText().contains("ephemeral")); + } + + @Test + public void batchDeleteMetadata() throws Exception { + Instance instance = new Instance("1.1.1.1", 8080, TEST_CLUSTER_NAME); + instance.setServiceName(TEST_SERVICE_NAME); + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + instance.setMetadata(metadata); + + Instance instance2 = new Instance("2.2.2.2", 8080, TEST_CLUSTER_NAME); + instance2.setServiceName(TEST_SERVICE_NAME); + + List instanceList = new LinkedList<>(); + instanceList.add(instance); + instanceList.add(instance2); + + Mockito.when(serviceManager + .batchOperate(ArgumentMatchers.anyString(), ArgumentMatchers.any(InstanceOperationInfo.class), + ArgumentMatchers.any(Function.class))).thenReturn(instanceList); + + MockHttpServletRequestBuilder builder = MockMvcRequestBuilders + .delete(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance/metadata/batch").param("namespace", "public") + .param("serviceName", TEST_SERVICE_NAME).param("instances", + "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"},{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") + .param("metadata", "{\"age\":\"20\",\"name\":\"horizon\"}"); + + String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); + + JsonNode result = JacksonUtils.toObj(actualValue); + + JsonNode updated = result.get("updated"); + + Assert.assertEquals(updated.size(), 2); + + Assert.assertTrue(updated.get(0).asText().contains("1.1.1.1")); + Assert.assertTrue(updated.get(0).asText().contains("8080")); + Assert.assertTrue(updated.get(0).asText().contains(TEST_CLUSTER_NAME)); + Assert.assertTrue(updated.get(0).asText().contains("ephemeral")); + + Assert.assertTrue(updated.get(1).asText().contains("2.2.2.2")); + Assert.assertTrue(updated.get(1).asText().contains("8080")); + Assert.assertTrue(updated.get(1).asText().contains(TEST_CLUSTER_NAME)); + Assert.assertTrue(updated.get(1).asText().contains("ephemeral")); + } } From 344e3d24a87164659ad6af7eaadb1702ecfcb9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Wed, 7 Oct 2020 22:18:28 +0800 Subject: [PATCH 20/22] fix code too length --- .../nacos/naming/controllers/InstanceControllerTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java index 092156ba7f3..173cc82698f 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/controllers/InstanceControllerTest.java @@ -185,7 +185,8 @@ public void batchUpdateMetadata() throws Exception { MockHttpServletRequestBuilder builder = MockMvcRequestBuilders .put(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance/metadata/batch").param("namespace", "public") .param("serviceName", TEST_SERVICE_NAME).param("instances", - "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"},{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") + "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}," + + "{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") .param("metadata", "{\"age\":\"20\",\"name\":\"horizon\"}"); String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); @@ -200,7 +201,7 @@ public void batchUpdateMetadata() throws Exception { Assert.assertTrue(updated.get(0).asText().contains("8080")); Assert.assertTrue(updated.get(0).asText().contains(TEST_CLUSTER_NAME)); Assert.assertTrue(updated.get(0).asText().contains("ephemeral")); - + Assert.assertTrue(updated.get(1).asText().contains("2.2.2.2")); Assert.assertTrue(updated.get(1).asText().contains("8080")); Assert.assertTrue(updated.get(1).asText().contains(TEST_CLUSTER_NAME)); @@ -229,7 +230,8 @@ public void batchDeleteMetadata() throws Exception { MockHttpServletRequestBuilder builder = MockMvcRequestBuilders .delete(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance/metadata/batch").param("namespace", "public") .param("serviceName", TEST_SERVICE_NAME).param("instances", - "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"},{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") + "[{\"ip\":\"1.1.1.1\",\"port\": \"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}," + + "{\"ip\":\"2.2.2.2\",\"port\":\"8080\",\"ephemeral\":\"true\",\"clusterName\":\"test-cluster\"}]") .param("metadata", "{\"age\":\"20\",\"name\":\"horizon\"}"); String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); From a2503dd205b48268e8fdf02058480977e5bb5f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Tue, 13 Oct 2020 00:53:00 +0800 Subject: [PATCH 21/22] update the param name --- .../alibaba/nacos/naming/controllers/InstanceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index 936e4d9e8a7..e91f1e1e6f8 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -288,7 +288,7 @@ private List parseBatchInstances(String instances) { return JacksonUtils.toObj(instances, new TypeReference>() { }); } catch (Exception e) { - Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'target' is illegal, ignore this operation", e); + Loggers.SRV_LOG.warn("UPDATE-METADATA: Param 'instances' is illegal, ignore this operation", e); } return null; } From 88e18a3b128ee730f3fb6816b67641840d34e3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BB=B6?= <1060026287@qq.com> Date: Thu, 15 Oct 2020 09:35:05 +0800 Subject: [PATCH 22/22] add feature's version of start --- .../nacos/naming/controllers/InstanceController.java | 6 ++++-- .../alibaba/nacos/naming/pojo/InstanceOperationContext.java | 1 + .../alibaba/nacos/naming/pojo/InstanceOperationInfo.java | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index e91f1e1e6f8..5746b2f7df3 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -195,8 +195,9 @@ public String update(HttpServletRequest request) throws Exception { * Batch update instance's metadata. old key exist = update, old key not exist = add. * * @param request http request - * @return 'ok' if success + * @return success updated instances. such as '{"updated":["2.2.2.2:8080:unknown:xxxx-cluster:ephemeral"}'. * @throws Exception any error during update + * @since 1.4.0 */ @CanDistro @PutMapping(value = "/metadata/batch") @@ -235,8 +236,9 @@ public ObjectNode batchUpdateInstanceMatadata(HttpServletRequest request) throws * Batch delete instance's metadata. old key exist = delete, old key not exist = not operate * * @param request http request - * @return 'ok' if success + * @return success updated instances. such as '{"updated":["2.2.2.2:8080:unknown:xxxx-cluster:ephemeral"}'. * @throws Exception any error during update + * @since 1.4.0 */ @CanDistro @DeleteMapping("/metadata/batch") diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java index 1e31338f9a8..7d1ad3b4508 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationContext.java @@ -24,6 +24,7 @@ * InstanceOperationContext. used in instance batch operation's consumer. * * @author horizonzy + * @since 1.4.0 */ public class InstanceOperationContext { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java index e61d79787c4..56e726194a9 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/pojo/InstanceOperationInfo.java @@ -24,6 +24,7 @@ * InstanceOperationInfo. operation resources's description * * @author horizonzy + * @since 1.4.0 */ public class InstanceOperationInfo {