diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java index aa0b3e8ea..ce687358a 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java @@ -94,7 +94,7 @@ public class ServiceController { private ServiceOperatorV2Impl serviceOperatorV2; /** - * Create a new service. + * Create a new service. This API will create a persistence service. * * @param namespaceId namespace id * @param serviceName service name @@ -114,6 +114,7 @@ public class ServiceController { serviceMetadata.setProtectThreshold(protectThreshold); serviceMetadata.setSelector(parseSelector(selector)); serviceMetadata.setExtendData(UtilsAndCommons.parseMetadata(metadata)); + serviceMetadata.setEphemeral(false); serviceOperatorV2.create(namespaceId, serviceName, serviceMetadata); return "ok"; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java index e11e5efc9..45819595c 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java @@ -47,7 +47,7 @@ public class ServiceOperatorV2Impl implements ServiceOperator { @Override public void create(String namespaceId, String serviceName, ServiceMetadata metadata) throws NacosException { - Service service = getServiceFromGroupedServiceName(namespaceId, serviceName); + Service service = getServiceFromGroupedServiceName(namespaceId, serviceName, metadata.isEphemeral()); if (ServiceManager.getInstance().containSingleton(service)) { throw new NacosException(NacosException.INVALID_PARAM, String.format("specified service %s already exists!", service.getGroupedServiceName())); @@ -66,7 +66,7 @@ public class ServiceOperatorV2Impl implements ServiceOperator { @Override public void delete(String namespaceId, String serviceName) throws NacosException { - metadataOperateService.deleteServiceMetadata(getServiceFromGroupedServiceName(namespaceId, serviceName)); + metadataOperateService.deleteServiceMetadata(getServiceFromGroupedServiceName(namespaceId, serviceName, true)); } @Override @@ -92,9 +92,9 @@ public class ServiceOperatorV2Impl implements ServiceOperator { return result; } - private Service getServiceFromGroupedServiceName(String namespaceId, String groupedServiceName) { + private Service getServiceFromGroupedServiceName(String namespaceId, String groupedServiceName, boolean ephemeral) { String groupName = NamingUtils.getGroupName(groupedServiceName); String serviceName = NamingUtils.getServiceName(groupedServiceName); - return Service.newService(namespaceId, groupName, serviceName); + return Service.newService(namespaceId, groupName, serviceName, ephemeral); } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java index 5f6e64f0e..09d3a5c19 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java @@ -20,6 +20,7 @@ import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.SmartSubscriber; import com.alibaba.nacos.common.utils.ConcurrentHashSet; +import com.alibaba.nacos.naming.core.v2.ServiceManager; import com.alibaba.nacos.naming.core.v2.event.client.ClientEvent; import com.alibaba.nacos.naming.core.v2.event.metadata.MetadataEvent; import com.alibaba.nacos.naming.core.v2.pojo.Service; @@ -41,12 +42,12 @@ import java.util.concurrent.ConcurrentMap; @Component public class NamingMetadataManager extends SmartSubscriber { - private final ConcurrentMap serviceMetadataMap; - - private final ConcurrentMap> instanceMetadataMap; - private final Set expiredMetadataInfos; + private ConcurrentMap serviceMetadataMap; + + private ConcurrentMap> instanceMetadataMap; + public NamingMetadataManager() { serviceMetadataMap = new ConcurrentHashMap<>(1 << 10); instanceMetadataMap = new ConcurrentHashMap<>(1 << 10); @@ -75,7 +76,9 @@ public class NamingMetadataManager extends SmartSubscriber { } /** - * Get service metadata for {@link Service}. + * Get service metadata for {@link Service}, which is the original metadata object. + * + *

This method should use only query, can't modified metadata. * * @param service service * @return service metadata @@ -85,7 +88,9 @@ public class NamingMetadataManager extends SmartSubscriber { } /** - * Get instance metadata for instance of {@link Service}. + * Get instance metadata for instance of {@link Service}, which is the original metadata object. + * + *

This method should use only query, can't modified metadata. * * @param service service * @param instanceId instance id @@ -106,6 +111,7 @@ public class NamingMetadataManager extends SmartSubscriber { * @param serviceMetadata new service metadata */ public void updateServiceMetadata(Service service, ServiceMetadata serviceMetadata) { + service.incrementRevision(); serviceMetadataMap.put(service, serviceMetadata); } @@ -171,12 +177,31 @@ public class NamingMetadataManager extends SmartSubscriber { return result; } - public void loadServiceMetadataSnapshot(Map snapshot) { - serviceMetadataMap.putAll(snapshot); + /** + * Load service metadata snapshot. + * + *

Service metadata need load back the service. + * + * @param snapshot snapshot + */ + public void loadServiceMetadataSnapshot(ConcurrentMap snapshot) { + for (Service each : snapshot.keySet()) { + ServiceManager.getInstance().getSingleton(each); + } + ConcurrentMap oldSnapshot = serviceMetadataMap; + serviceMetadataMap = snapshot; + oldSnapshot.clear(); } - public void loadInstanceMetadataSnapshot(Map> snapshot) { - instanceMetadataMap.putAll(snapshot); + /** + * Load instance metadata snapshot. + * + * @param snapshot snapshot + */ + public void loadInstanceMetadataSnapshot(ConcurrentMap> snapshot) { + ConcurrentMap> oldSnapshot = instanceMetadataMap; + instanceMetadataMap = snapshot; + oldSnapshot.clear(); } public Set getExpiredMetadataInfos() { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java index a9f084e78..121875010 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java @@ -33,6 +33,11 @@ public class ServiceMetadata implements Serializable { private static final long serialVersionUID = -6605609934135069566L; + /** + * Service is ephemeral or persistence. + */ + private boolean ephemeral = true; + /** * protect threshold. */ @@ -47,6 +52,14 @@ public class ServiceMetadata implements Serializable { private Map clusters = new ConcurrentHashMap<>(1); + public boolean isEphemeral() { + return ephemeral; + } + + public void setEphemeral(boolean ephemeral) { + this.ephemeral = ephemeral; + } + public float getProtectThreshold() { return protectThreshold; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java index 1f34e18e3..fedbb4e5e 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java @@ -34,6 +34,7 @@ import org.springframework.stereotype.Component; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.locks.ReentrantReadWriteLock; /** @@ -100,9 +101,36 @@ public class ServiceMetadataProcessor extends RequestProcessor4CP { } private void updateServiceMetadata(MetadataOperation op) { - Service service = ServiceManager.getInstance() - .getSingleton(Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName())); - namingMetadataManager.updateServiceMetadata(service, op.getMetadata()); + Service service = Service + .newService(op.getNamespace(), op.getGroup(), op.getServiceName(), op.getMetadata().isEphemeral()); + Optional currentMetadata = namingMetadataManager.getServiceMetadata(service); + if (currentMetadata.isPresent()) { + ServiceMetadata newMetadata = mergeMetadata(currentMetadata.get(), op.getMetadata()); + Service singleton = ServiceManager.getInstance().getSingleton(service); + namingMetadataManager.updateServiceMetadata(singleton, newMetadata); + } else { + Service singleton = ServiceManager.getInstance().getSingleton(service); + namingMetadataManager.updateServiceMetadata(singleton, op.getMetadata()); + } + } + + /** + * Do not modified old metadata directly to avoid read half status. + * + *

Ephemeral variable should only use the value the metadata create. + * + * @param oldMetadata old metadata + * @param newMetadata new metadata + * @return merged metadata + */ + private ServiceMetadata mergeMetadata(ServiceMetadata oldMetadata, ServiceMetadata newMetadata) { + ServiceMetadata result = new ServiceMetadata(); + result.setEphemeral(oldMetadata.isEphemeral()); + result.setClusters(oldMetadata.getClusters()); + result.setProtectThreshold(newMetadata.getProtectThreshold()); + result.setSelector(newMetadata.getSelector()); + result.setExtendData(newMetadata.getExtendData()); + return result; } private void deleteServiceMetadata(MetadataOperation op) {