Skip to content

Commit

Permalink
ISPN-14568 Cache aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
tristantarrant committed Mar 11, 2024
1 parent dcb6440 commit 5269fb7
Show file tree
Hide file tree
Showing 58 changed files with 514 additions and 198 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,15 @@ public Iterable<String> getChildrenNames() {

@Override
public Resource getChild(String name) {
switch (name) {
case Resource.PARENT:
return parent;
case CachesResource.NAME:
return new CachesResource(this);
case CountersResource.NAME:
return new CountersResource(this);
case ConfigurationsResource.NAME:
return new ConfigurationsResource(this);
case SchemasResource.NAME:
return new SchemasResource(this);
case TasksResource.NAME:
return new TasksResource(this);
default:
throw Messages.MSG.noSuchResource(name);
}
return switch (name) {
case Resource.PARENT -> parent;
case CachesResource.NAME -> new CachesResource(this);
case CountersResource.NAME -> new CountersResource(this);
case ConfigurationsResource.NAME -> new ConfigurationsResource(this);
case SchemasResource.NAME -> new SchemasResource(this);
case TasksResource.NAME -> new TasksResource(this);
default -> throw Messages.MSG.noSuchResource(name);
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ public CompletionStage<RestResponse> updateWithConfiguration(RestEntity configur
public CompletionStage<RestResponse> updateConfigurationAttribute(String attribute, String... value) {
StringBuilder sb = new StringBuilder(path);
sb.append("?action=set-mutable-attribute&attribute-name=");
sb.append(attribute);
sb.append(sanitize(attribute));
for(String v : value) {
sb.append("&attribute-value=");
sb.append(sanitize(v));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.infinispan.commons.CacheException;
Expand Down Expand Up @@ -124,6 +125,10 @@ public void removeListener(AttributeListener<T> listener) {
}
}

public void removeListener(Predicate<AttributeListener<T>> filter) {
listeners.removeIf(filter);
}

public boolean isNull() {
return value == null;
}
Expand Down Expand Up @@ -220,7 +225,9 @@ public boolean matches(Attribute<?> other) {
if (!this.definition.equals(other.definition))
return false;
if (this.definition.isGlobal()) {
if (Matchable.class.isAssignableFrom(this.definition.getType())) {
if (this.definition.matcher() != null) {
return this.definition.matcher().matches(this, (Attribute<T>) other);
} else if (Matchable.class.isAssignableFrom(this.definition.getType())) {
return ((Matchable) value).matches(other.value);
} else {
return Objects.equals(value, other.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
import org.infinispan.commons.CacheConfigurationException;

/**
*
* AttributeDefinition. Defines the characteristics of a configuration attribute. It is used to
* construct an actual {@link Attribute} holder.
*
* <p>
* An attribute definition has the following characteristics:
* <ul>
* <li>A name</li>
Expand Down Expand Up @@ -41,6 +40,7 @@ public final class AttributeDefinition<T> {
private final int deprecatedMinor;
private final int sinceMajor;
private final int sinceMinor;
private final AttributeMatcher<T> matcher;

private AttributeDefinition(Builder<T> builder) {
this.name = builder.name;
Expand All @@ -50,6 +50,7 @@ private AttributeDefinition(Builder<T> builder) {
this.global = builder.global;
this.copier = builder.copier;
this.initializer = builder.initializer;
this.matcher = builder.matcher;
this.validator = builder.validator;
this.serializer = builder.serializer;
this.parser = builder.parser;
Expand Down Expand Up @@ -104,6 +105,10 @@ public AttributeInitializer<? extends T> initializer() {
return initializer;
}

public AttributeMatcher<T> matcher() {
return matcher;
}

AttributeValidator<? super T> validator() {
return validator;
}
Expand All @@ -117,7 +122,7 @@ public T parse(String value) {
}

public Attribute<T> toAttribute() {
return new Attribute<T>(this);
return new Attribute<>(this);
}

public void validate(T value) {
Expand Down Expand Up @@ -201,13 +206,13 @@ public static final class Builder<T> {
private AttributeValidator<? super T> validator;
private AttributeSerializer<? super T> serializer = AttributeSerializer.DEFAULT;
private AttributeParser<? super T> parser = AttributeParser.DEFAULT;
private AttributeMatcher<T> matcher;
private int deprecatedMajor = Integer.MAX_VALUE;
private int deprecatedMinor = Integer.MAX_VALUE;
// We started with Infinispan 4.0
private int sinceMajor = 4;
private int sinceMinor = 0;


private Builder(String name, T defaultValue, Class<T> type) {
this.name = name;
this.defaultValue = defaultValue;
Expand All @@ -229,6 +234,11 @@ public Builder<T> initializer(AttributeInitializer<? extends T> initializer) {
return this;
}

public Builder<T> matcher(AttributeMatcher<T> matcher) {
this.matcher = matcher;
return this;
}

public Builder<T> autoPersist(boolean autoPersist) {
this.autoPersist = autoPersist;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.infinispan.commons.configuration.attributes;

public interface AttributeMatcher<T> {
boolean matches(Attribute<T> o1, Attribute<T> o2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,8 @@ public boolean equals(Object obj) {
return false;
AttributeSet other = (AttributeSet) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
return true;
return other.attributes == null;
} else return attributes.equals(other.attributes);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ public AdvancedCache<K, V> withWrapping(Class<? extends Wrapper> keyWrapper, Cla
* No generics because some methods return {@code AdvancedCache<?, ?>},
* and returning the proper type would require erasure anyway.
*/
@SuppressWarnings("rawtypes")
public abstract AdvancedCache rewrap(AdvancedCache newDelegate);

@Override
Expand Down
26 changes: 26 additions & 0 deletions core/src/main/java/org/infinispan/cache/impl/AliasCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.infinispan.cache.impl;

import org.infinispan.AdvancedCache;

/**
* @since 15.0
**/
public class AliasCache<K, V> extends AbstractDelegatingAdvancedCache<K, V> {
private final String alias;

public AliasCache(AdvancedCache<K, V> cache, String alias) {
super(cache);
this.alias = alias;
}

@SuppressWarnings("rawtypes")
@Override
public AdvancedCache rewrap(AdvancedCache newDelegate) {
throw new UnsupportedOperationException("Alias caches should not delegate wrapping operations");
}

@Override
public String getName() {
return alias;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import static org.infinispan.util.logging.Log.CONFIG;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import org.infinispan.commons.configuration.Combine;
import org.infinispan.commons.configuration.attributes.Attribute;
import org.infinispan.commons.configuration.attributes.AttributeListener;
import org.infinispan.commons.util.GlobUtils;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
Expand All @@ -27,12 +29,14 @@
*/
public class ConfigurationManager {
private final GlobalConfiguration globalConfiguration;
private final ConcurrentMap<String, Configuration> namedConfiguration;
private final Map<String, Configuration> namedConfiguration;
private final Map<String, String> aliases;


public ConfigurationManager(GlobalConfiguration globalConfiguration) {
this.globalConfiguration = globalConfiguration;
this.namedConfiguration = new ConcurrentHashMap<>();
this.aliases = new ConcurrentHashMap<>();
}

public ConfigurationManager(ConfigurationBuilderHolder holder) {
Expand Down Expand Up @@ -89,7 +93,10 @@ private Configuration findConfiguration(String name) {
}

public Configuration putConfiguration(String cacheName, Configuration configuration) {
// This will fail if the names are already in use
addAliases(cacheName, configuration.aliases());
namedConfiguration.put(cacheName, configuration);
configuration.attributes().attribute(Configuration.ALIASES).addListener(new AliasListener(cacheName));
return configuration;
}

Expand All @@ -98,13 +105,17 @@ public Configuration putConfiguration(String cacheName, ConfigurationBuilder bui
}

public void removeConfiguration(String cacheName) {
namedConfiguration.remove(cacheName);
Configuration removed = namedConfiguration.remove(cacheName);
if (removed != null) {
removed.attributes().attribute(Configuration.ALIASES).removeListener(f -> f.getClass() == AliasListener.class);
removeAliases(removed.aliases());
}
}

public Collection<String> getDefinedCaches() {
return namedConfiguration.entrySet().stream()
.filter(entry -> !entry.getValue().isTemplate())
.map(Map.Entry::getKey).collect(Collectors.toUnmodifiableList());
.map(Map.Entry::getKey).toList();
}

public Collection<String> getDefinedConfigurations() {
Expand All @@ -119,4 +130,54 @@ public ConfigurationBuilderHolder toBuilderHolder() {
}
return holder;
}

private void addAliases(String cacheName, Collection<String> aliases) {
synchronized (this.aliases) {
for (String alias : aliases) {
// Ensure there are no cache name conflicts
if (this.namedConfiguration.containsKey(alias) || cacheName.equals(alias)) {
throw CONFIG.duplicateCacheName(alias);
}
// Ensure there are no alias name conflicts
if (this.aliases.containsKey(alias)) {
throw CONFIG.duplicateAliasName(alias, this.aliases.get(alias));
}
}
// Now we can register the aliases
for (String alias : aliases) {
this.aliases.put(alias, cacheName);
}
}
}

private void removeAliases(Collection<String> aliases) {
for (String alias : aliases) {
this.aliases.remove(alias);
}
}

public String selectCache(String cacheName) {
return aliases.getOrDefault(cacheName, cacheName);
}

class AliasListener implements AttributeListener<List<String>> {
private final String cacheName;

AliasListener(String cacheName) {
this.cacheName = cacheName;
}

public void attributeChanged(Attribute<List<String>> attribute, List<String> oldValues) {
synchronized (aliases) {
// Ensure that any new aliases aren't registered yet
List<String> newValues = new ArrayList<>(attribute.get());
newValues.removeAll(oldValues);
addAliases(cacheName, newValues);
// Now remove the ones that are no longer needed
List<String> removedValues = new ArrayList<>(oldValues);
removedValues.removeAll(attribute.get());
removeAliases(removedValues);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ protected AbstractConfigurationChildBuilder(ConfigurationBuilder builder) {
this.builder = builder;
}

@Override
public ConfigurationBuilder aliases(String... aliases) {
return builder.aliases(aliases);
}

@Override
public ConfigurationChildBuilder template(boolean template) {
return builder.template(template);
Expand Down

0 comments on commit 5269fb7

Please sign in to comment.