[
https://issues.apache.org/jira/browse/KARAF-5562?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16640973#comment-16640973
]
ASF GitHub Bot commented on KARAF-5562:
---------------------------------------
jbonofre closed pull request #44: [KARAF-5562] Improve cellar groups
configuration synchronisation from…
URL: https://github.com/apache/karaf-cellar/pull/44
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git
a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
index 96b923dc..835b5476 100644
---
a/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
+++
b/hazelcast/src/main/java/org/apache/karaf/cellar/hazelcast/HazelcastGroupManager.java
@@ -13,15 +13,8 @@
*/
package org.apache.karaf.cellar.hazelcast;
-import java.io.IOException;
-import java.util.*;
-
import com.hazelcast.core.*;
-import org.apache.karaf.cellar.core.Configurations;
-import org.apache.karaf.cellar.core.Group;
-import org.apache.karaf.cellar.core.GroupManager;
-import org.apache.karaf.cellar.core.Node;
-import org.apache.karaf.cellar.core.Synchronizer;
+import org.apache.karaf.cellar.core.*;
import org.apache.karaf.cellar.core.event.EventConsumer;
import org.apache.karaf.cellar.core.event.EventProducer;
import org.apache.karaf.cellar.core.event.EventTransportFactory;
@@ -36,22 +29,26 @@
import org.osgi.service.cm.ConfigurationListener;
import org.slf4j.Logger;
+import java.io.IOException;
+import java.util.*;
+
/**
* A group manager implementation powered by Hazelcast.
* The role of this class is to provide means of creating groups, setting
nodes to groups etc.
* Keep in sync the distributed group configuration with the locally persisted.
*/
-public class HazelcastGroupManager implements GroupManager, EntryListener,
ConfigurationListener {
+public class HazelcastGroupManager implements GroupManager,
EntryListener<String,Object>, ConfigurationListener {
private static final transient Logger LOGGER =
org.slf4j.LoggerFactory.getLogger(HazelcastGroupManager.class);
- private static final String GROUPS = "org.apache.karaf.cellar.groups";
- private static final String GROUPS_CONFIG =
"org.apache.karaf.cellar.groups.config";
- private static final String DEFAULT_GROUP = "default";
+ private static final String HAZELCAST_GROUPS =
"org.apache.karaf.cellar.groups";
+ private static final String HAZELCAST_GROUPS_CONFIG =
"org.apache.karaf.cellar.groups.config";
private Map<String, ServiceRegistration> producerRegistrations = new
HashMap<String, ServiceRegistration>();
private Map<String, ServiceRegistration> consumerRegistrations = new
HashMap<String, ServiceRegistration>();
+ private Map<String, Object> localConfig = new HashMap<String, Object>();
+
private Map<String, EventProducer> groupProducers = new HashMap<String,
EventProducer>();
private Map<String, EventConsumer> groupConsumer = new HashMap<String,
EventConsumer>();
@@ -64,47 +61,140 @@
private CombinedClassLoader combinedClassLoader;
public void init() {
- // create a listener for group configuration.
- IMap groupConfiguration = instance.getMap(GROUPS_CONFIG);
- groupConfiguration.addEntryListener(this, true);
try {
// create group stored in configuration admin
- Configuration configuration =
configurationAdmin.getConfiguration(Configurations.GROUP, null);
- if (configuration != null) {
- Dictionary<String, Object> properties =
configuration.getProperties();
- if (properties == null) {
+ Configuration groupsConfiguration = getConfigurationForGroups();
+ Dictionary<String, Object> properties =
groupsConfiguration.getProperties();
+
+ // create a listener for group configuration.
+ IMap<String,Object> hazelcastGroupsConfig =
getClusterGroupsConfig();
+
+ hazelcastGroupsConfig.addEntryListener(this, true);
+
+ if (hazelcastGroupsConfig.isEmpty()) {
+ // First one to be here - initialize hazelcast map with local
configuration
+ LOGGER.debug("CELLAR HAZELCAST: intialize cluster with local
config");
+
+ Map<String, Object> updates =
getUpdatesForHazelcastMap(properties);
+ hazelcastGroupsConfig.putAll(updates);
+ } else {
+ if (properties != null) {
+ Enumeration<String> en = properties.keys();
+ while (en.hasMoreElements()) {
+ String key = en.nextElement();
+ localConfig.put(key , properties.get(key));
+ }
+ } else {
properties = new Hashtable<String, Object>();
}
- String groups = (String)
properties.get(Configurations.GROUPS_KEY);
- Set<String> groupNames = convertStringToSet(groups);
- if (groupNames != null && !groupNames.isEmpty()) {
- for (String groupName : groupNames) {
- createGroup(groupName);
- }
+ boolean updated = false;
+ for (String key : hazelcastGroupsConfig.keySet()) {
+ Object value = hazelcastGroupsConfig.get(key);
+ updated |= updatePropertiesFromHazelcastMap(properties,
key, value);
+ }
+ if (updated) {
+ updateConfiguration(groupsConfiguration, properties);
}
}
+
+ Node node = getNode();
+
+ // add group membership from configuration
+ properties = getConfigurationForNode().getProperties();
+ Set<String> groupNames = convertStringToSet(properties != null ?
(String) properties.get(Configurations.GROUPS_KEY) : null);
+ getClusterGroups().put(node, groupNames);
} catch (IOException e) {
LOGGER.warn("CELLAR HAZELCAST: can't create cluster group from
configuration admin", e);
}
- try {
- // add group membership from configuration
- Configuration configuration =
configurationAdmin.getConfiguration(Configurations.NODE, null);
- if (configuration != null) {
- Dictionary<String, Object> properties =
configuration.getProperties();
- if (properties == null) {
- properties = new Hashtable<String, Object>();
+ }
+
+ private boolean updatePropertiesFromHazelcastMap(Dictionary<String,
Object> properties, String key, Object value) {
+ if (!(value instanceof Map)) {
+ return false;
+ }
+ boolean changed = false;
+ @SuppressWarnings("unchecked")
+ Map<String, Object> map = (Map<String, Object>) value;
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ String entryKey = entry.getKey();
+ Object entryValue = entry.getValue();
+ if (entryKey.equals(".change")) {
+ Set<String> groups = convertStringToSet((String)
properties.get(Configurations.GROUPS_KEY));
+ if ((entryValue.equals("added") && !groups.contains(key))
+ || entryValue.equals("removed") &&
groups.contains(key)) {
+ LOGGER.debug("CELLAR HAZELCAST: get group " + key + "
configuration from cluster : " + key
+ + " has been " + entryValue);
+ if (entryValue.equals("added")) {
+ groups.add(key);
+ } else {
+ groups.remove(key);
+ }
+ String newValue = convertSetToString(groups);
+ properties.put(Configurations.GROUPS_KEY, newValue);
+ localConfig.put(Configurations.GROUPS_KEY, newValue);
+ changed = true;
}
- String groups = (String)
properties.get(Configurations.GROUPS_KEY);
- Set<String> groupNames = convertStringToSet(groups);
- if (groupNames != null && !groupNames.isEmpty()) {
- for (String groupName : groupNames) {
- registerGroup(groupName);
+ } else if (properties.get(entryKey) == null ||
!properties.get(entryKey).equals(entryValue)) {
+ LOGGER.debug("CELLAR HAZELCAST: get group " + key + "
configuration from cluster : " + entryKey + " = "
+ + entryValue);
+ properties.put(entryKey, entryValue);
+ localConfig.put(entryKey, entryValue);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private Map<String, Object> getUpdatesForHazelcastMap(Dictionary<String,
Object> properties) {
+ Map<String,Object> updates = new HashMap<String,Object>();
+ if (properties == null) {
+ return updates;
+ }
+ Enumeration<String> en = properties.keys();
+ while (en.hasMoreElements()) {
+ String key = en.nextElement();
+ Object value = properties.get(key);
+
+ if (!key.startsWith("felix.") && !key.startsWith("service.")) {
+ Object localValue = localConfig.get(key);
+ if (localValue == null || !localValue.equals(value)) {
+ if (key.equals(Configurations.GROUPS_KEY)) {
+ Set<String> removedGroups =
convertStringToSet((String) localValue);
+ Set<String> addedGroups = convertStringToSet((String)
value);
+ addedGroups.removeAll(removedGroups);
+ removedGroups.removeAll(convertStringToSet((String)
value));
+ for (String addedGroup : addedGroups) {
+ getOrCreateMap(updates, addedGroup).put(".change",
"added");
+ }
+ for (String removedGroup : removedGroups) {
+ getOrCreateMap(updates,
removedGroup).put(".change", "removed");
+ }
+ } else {
+ int idx = key.indexOf(".");
+ if (idx > 0) {
+ String groupKey = key.substring(0, idx);
+ getOrCreateMap(updates, groupKey).put(key, value);
+ } else {
+ LOGGER.warn("CELLAR HAZELCAST: found group
property that is not prefixed with a group name: {}. Skipping it", key);
+ }
}
}
}
- } catch (IOException e) {
- LOGGER.error("CELLAR HAZELCAST: can't set group membership for the
current node", e);
+
+ localConfig.put(key , value);
+
}
+ return updates;
+ }
+
+ private Map<String, Object> getOrCreateMap(Map<String, Object> updates,
String group) {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> props = (Map<String, Object>) updates.get(group);
+ if (props == null) {
+ props = new HashMap<String, Object>();
+ updates.put(group, props);
+ }
+ return props;
}
public void destroy() {
@@ -113,12 +203,9 @@ public void destroy() {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
// update the group
Node local = this.getNode();
- Set<Group> groups = this.listGroups(local);
- for (Group group : groups) {
- String groupName = group.getName();
- group.getNodes().remove(local);
- listGroups().put(groupName, group);
- }
+
+ getClusterGroups().remove(local);
+
// shutdown the group consumer/producers
for (Map.Entry<String, EventConsumer> consumerEntry :
groupConsumer.entrySet()) {
EventConsumer consumer = consumerEntry.getValue();
@@ -153,18 +240,24 @@ public Group createGroup(String groupName) {
ClassLoader originalClassLoader =
Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
- Group group = listGroups().get(groupName);
+ Map<String, Group> listGroups = listGroups();
+ Group group = listGroups.get(groupName);
if (group == null) {
group = new Group(groupName);
- }
- if (!listGroups().containsKey(groupName)) {
- copyGroupConfiguration(Configurations.DEFAULT_GROUP_NAME,
groupName);
- listGroups().put(groupName, group);
try {
- // store the group list to configuration admin
- persist(listGroups());
- } catch (Exception e) {
- LOGGER.warn("CELLAR HAZELCAST: can't store cluster group
list", e);
+ Configuration configuration = getConfigurationForGroups();
+ if (configuration != null) {
+ Dictionary<String, Object> properties =
configuration.getProperties();
+ if (properties != null && !properties.isEmpty()) {
+ properties =
copyGroupConfiguration(Configurations.DEFAULT_GROUP_NAME + '.', groupName +
'.', properties);
+ Set<String> groups = convertStringToSet((String)
properties.get(Configurations.GROUPS_KEY));
+ groups.add(groupName);
+ properties.put(Configurations.GROUPS_KEY,
convertSetToString(groups));
+ updateConfiguration(configuration, properties);
+ }
+ }
+ } catch (IOException e) {
+ LOGGER.error("CELLAR HAZELCAST: failed to update cluster
group configuration", e);
}
}
return group;
@@ -179,11 +272,15 @@ public void deleteGroup(String groupName) {
try {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
if (!groupName.equals(Configurations.DEFAULT_GROUP_NAME)) {
- listGroups().remove(groupName);
try {
// store the group list to configuration admin
- persist(listGroups());
- } catch (Exception e) {
+ Configuration configuration = getConfigurationForGroups();
+ Dictionary<String, Object> properties =
configuration.getProperties();
+ Set<String> groups = convertStringToSet((String)
properties.get(Configurations.GROUPS_KEY));
+ groups.remove(groupName);
+ properties.put(Configurations.GROUPS_KEY,
convertSetToString(groups));
+ updateConfiguration(configuration, properties);
+ } catch (IOException e) {
LOGGER.warn("CELLAR HAZELCAST: can't store cluster group
list", e);
}
}
@@ -192,24 +289,6 @@ public void deleteGroup(String groupName) {
}
}
- /**
- * Store the group names in configuration admin.
- *
- * @param groups the list of group to store.
- * @throws Exception in case of storage failure.
- */
- private void persist(Map<String, Group> groups) throws Exception {
- Configuration configuration =
configurationAdmin.getConfiguration(Configurations.GROUP, null);
- if (configuration != null) {
- Dictionary<String, Object> properties =
configuration.getProperties();
- if (properties == null) {
- properties = new Hashtable<String, Object>();
- }
- properties.put(Configurations.GROUPS_KEY,
convertSetToString(groups.keySet()));
- configuration.update(properties);
- }
- }
-
@Override
public Set<Group> listLocalGroups() {
ClassLoader originalClassLoader =
Thread.currentThread().getContextClassLoader();
@@ -264,8 +343,24 @@ public Group findGroupByName(String groupName) {
public Map<String, Group> listGroups() {
ClassLoader originalClassLoader =
Thread.currentThread().getContextClassLoader();
try {
+ Map<String, Group> res = new HashMap<String, Group>();
Thread.currentThread().setContextClassLoader(combinedClassLoader);
- return instance.getMap(GROUPS);
+ Map<Node, Set<String>> nodes = getClusterGroups();
+
+ Set<String> groups = convertStringToSet((String)
localConfig.get(Configurations.GROUPS_KEY));
+ groups.add(Configurations.DEFAULT_GROUP_NAME);
+
+ for (String groupName : groups) {
+ Group group = new Group(groupName);
+ res.put(groupName, group);
+ for (Map.Entry<Node, Set<String>> entry : nodes.entrySet()) {
+ if (entry.getValue().contains(groupName)) {
+ group.getNodes().add(entry.getKey());
+ }
+ }
+ }
+
+ return res;
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
@@ -278,15 +373,15 @@ public Group findGroupByName(String groupName) {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
Set<Group> result = new HashSet<Group>();
- Map<String, Group> groupMap = instance.getMap(GROUPS);
- Collection<Group> groupCollection = groupMap.values();
- if (groupCollection != null && !groupCollection.isEmpty()) {
- for (Group group : groupCollection) {
- if (group.getNodes().contains(node)) {
- result.add(group);
- }
- }
+ Map<Node, Set<String>> groupMap = getClusterGroups();
+ Set<String> groupNames = groupMap.get(node);
+
+ if (groupNames != null) {
+ Map<String, Group> g = listGroups();
+ g.keySet().retainAll(groupNames);
+ result.addAll(g.values());
}
+
return result;
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
@@ -336,7 +431,6 @@ public void registerGroup(Group group) {
try {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
String groupName = group.getName();
- createGroup(groupName);
LOGGER.debug("CELLAR HAZELCAST: registering cluster group {}.",
groupName);
Properties serviceProperties = new Properties();
@@ -366,12 +460,17 @@ public void registerGroup(Group group) {
consumerRegistrations.put(groupName, consumerRegistration);
}
- group.getNodes().add(getNode());
- listGroups().put(groupName, group);
+ Node node = getNode();
+ group.getNodes().add(node);
+ Map<Node, Set<String>> map = getClusterGroups();
+ Set<String> groupNames = (Set<String>) map.get(node);
+ groupNames = new HashSet<String>(groupNames);
+ groupNames.add(groupName);
+ map.put(node, groupNames);
// add group to configuration
try {
- Configuration configuration =
configurationAdmin.getConfiguration(Configurations.NODE, null);
+ Configuration configuration = getConfigurationForNode();
if (configuration != null) {
Dictionary<String, Object> properties =
configuration.getProperties();
if (properties != null) {
@@ -388,7 +487,7 @@ public void registerGroup(Group group) {
groups = groupName;
}
properties.put(Configurations.GROUPS_KEY, groups);
- configuration.update(properties);
+ updateConfiguration(configuration, properties);
}
}
} catch (IOException e) {
@@ -420,11 +519,7 @@ public void registerGroup(String groupName) {
ClassLoader originalClassLoader =
Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(combinedClassLoader);
- Group group = listGroups().get(groupName);
- if (group == null) {
- group = new Group(groupName);
- }
- registerGroup(group);
+ registerGroup(new Group(groupName));
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
@@ -476,9 +571,17 @@ public void unRegisterGroup(Group group) {
consumer.stop();
}
+ Node node = getNode();
+ group.getNodes().add(node);
+ Map<Node, Set<String>> map = getClusterGroups();
+ Set<String> groupNames = (Set<String>) map.get(node);
+ groupNames = new HashSet<String>(groupNames);
+ groupNames.remove(groupName);
+ map.put(node, groupNames);
+
// remove cluster group from configuration
try {
- Configuration configuration =
configurationAdmin.getConfiguration(Configurations.NODE, null);
+ Configuration configuration = getConfigurationForNode();
Dictionary<String, Object> properties =
configuration.getProperties();
String groups = (String)
properties.get(Configurations.GROUPS_KEY);
if (groups == null || groups.isEmpty()) {
@@ -489,7 +592,7 @@ public void unRegisterGroup(Group group) {
groups = convertSetToString(groupNamesSet);
}
properties.put(Configurations.GROUPS_KEY, groups);
- configuration.update(properties);
+ updateConfiguration(configuration, properties);
} catch (IOException e) {
LOGGER.error("CELLAR HAZELCAST: failed to read cluster group
configuration", e);
}
@@ -501,50 +604,24 @@ public void unRegisterGroup(Group group) {
/**
* Copy the configuration of a cluster {@link Group}.
*
- * <b>1.</b> Updates configuration admin from Hazelcast using source
config.
- * <b>2.</b> Creates target configuration both on Hazelcast and
configuration admin.
- *
- * @param sourceGroupName the source cluster group.
- * @param targetGroupName the target cluster group.
+ * @param sourceGroupPrefix the source cluster group prefix
+ * @param targetGroupPrefix the target cluster group prefix
+ * @return new properties object
*/
- public void copyGroupConfiguration(String sourceGroupName, String
targetGroupName) {
- try {
- Configuration conf =
configurationAdmin.getConfiguration(Configurations.GROUP, null);
- if (conf != null) {
-
- // get configuration from config admin
- Dictionary configAdminProperties = conf.getProperties();
- if (configAdminProperties == null) {
- configAdminProperties = new Properties();
- }
- // get configuration from Hazelcast
- Map<String, String> sourceGroupConfig =
instance.getMap(GROUPS_CONFIG);
-
- // update local configuration from cluster
- for (Map.Entry<String, String> parentEntry :
sourceGroupConfig.entrySet()) {
- configAdminProperties.put(parentEntry.getKey(),
parentEntry.getValue());
- }
-
- Dictionary updatedProperties = new Properties();
- Enumeration keyEnumeration = configAdminProperties.keys();
- while (keyEnumeration.hasMoreElements()) {
- String key = (String) keyEnumeration.nextElement();
- String value = configAdminProperties.get(key).toString();
-
- if (key.startsWith(sourceGroupName)) {
- String newKey = key.replace(sourceGroupName,
targetGroupName);
- updatedProperties.put(newKey, value);
- sourceGroupConfig.put(key, value);
- }
- updatedProperties.put(key, value);
- }
-
- conf.update(updatedProperties);
+ public Dictionary<String, Object> copyGroupConfiguration(String
sourceGroupPrefix, String targetGroupPrefix, Dictionary<String, Object>
properties) {
+ Dictionary<String, Object> updatedProperties = new Hashtable<String,
Object>();
+ Enumeration<String> keyEnumeration = properties.keys();
+ while (keyEnumeration.hasMoreElements()) {
+ String key = keyEnumeration.nextElement();
+ Object value = properties.get(key);
+
+ if (key.startsWith(sourceGroupPrefix)) {
+ String newKey = targetGroupPrefix +
key.substring(sourceGroupPrefix.length());
+ updatedProperties.put(newKey, value);
}
-
- } catch (IOException e) {
- LOGGER.error("CELLAR HAZELCAST: failed to read cluster group
configuration", e);
+ updatedProperties.put(key, value);
}
+ return updatedProperties;
}
/**
@@ -554,7 +631,7 @@ public void copyGroupConfiguration(String sourceGroupName,
String targetGroupNam
* @return the String corresponding to the Set.
*/
protected String convertSetToString(Set<String> set) {
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
Iterator<String> groupIterator = set.iterator();
while (groupIterator.hasNext()) {
String name = groupIterator.next();
@@ -573,14 +650,14 @@ protected String convertSetToString(Set<String> set) {
* @return the Set corresponding to the String.
*/
protected Set<String> convertStringToSet(String string) {
- if (string == null)
- return Collections.EMPTY_SET;
- Set<String> result = new HashSet<String>();
+ if (string == null)
+ return Collections.emptySet();
+ Set<String> result = new TreeSet<String>();
String[] groupNames = string.split(",");
if (groupNames != null && groupNames.length > 0) {
for (String name : groupNames) {
- result.add(name);
+ result.add(name.trim());
}
} else {
result.add(string);
@@ -593,26 +670,35 @@ protected String convertSetToString(Set<String> set) {
*
* @param configurationEvent the local configuration event.
*/
+ @SuppressWarnings("unchecked")
@Override
public void configurationEvent(ConfigurationEvent configurationEvent) {
- String pid = configurationEvent.getPid();
- if (pid.equals(GROUPS)) {
- Map groupConfiguration = instance.getMap(GROUPS_CONFIG);
-
- try {
- Configuration conf =
configurationAdmin.getConfiguration(GROUPS, null);
- Dictionary properties = conf.getProperties();
- Enumeration keyEnumeration = properties.keys();
- while (keyEnumeration.hasMoreElements()) {
- Object key = keyEnumeration.nextElement();
- Object value = properties.get(key);
- if (!groupConfiguration.containsKey(key) ||
groupConfiguration.get(key) == null ||
!groupConfiguration.get(key).equals(value)) {
- groupConfiguration.put(key, value);
+ if (!Configurations.GROUP.equals(configurationEvent.getPid())) {
+ return;
+ }
+ try {
+ Map<String, Object> hazelcastGroupConfig =
getClusterGroupsConfig();
+ Configuration conf = getConfigurationForGroups();
+ Dictionary<String, Object> properties = conf.getProperties();
+ Map<String, Object> updates =
getUpdatesForHazelcastMap(properties);
+ for (Map.Entry<String, Object> entry : updates.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ Object clusterValue = hazelcastGroupConfig.get(key);
+ if (clusterValue == null || !clusterValue.equals(value)) {
+ LOGGER.debug("CELLAR HAZELCAST : sending updates to
cluster : " + key + " = " + value);
+ if (clusterValue != null && value instanceof Map) {
+ @SuppressWarnings("rawtypes")
+ Map<String, Object> newValue = new HashMap((Map)
clusterValue);
+ newValue.putAll((Map<? extends String, ?>) value);
+ hazelcastGroupConfig.put(key, newValue);
+ } else {
+ hazelcastGroupConfig.put(key, value);
}
}
- } catch (Exception e) {
- LOGGER.warn("CELLAR HAZELCAST: failed to update cluster group
configuration", e);
}
+ } catch (Exception e) {
+ LOGGER.warn("CELLAR HAZELCAST: failed to update cluster group
configuration", e);
}
}
@@ -622,7 +708,7 @@ public void configurationEvent(ConfigurationEvent
configurationEvent) {
* @param entryEvent entry event
*/
@Override
- public void entryAdded(EntryEvent entryEvent) {
+ public void entryAdded(EntryEvent<String,Object> entryEvent) {
entryUpdated(entryEvent);
}
@@ -632,7 +718,7 @@ public void entryAdded(EntryEvent entryEvent) {
* @param entryEvent entry event
*/
@Override
- public void entryRemoved(EntryEvent entryEvent) {
+ public void entryRemoved(EntryEvent<String,Object> entryEvent) {
entryUpdated(entryEvent);
}
@@ -642,16 +728,16 @@ public void entryRemoved(EntryEvent entryEvent) {
* @param entryEvent entry event
*/
@Override
- public void entryUpdated(EntryEvent entryEvent) {
- LOGGER.debug("CELLAR HAZELCAST: cluster group configuration has been
updated, updating local configuration");
+ public void entryUpdated(EntryEvent<String,Object> entryEvent) {
try {
- Configuration conf = configurationAdmin.getConfiguration(GROUPS,
null);
- Dictionary props = conf.getProperties();
- Object key = entryEvent.getKey();
+ Configuration conf = getConfigurationForGroups();
+ Dictionary<String, Object> properties = conf.getProperties();
+ String key = entryEvent.getKey();
Object value = entryEvent.getValue();
- if (props.get(key) == null || !props.get(key).equals(value)) {
- props.put(key, value);
- conf.update(props);
+
+ if (updatePropertiesFromHazelcastMap(properties, key, value)) {
+ LOGGER.debug("CELLAR HAZELCAST: cluster group configuration
has been updated, updating local configuration: {} = {}", key, value);
+ updateConfiguration(conf, properties);
}
} catch (Exception ex) {
LOGGER.warn("CELLAR HAZELCAST: failed to update local
configuration", ex);
@@ -664,7 +750,7 @@ public void entryUpdated(EntryEvent entryEvent) {
* @param entryEvent entry event
*/
@Override
- public void entryEvicted(EntryEvent entryEvent) {
+ public void entryEvicted(EntryEvent<String,Object> entryEvent) {
entryUpdated(entryEvent);
}
@@ -718,4 +804,24 @@ public void setCombinedClassLoader(CombinedClassLoader
combinedClassLoader) {
this.combinedClassLoader = combinedClassLoader;
}
+ private Configuration getConfigurationForGroups() throws IOException {
+ return configurationAdmin.getConfiguration(Configurations.GROUP, null);
+ }
+
+ private Configuration getConfigurationForNode() throws IOException {
+ return configurationAdmin.getConfiguration(Configurations.NODE, null);
+ }
+
+ private IMap<Node, Set<String>> getClusterGroups() {
+ return instance.getMap(HAZELCAST_GROUPS);
+ }
+
+ private IMap<String, Object> getClusterGroupsConfig() {
+ return instance.getMap(HAZELCAST_GROUPS_CONFIG);
+ }
+
+ private void updateConfiguration(Configuration cfg, Dictionary<String,
Object> properties) throws IOException {
+ cfg.update(properties);
+ LOGGER.debug("CELLAR HAZELCAST: updated configuration with pid: {}",
cfg.getPid());
+ }
}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> Improve cellar groups configuration synchronisation from hazelcast
> ------------------------------------------------------------------
>
> Key: KARAF-5562
> URL: https://issues.apache.org/jira/browse/KARAF-5562
> Project: Karaf
> Issue Type: Improvement
> Components: cellar
> Affects Versions: cellar-4.0.4, cellar-4.1.1
> Reporter: Thomas Draier
> Assignee: Jean-Baptiste Onofré
> Priority: Major
> Fix For: cellar-4.0.5, cellar-4.1.2, cellar-4.2.0
>
>
> We encountered different issues due to HazelcastGroupManager, I'm grouping
> them here as all of them are linked and we fixed them in a single refactoring
> of the class. This globally result in a better synchronization of the cellar
> groups configuration.
> - Hazelcast network splits can result in very bad behaviour on the “groups”
> shared map - this map contains the list of groups and its members, and the
> system fully rely on it to know in which groups you are. If multiple nodes
> updates the map while they are not connected together (easy to reproduce by
> starting both nodes at the same time), and then join afterwards, the default
> merge algorithm is applied and simply overwrite the full map. This basically
> result in groups loosing members, even if the configuration file claims that
> the nodes are still members.
> - When handling the groups configuration, HazelcastGroupManager replicates
> the felix.fileinstall.filename property on each node, containing the
> configuration file path. It’s quite “ok” if you’re on a cluster with each
> node installed on the exact same path - however if you’re on the same
> machine, with 2 nodes on different paths : one node will at one point write
> on the config file of the other node and never updates its own config, which
> can be quite confusing.
> - The HazelcastGroupManager can start even when a configuration is not
> detected by fileinstall yet - it then creates a new config, based on the
> hazelcast shared config, which will override the config file when fileinstall
> detects it. It does not have a huge impact, but it shuffles the properties
> files and makes it unreadable.
> - The updates from hazelcast to local config trigger back update on hazelcast
> which goes back to local config and sometimes revert the changes, resulting
> in no change in the config. Basically , when adding a group, a lot of
> properties are updated - for each of them we trigger a configuration update.
> Each configuration update triggers an event which send the whole config back
> to hazelcast, including properties that are not updated yet, setting them
> back to their old values. All events (hazelcast updates and osgi config) are
> treated asynchronously - depending on the orders of events, some properties
> can be reverted or never added (usually groups property is always reverted
> after a group add).
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)