Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FISH-1289 QACI-579] fix race condition with duplicate initialization of Micro ports #5184

Merged
merged 1 commit into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2016-2020 Payara Foundation and/or its affiliates. All rights reserved.
* Copyright (c) 2016-2021 Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -95,6 +95,8 @@
import fish.payara.nucleus.hazelcast.HazelcastCore;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.glassfish.grizzly.utils.Holder.LazyHolder;
import static org.glassfish.grizzly.utils.Holder.lazyHolder;

/**
* Internal Payara Service for describing instances
Expand Down Expand Up @@ -140,7 +142,7 @@ public class PayaraInstanceImpl implements EventListener, MessageReceiver, Payar
private String instanceName;
private String instanceGroup;

private InstanceDescriptorImpl me;
private final LazyHolder<InstanceDescriptorImpl> descriptor = lazyHolder(this::initialiseInstanceDescriptor);

@Inject
private ServerEnvironment environment;
Expand All @@ -153,13 +155,7 @@ public class PayaraInstanceImpl implements EventListener, MessageReceiver, Payar

@Inject
private PayaraExecutorService executor;

private synchronized InstanceDescriptorImpl getMyInstanceDescriptor() {
if (me == null) {
initialiseInstanceDescriptor();
}
return me;
}


@Override
public String getInstanceName() {
Expand All @@ -169,7 +165,7 @@ public String getInstanceName() {
@Override
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
me.setInstanceName(instanceName);
descriptor.get().setInstanceName(instanceName);
}

@Override
Expand Down Expand Up @@ -246,32 +242,32 @@ void postConstruct() {
@SuppressWarnings({"unchecked"})
public void event(Event event) {
if (event.is(EventTypes.SERVER_READY)) {
PayaraInternalEvent pie = new PayaraInternalEvent(PayaraInternalEvent.MESSAGE.ADDED, getMyInstanceDescriptor());
PayaraInternalEvent pie = new PayaraInternalEvent(PayaraInternalEvent.MESSAGE.ADDED, descriptor.get());
ClusterMessage<PayaraInternalEvent> message = new ClusterMessage<>(pie);
this.cluster.getEventBus().publish(INTERNAL_EVENTS_NAME, message);

for (String appName : appRegistry.getAllApplicationNames()) {
getMyInstanceDescriptor().addApplication(new ApplicationDescriptorImpl(appRegistry.get(appName)));
descriptor.get().addApplication(new ApplicationDescriptorImpl(appRegistry.get(appName)));
}

cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, getMyInstanceDescriptor());
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, descriptor.get());
executor.scheduleAtFixedRate(() -> {
getMyInstanceDescriptor().setLastHeartBeat(System.currentTimeMillis());
descriptor.get().setLastHeartBeat(System.currentTimeMillis());
if (myCurrentID != null) {
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, getMyInstanceDescriptor());
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, descriptor.get());
}
}, 0, 5, TimeUnit.SECONDS);
} // Adds the application to the clustered register of deployed applications
else if (event.is(Deployment.APPLICATION_STARTED)) {
if (event.hook() != null && event.hook() instanceof ApplicationInfo) {
ApplicationInfo applicationInfo = (ApplicationInfo) event.hook();
getMyInstanceDescriptor().addApplication(new ApplicationDescriptorImpl(applicationInfo));
descriptor.get().addApplication(new ApplicationDescriptorImpl(applicationInfo));
logger.log(Level.FINE, "App Loaded: {2}, Enabled: {0}, my ID: {1}", new Object[] { hazelcast.isEnabled(),
myCurrentID, applicationInfo.getName() });
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, getMyInstanceDescriptor());
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, descriptor.get());
}
}
// ensures the same application id is used when there is a deployment
// ensures the same application id is used when there is a deployment
// if the application id is in the cluster keyed by application name
else if (event.is(Deployment.APPLICATION_PREPARED)) {
if (event.hook() != null && event.hook() instanceof DeploymentContext) {
Expand All @@ -291,19 +287,19 @@ else if (event.is(Deployment.APPLICATION_PREPARED)) {
else if (event.is(Deployment.APPLICATION_UNLOADED)) {
if (event.hook() != null && event.hook() instanceof ApplicationInfo) {
ApplicationInfo applicationInfo = (ApplicationInfo) event.hook();
getMyInstanceDescriptor().removeApplication(new ApplicationDescriptorImpl(applicationInfo));
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, getMyInstanceDescriptor());
descriptor.get().removeApplication(new ApplicationDescriptorImpl(applicationInfo));
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, descriptor.get());
}
} else if (event.is(HazelcastEvents.HAZELCAST_SHUTDOWN_STARTED)) {
PayaraInternalEvent pie = new PayaraInternalEvent(PayaraInternalEvent.MESSAGE.REMOVED, getMyInstanceDescriptor());
PayaraInternalEvent pie = new PayaraInternalEvent(PayaraInternalEvent.MESSAGE.REMOVED, descriptor.get());
ClusterMessage<PayaraInternalEvent> message = new ClusterMessage<>(pie);
this.cluster.getClusteredStore().remove(INSTANCE_STORE_NAME, myCurrentID);
this.cluster.getEventBus().publish(INTERNAL_EVENTS_NAME, message);
}

// When Hazelcast is bootstrapped, update the instance descriptor with any new information
if (event.is(HazelcastEvents.HAZELCAST_BOOTSTRAP_COMPLETE)) {
initialiseInstanceDescriptor();
descriptor.get();
logger.log(Level.FINE, "Hz Bootstrap Complete, Enabled: {0}, my ID: {1}", new Object[] { hazelcast.isEnabled(), myCurrentID });
// remove listener first
cluster.getEventBus().removeMessageReceiver(INTERNAL_EVENTS_NAME, this);
Expand All @@ -314,7 +310,7 @@ else if (event.is(Deployment.APPLICATION_UNLOADED)) {

// If the generated name had to be changed, update the instance descriptor with the new information
if (event.is(HazelcastEvents.HAZELCAST_GENERATED_NAME_CHANGE)) {
initialiseInstanceDescriptor();
descriptor.get();
}
}

Expand All @@ -334,7 +330,7 @@ public Set<InstanceDescriptor> getClusteredPayaras() {
@Override
public void publishCDIEvent(PayaraClusteredCDIEvent event) {
if (event.getInstanceDescriptor() == null) {
event.setId(me);
event.setId(descriptor.get());
}
ClusterMessage<PayaraClusteredCDIEvent> message = new ClusterMessage<>(event);
cluster.getEventBus().publish(CDI_EVENTS_NAME, message);
Expand Down Expand Up @@ -362,7 +358,7 @@ public void addCDIListener(CDIEventListener listener) {

@Override
public InstanceDescriptor getLocalDescriptor() {
return me;
return descriptor.get();
}

@Override
Expand All @@ -374,7 +370,7 @@ public InstanceDescriptorImpl getDescriptor(UUID member) {
return result;
}

private void initialiseInstanceDescriptor() {
private InstanceDescriptorImpl initialiseInstanceDescriptor() {
boolean liteMember = false;
int hazelcastPort = 5900;
InetAddress hostname = null;
Expand All @@ -399,7 +395,7 @@ private void initialiseInstanceDescriptor() {
List<Integer> ports = new ArrayList<>();
List<Integer> sslPorts = new ArrayList<>();
int adminPort = 0;
for (NetworkListener networkListener :
for (NetworkListener networkListener :
context.getConfigBean().getConfig().getNetworkConfig().getNetworkListeners().getNetworkListener()) {

// Try and get the port. First get the port in the domain xml, then attempt to get the dynamic config port.
Expand Down Expand Up @@ -444,45 +440,43 @@ private void initialiseInstanceDescriptor() {

// Initialise the instance descriptor and set all of its attributes
try {
InstanceDescriptorImpl instanceDescriptor = new InstanceDescriptorImpl(myCurrentID);
// If Hazelcast is being rebooted dynamically, we don't want to lose the already registered applications
Collection<ApplicationDescriptor> deployedApplications = new ArrayList<>();
if (me != null) {
deployedApplications = me.getDeployedApplications();
}
me = new InstanceDescriptorImpl(myCurrentID);
me.setInstanceName(instanceName);
me.setInstanceGroup(instanceGroup);
Collection<ApplicationDescriptor> deployedApplications = instanceDescriptor.getDeployedApplications();
instanceDescriptor.setInstanceName(instanceName);
instanceDescriptor.setInstanceGroup(instanceGroup);
for (int port : ports) {
me.addHttpPort(port);
instanceDescriptor.addHttpPort(port);
}

for (int sslPort : sslPorts) {
me.addHttpsPort(sslPort);
instanceDescriptor.addHttpsPort(sslPort);
}

me.setAdminPort(adminPort);
me.setHazelcastPort(hazelcastPort);
me.setLiteMember(liteMember);
me.setInstanceType(instanceType);
instanceDescriptor.setAdminPort(adminPort);
instanceDescriptor.setHazelcastPort(hazelcastPort);
instanceDescriptor.setLiteMember(liteMember);
instanceDescriptor.setInstanceType(instanceType);

if (hostname != null) {
me.setHostName(hostname);
instanceDescriptor.setHostName(hostname);
}

// If there were some deployed applications from the previous instance descriptor, register them with the new
// If there were some deployed applications from the previous instance descriptor, register them with the new
// one
if (!deployedApplications.isEmpty()) {
for (ApplicationDescriptor application : deployedApplications) {
me.addApplication(application);
instanceDescriptor.addApplication(application);
}
}

// Register the instance descriptor to the cluster if it's enabled
if (cluster.isEnabled()) {
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, me);
cluster.getClusteredStore().set(INSTANCE_STORE_NAME, myCurrentID, instanceDescriptor);
}
return instanceDescriptor;
} catch (UnknownHostException ex) {
logger.log(Level.SEVERE, "Could not find local hostname", ex);
throw new RuntimeException(ex);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.

Copyright (c) 2016-2020 Payara Foundation. All rights reserved.
Copyright (c) 2016-2021 Payara Foundation. All rights reserved.

The contents of this file are subject to the terms of the Common Development
and Distribution License("CDDL") (collectively, the "License"). You
Expand All @@ -25,7 +25,6 @@ and Distribution License("CDDL") (collectively, the "License"). You
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -46,6 +45,10 @@ and Distribution License("CDDL") (collectively, the "License"). You
import fish.payara.micro.data.ApplicationDescriptor;
import fish.payara.micro.data.InstanceDescriptor;
import fish.payara.micro.data.ModuleDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;

/**
Expand All @@ -58,8 +61,8 @@ public class InstanceDescriptorImpl implements InstanceDescriptor {

private final UUID memberUUID;
private String instanceName;
private final List<Integer> httpPorts;
private final List<Integer> httpsPorts;
private final Set<Integer> httpPorts;
private final Set<Integer> httpsPorts;
private InetAddress hostName;
private Map<String, ApplicationDescriptor> deployedApplications;
private boolean liteMember;
Expand All @@ -72,8 +75,8 @@ public class InstanceDescriptorImpl implements InstanceDescriptor {
public InstanceDescriptorImpl(UUID uuid) throws UnknownHostException {
hostName = InetAddress.getLocalHost();
memberUUID = uuid;
httpPorts = new ArrayList<>();
httpsPorts = new ArrayList<>();
httpPorts = new LinkedHashSet<>();
httpsPorts = new LinkedHashSet<>();
heartBeatTS = System.currentTimeMillis();
}

Expand Down Expand Up @@ -116,7 +119,7 @@ public UUID getMemberUUID() {
*/
@Override
public List<Integer> getHttpPorts() {
return httpPorts;
return Collections.unmodifiableList(new ArrayList<>(httpPorts));
}

