-
Notifications
You must be signed in to change notification settings - Fork 218
eventing refinements mentioned on #2012 #2034
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,17 @@ | ||
package io.javaoperatorsdk.operator.processing.event.source.informer; | ||
|
||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import io.fabric8.kubernetes.api.model.HasMetadata; | ||
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; | ||
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; | ||
import io.javaoperatorsdk.operator.processing.event.ResourceID; | ||
|
||
|
@@ -33,16 +37,33 @@ | |
public class TemporaryResourceCache<T extends HasMetadata> { | ||
|
||
private static final Logger log = LoggerFactory.getLogger(TemporaryResourceCache.class); | ||
private static final int MAX_RESOURCE_VERSIONS = 256; | ||
|
||
private final Map<ResourceID, T> cache = new ConcurrentHashMap<>(); | ||
private final ManagedInformerEventSource<T, ?, ?> managedInformerEventSource; | ||
private final boolean parseResourceVersions; | ||
private final Set<String> knownResourceVersions; | ||
|
||
public TemporaryResourceCache(ManagedInformerEventSource<T, ?, ?> managedInformerEventSource) { | ||
public TemporaryResourceCache(ManagedInformerEventSource<T, ?, ?> managedInformerEventSource, | ||
boolean parseResourceVersions) { | ||
this.managedInformerEventSource = managedInformerEventSource; | ||
this.parseResourceVersions = parseResourceVersions; | ||
if (parseResourceVersions) { | ||
knownResourceVersions = Collections.newSetFromMap(new LinkedHashMap<String, Boolean>() { | ||
@Override | ||
protected boolean removeEldestEntry(java.util.Map.Entry<String, Boolean> eldest) { | ||
return size() >= MAX_RESOURCE_VERSIONS; | ||
} | ||
}); | ||
} else { | ||
knownResourceVersions = null; | ||
} | ||
} | ||
|
||
public synchronized Optional<T> removeResourceFromCache(T resource) { | ||
return Optional.ofNullable(cache.remove(ResourceID.fromResource(resource))); | ||
public synchronized void onEvent(T resource, boolean unknownState) { | ||
cache.computeIfPresent(ResourceID.fromResource(resource), | ||
(id, cached) -> (unknownState || !isLaterResourceVersion(id, cached, resource)) ? null | ||
: cached); | ||
} | ||
|
||
public synchronized void putAddedResource(T newResource) { | ||
|
@@ -56,23 +77,50 @@ public synchronized void putAddedResource(T newResource) { | |
* @param previousResourceVersion null indicates an add | ||
*/ | ||
public synchronized void putResource(T newResource, String previousResourceVersion) { | ||
if (knownResourceVersions != null) { | ||
knownResourceVersions.add(newResource.getMetadata().getResourceVersion()); | ||
} | ||
var resourceId = ResourceID.fromResource(newResource); | ||
var cachedResource = getResourceFromCache(resourceId) | ||
.orElse(managedInformerEventSource.get(resourceId).orElse(null)); | ||
|
||
if ((previousResourceVersion == null && cachedResource == null) | ||
|| (cachedResource != null && previousResourceVersion != null | ||
&& cachedResource.getMetadata().getResourceVersion() | ||
.equals(previousResourceVersion))) { | ||
|| (cachedResource != null | ||
&& (cachedResource.getMetadata().getResourceVersion().equals(previousResourceVersion)) | ||
|| isLaterResourceVersion(resourceId, newResource, cachedResource))) { | ||
log.debug( | ||
"Temporarily moving ahead to target version {} for resource id: {}", | ||
newResource.getMetadata().getResourceVersion(), resourceId); | ||
putToCache(newResource, resourceId); | ||
} else { | ||
if (cache.remove(resourceId) != null) { | ||
log.debug("Removed an obsolete resource from cache for id: {}", resourceId); | ||
} else if (cache.remove(resourceId) != null) { | ||
log.debug("Removed an obsolete resource from cache for id: {}", resourceId); | ||
} | ||
} | ||
|
||
public boolean isKnownResourceVersion(T resource) { | ||
return knownResourceVersions != null | ||
&& knownResourceVersions.contains(resource.getMetadata().getResourceVersion()); | ||
} | ||
|
||
/** | ||
* @return true if {@link InformerConfiguration#parseResourceVersions()} is enabled and the | ||
* resourceVersion of newResource is numerically greater than cachedResource, otherwise | ||
* false | ||
*/ | ||
private boolean isLaterResourceVersion(ResourceID resourceId, T newResource, T cachedResource) { | ||
try { | ||
if (parseResourceVersions | ||
&& Long.parseLong(newResource.getMetadata().getResourceVersion()) > Long | ||
.parseLong(cachedResource.getMetadata().getResourceVersion())) { | ||
return true; | ||
} | ||
} catch (NumberFormatException e) { | ||
log.debug( | ||
"Could not compare resourceVersions {} and {} for {}", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't be this a warning? even if it could pollute cache? (no strong opinion) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It won't pollute the cache, it would exhibit the same behavior as it does now. It can of course be at whatever level you want. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean pollute logs :) |
||
newResource.getMetadata().getResourceVersion(), | ||
cachedResource.getMetadata().getResourceVersion(), resourceId); | ||
} | ||
return false; | ||
} | ||
|
||
private void putToCache(T resource, ResourceID resourceID) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a more concrete example of when setting this to
true
would help. As is, it's not obvious when people might want to use this and I would rather not expose this at all if this isn't sufficiently / broadly applicable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's basically for feature parity with the mutable cache that is in go client - I'm not aware of user request for the feature, so if you feel strongly about it, then it could be hidden or removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metacosm @csviri what do you think - would it be better to pull out or hide the resourceVersion parsing logic?