Skip to content
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
Expand Up @@ -63,6 +63,10 @@ public static DependencyNode getClassDependencyNode(Class<?> clazz) {
return REGISTRY.getClassDependencyNode(clazz);
}

public static DependencyNode getClassInstanceDependencyNode(Class<?> clazz) {
return REGISTRY.getClassInstanceDependencyNode(clazz);
}

public static DependencyNode getTagDependencyNode(String tag) {
return REGISTRY.getTagDependencyNode(tag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,20 @@ public final class CleanableRegister implements CacheCleaner {
private static final Logger logger = LoggerFactory.getLogger(CleanableRegister.class);

private final Map<Class<?>, ClassCleanableInstanceList<?>> classCleanMap = new THashMap<Class<?>, ClassCleanableInstanceList<?>>();
private final Map<Class<?>, DependencyNode> classMapping = new THashMap<Class<?>, DependencyNode>();
private final Map<String, DependencyNode> groupMapping = new THashMap<String, DependencyNode>();
private final Map<String, DependencyNode> tagMapping = new THashMap<String, DependencyNode>();

/**
* For each class there are two DependencyNodes: one for static methods and one for its instance methods.
*
* Instance method node depends on static node and on instance nodes of parent classes and interfaces.
*
* So it's enough to invalidate static node to invalidate all static caches of cache, instance caches of this
* class and all instance caches of its child classes too. This is what {@link #clearCacheByClass(Class)} does.
*/
private final Map<Class<?>, DependencyNode> classStaticNodes = new THashMap<Class<?>, DependencyNode>();
private final Map<Class<?>, DependencyNode> classInstanceNodes = new THashMap<Class<?>, DependencyNode>();

private final Map<String, DependencyNode> groupNodes = new THashMap<String, DependencyNode>();
private final Map<String, DependencyNode> tagNodes = new THashMap<String, DependencyNode>();

private static final Cleanable<?> EMPTY_CLEANABLE = new EmptyCleanable();

Expand Down Expand Up @@ -191,7 +202,7 @@ public void clearCacheByClass(Class<?> clazz) {

DependencyNode node;
synchronized (this) {
node = classMapping.get(clazz);
node = classStaticNodes.get(clazz);
}
if (node == null) {
logger.warn("There is no subclasses of " + clazz + " with caches yet");
Expand All @@ -204,7 +215,7 @@ public void clearCacheByClass(Class<?> clazz) {
public void clearCacheByGroup(String group) {
DependencyNode node;
synchronized (this) {
node = groupMapping.get(group);
node = groupNodes.get(group);
}
if (node == null) {
logger.warn("There is no caches of group <" + group + "> yet");
Expand All @@ -217,7 +228,7 @@ public void clearCacheByGroup(String group) {
public void clearCacheByTag(String tag) {
DependencyNode node;
synchronized (this) {
node = tagMapping.get(tag);
node = tagNodes.get(tag);
}
if (node == null) {
logger.warn("There is no caches with tag <" + tag + "> yet");
Expand All @@ -233,7 +244,7 @@ public void clearCacheByTag(String tag) {
public void clearCacheByAnnotation(Class<? extends Annotation> annotationClass) {
DependencyNode node;
synchronized (this) {
node = tagMapping.get("@" + annotationClass.getName());
node = tagNodes.get("@" + annotationClass.getName());
}
if (node == null) {
logger.warn("Can`t find cache for annotation " + annotationClass);
Expand All @@ -242,30 +253,55 @@ public void clearCacheByAnnotation(Class<? extends Annotation> annotationClass)
}
}

@Nullable
@Nonnull
public synchronized DependencyNode getClassDependencyNode(Class<?> clazz) {
DependencyNode tagNode = classMapping.get(clazz);
DependencyNode tagNode = classStaticNodes.get(clazz);
if (tagNode == null) {
tagNode = new EmptyDependencyNode("class:" + clazz.getName());
classMapping.put(clazz, tagNode);
classStaticNodes.put(clazz, tagNode);
}
return tagNode;
}

@Nonnull
public synchronized DependencyNode getClassInstanceDependencyNode(Class<?> clazz) {
DependencyNode tagNode = classInstanceNodes.get(clazz);
if (tagNode == null) {
tagNode = new EmptyDependencyNode("instance:" + clazz.getName());
trackParentAndInterfaceDependencies(clazz, tagNode);

classInstanceNodes.put(clazz, tagNode);
}
return tagNode;
}

private void trackParentAndInterfaceDependencies(Class<?> clazz, DependencyNode tagNode) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
getClassInstanceDependencyNode(superclass).trackDependency(tagNode);
}
for (Class<?> intf : clazz.getInterfaces()) {
getClassInstanceDependencyNode(intf).trackDependency(tagNode);
}
getClassDependencyNode(clazz).trackDependency(tagNode);
}

@Nonnull
public synchronized DependencyNode getTagDependencyNode(String tag) {
DependencyNode tagNode = tagMapping.get(tag);
DependencyNode tagNode = tagNodes.get(tag);
if (tagNode == null) {
tagNode = new EmptyDependencyNode("tag:" + tag);
tagMapping.put(tag, tagNode);
tagNodes.put(tag, tagNode);
}
return tagNode;
}

@Nonnull
public synchronized DependencyNode getGroupDependencyNode(String group) {
DependencyNode groupNode = groupMapping.get(group);
DependencyNode groupNode = groupNodes.get(group);
if (groupNode == null) {
groupNode = new EmptyDependencyNode("group:" + group);
groupMapping.put(group, groupNode);
groupNodes.put(group, groupNode);
}
return groupNode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.maxifier.mxcache.impl.resource.DependencyNode;
import com.maxifier.mxcache.impl.resource.DependencyTracker;
import com.maxifier.mxcache.caches.Cache;
import gnu.trove.set.hash.THashSet;

import javax.annotation.Nullable;

Expand Down Expand Up @@ -104,27 +103,15 @@ private static DependencyNode[] getExplicitDependencies(CacheDescriptor descript
res.add(CacheFactory.getGroupDependencyNode(group));
}
if (descriptor.isStatic()) {
// static cache is not invalidated when a superclass of declaring class is invalidated
// static cache is not invalidated when a superclass of declaring class is invalidated,
// so we put it to a separate node
res.add(CacheFactory.getClassDependencyNode(ownerClass));
} else {
Set<Class<?>> visitedClasses = new THashSet<Class<?>>();
addAllSuperClassesAndInterfaces(res, visitedClasses, ownerClass);
res.add(CacheFactory.getClassInstanceDependencyNode(ownerClass));
}
return res.isEmpty() ? null : res.toArray(new DependencyNode[res.size()]);
}

private static void addAllSuperClassesAndInterfaces(List<DependencyNode> res, Set<Class<?>> visitedClasses, Class<?> clazz) {
while (clazz != null && clazz != Object.class) {
if (visitedClasses.add(clazz)) {
res.add(CacheFactory.getClassDependencyNode(clazz));
for (Class<?> intf : clazz.getInterfaces()) {
addAllSuperClassesAndInterfaces(res, visitedClasses, intf);
}
}
clazz = clazz.getSuperclass();
}
}

protected StatisticsModeEnum getStatisticsMode() {
return statisticsMode;
}
Expand Down