/**
Expand Down Expand Up @@ -157,7 +160,7 @@ public Collection<ApplicationDescriptor> getDeployedApplications() {
*/
@Override
public List<Integer> getHttpsPorts() {
return httpsPorts;
return Collections.unmodifiableList(new ArrayList<>(httpsPorts));
}

/**
Expand Down Expand Up @@ -342,7 +345,7 @@ private JsonObject toJsonObject(boolean verbose) {
});
appBuilder.add("Mappings", servletMappings.build());
}

// If there's more modules, print info for each module
} else {
JsonArrayBuilder modules = Json.createArrayBuilder();
Expand Down Expand Up @@ -398,7 +401,7 @@ public String toString() {
if (memberUUID != null) {
sb.append("Hazelcast Member UUID ").append(this.memberUUID).append('\n');
}

for (ApplicationDescriptor applicationDescriptor : getDeployedApplications()) {
sb.append("Deployed: ");
sb.append(applicationDescriptor.getName()).append(" ( ");
Expand All @@ -409,7 +412,7 @@ public String toString() {
} else {
sb.append("***");
}

sb.append(" [ ");
for (Entry<String, String> servletMapping : moduleDescriptor.getServletMappings().entrySet()) {
sb.append("< ")
Expand All @@ -419,7 +422,7 @@ public String toString() {
sb.append(" ] ");
}
sb.append(")\n");

String libraries = applicationDescriptor.getLibraries();
if (libraries != null) {
sb.append(' ').append(applicationDescriptor.getLibraries());
Expand Down Expand Up @@ -457,23 +460,23 @@ public List<URL> getApplicationURLS() {
}
return result;
}

/**
* Gets the instance group name
* @return The instance group name
*/
public String getInstanceGroup() {
return instanceGroup;
}

/**
* Sets the instance group name
* @param instanceGroup The instance group name
*/
public void setInstanceGroup(String instanceGroup) {
this.instanceGroup = instanceGroup;
}

public void setLastHeartBeat(long val) {
heartBeatTS = val;
}
Expand Down
8 changes: 7 additions & 1 deletion appserver/tests/payara-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<!-- >= 1.7.0 supports parallel testing -->
<version>1.7.0.Alpha6</version>
<version>1.7.0.Alpha9</version>
<scope>import</scope>
<type>pom</type>
</dependency>
Expand Down Expand Up @@ -534,6 +534,12 @@
<version>1.7.30</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>fish.payara.arquillian</groupId>
<artifactId>payara-client-ee8</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
<!-- needed for maven-war-plugin to work properly -->
<dependency>
<groupId>jakarta.servlet</groupId>
Expand Down
Loading