Skip to content

Commit 75eec9c

Browse files
authored
fix: remove cache pruning (#1694)
1 parent 08e0c78 commit 75eec9c

File tree

22 files changed

+42
-428
lines changed

22 files changed

+42
-428
lines changed

docs/documentation/features.md

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -711,30 +711,6 @@ setting, where this flag usually needs to be set to false, in order to control t
711711
See also an example implementation in the
712712
[WebPage sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/3e2e7c4c834ef1c409d636156b988125744ca911/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java#L38-L43)
713713

714-
## Optimization of Caches
715-
716-
** Cache pruning is an experimental feature. Might a subject of change or even removal in the future. **
717-
718-
Operators using informers will initially cache the data for all known resources when starting up
719-
so that access to resources can be performed quickly. Consequently, the memory required for the
720-
operator to run and startup time will both increase quite dramatically when dealing with large
721-
clusters with numerous resources.
722-
723-
It is thus possible to configure the operator to cache only pruned versions of the resources to
724-
alleviate the memory usage of the primary and secondary caches. This setup, however, has
725-
implications on how reconcilers deal with resources since they will only work with partial
726-
objects. As a consequence, resources need to be updated using PATCH operations only, sending
727-
only required changes.
728-
729-
To see how to use, and how to handle related caveats regarding how to deal with pruned objects
730-
that leverage
731-
[server side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) patches,
732-
please check the provided
733-
[integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/c688524e64205690ba15587e7ed96a64dc231430/operator-framework/src/test/java/io/javaoperatorsdk/operator/CachePruneIT.java)
734-
and associates reconciler.
735-
736-
Pruned caches are currently not supported with the Dependent Resources feature.
737-
738714
## Automatic Generation of CRDs
739715

740716
Note that this feature is provided by the

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Set;
88
import java.util.concurrent.TimeUnit;
99
import java.util.function.Function;
10-
import java.util.function.UnaryOperator;
1110
import java.util.stream.Collectors;
1211

1312
import org.slf4j.Logger;
@@ -144,8 +143,6 @@ protected <P extends HasMetadata> ControllerConfiguration<P> configFor(Reconcile
144143
Utils.contextFor(name, null, null)),
145144
Utils.instantiate(annotation.genericFilter(), GenericFilter.class,
146145
Utils.contextFor(name, null, null)),
147-
Utils.instantiate(annotation.cachePruneFunction(), UnaryOperator.class,
148-
Utils.contextFor(name, null, null)),
149146
Set.of(valueOrDefault(annotation,
150147
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::namespaces,
151148
DEFAULT_NAMESPACES_SET.toArray(String[]::new))),

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.util.List;
77
import java.util.Map;
88
import java.util.Set;
9-
import java.util.function.UnaryOperator;
109

1110
import io.fabric8.kubernetes.api.model.HasMetadata;
1211
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
@@ -36,7 +35,6 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
3635
private OnUpdateFilter<R> onUpdateFilter;
3736
private GenericFilter<R> genericFilter;
3837
private RateLimiter rateLimiter;
39-
private UnaryOperator<R> cachePruneFunction;
4038
private Map<DependentResourceSpec, Object> configurations;
4139

4240
private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
@@ -52,7 +50,6 @@ private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
5250
this.genericFilter = original.genericFilter().orElse(null);
5351
this.original = original;
5452
this.rateLimiter = original.getRateLimiter();
55-
this.cachePruneFunction = original.cachePruneFunction().orElse(null);
5653
}
5754

5855
public ControllerConfigurationOverrider<R> withFinalizer(String finalizer) {
@@ -155,12 +152,6 @@ public ControllerConfigurationOverrider<R> withGenericFilter(GenericFilter<R> ge
155152
return this;
156153
}
157154

158-
public ControllerConfigurationOverrider<R> withCachePruneFunction(
159-
UnaryOperator<R> cachePruneFunction) {
160-
this.cachePruneFunction = cachePruneFunction;
161-
return this;
162-
}
163-
164155
public ControllerConfigurationOverrider<R> replacingNamedDependentResourceConfig(String name,
165156
Object dependentResourceConfig) {
166157

@@ -182,7 +173,7 @@ public ControllerConfiguration<R> build() {
182173
final var overridden = new ResolvedControllerConfiguration<>(
183174
original.getResourceClass(), original.getName(),
184175
generationAware, original.getAssociatedReconcilerClassName(), retry, rateLimiter,
185-
reconciliationMaxInterval, onAddFilter, onUpdateFilter, genericFilter, cachePruneFunction,
176+
reconciliationMaxInterval, onAddFilter, onUpdateFilter, genericFilter,
186177
original.getDependentResources(),
187178
namespaces, finalizer, labelSelector, configurations);
188179
overridden.setEventFilter(customResourcePredicate);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.util.Optional;
44
import java.util.Set;
5-
import java.util.function.UnaryOperator;
65

76
import io.fabric8.kubernetes.api.model.HasMetadata;
87
import io.javaoperatorsdk.operator.ReconcilerUtils;
@@ -20,12 +19,10 @@ public class DefaultResourceConfiguration<R extends HasMetadata>
2019
private final GenericFilter<R> genericFilter;
2120
private final String labelSelector;
2221
private final Set<String> namespaces;
23-
private final UnaryOperator<R> cachePruneFunction;
2422

2523
protected DefaultResourceConfiguration(Class<R> resourceClass,
2624
Set<String> namespaces, String labelSelector, OnAddFilter<R> onAddFilter,
27-
OnUpdateFilter<R> onUpdateFilter, GenericFilter<R> genericFilter,
28-
UnaryOperator<R> cachePruneFunction) {
25+
OnUpdateFilter<R> onUpdateFilter, GenericFilter<R> genericFilter) {
2926
this.resourceClass = resourceClass;
3027
this.resourceTypeName = ReconcilerUtils.getResourceTypeName(resourceClass);
3128
this.onAddFilter = onAddFilter;
@@ -34,7 +31,6 @@ protected DefaultResourceConfiguration(Class<R> resourceClass,
3431

3532
this.namespaces = ResourceConfiguration.ensureValidNamespaces(namespaces);
3633
this.labelSelector = ResourceConfiguration.ensureValidLabelSelector(labelSelector);
37-
this.cachePruneFunction = cachePruneFunction;
3834
}
3935

4036
@Override
@@ -52,11 +48,6 @@ public Set<String> getNamespaces() {
5248
return namespaces;
5349
}
5450

55-
@Override
56-
public Optional<UnaryOperator<R>> cachePruneFunction() {
57-
return Optional.ofNullable(this.cachePruneFunction);
58-
}
59-
6051
@Override
6152
public Class<R> getResourceClass() {
6253
return resourceClass;

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResolvedControllerConfiguration.java

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
package io.javaoperatorsdk.operator.api.config;
22

33
import java.time.Duration;
4-
import java.util.Collections;
5-
import java.util.List;
6-
import java.util.Map;
7-
import java.util.Optional;
8-
import java.util.Set;
4+
import java.util.*;
95
import java.util.concurrent.TimeUnit;
10-
import java.util.function.UnaryOperator;
116

127
import io.fabric8.kubernetes.api.model.HasMetadata;
138
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationProvider;
@@ -43,7 +38,7 @@ public ResolvedControllerConfiguration(Class<P> resourceClass, ControllerConfigu
4338
other.getAssociatedReconcilerClassName(), other.getRetry(), other.getRateLimiter(),
4439
other.maxReconciliationInterval().orElse(null),
4540
other.onAddFilter().orElse(null), other.onUpdateFilter().orElse(null),
46-
other.genericFilter().orElse(null), other.cachePruneFunction().orElse(null),
41+
other.genericFilter().orElse(null),
4742
other.getDependentResources(), other.getNamespaces(),
4843
other.getFinalizerName(), other.getLabelSelector(), Collections.emptyMap());
4944
}
@@ -69,12 +64,12 @@ public ResolvedControllerConfiguration(Class<P> resourceClass, String name,
6964
boolean generationAware, String associatedReconcilerClassName, Retry retry,
7065
RateLimiter rateLimiter, Duration maxReconciliationInterval,
7166
OnAddFilter<P> onAddFilter, OnUpdateFilter<P> onUpdateFilter,
72-
GenericFilter<P> genericFilter, UnaryOperator<P> cachePruneFunction,
67+
GenericFilter<P> genericFilter,
7368
List<DependentResourceSpec> dependentResources,
7469
Set<String> namespaces, String finalizer, String labelSelector,
7570
Map<DependentResourceSpec, Object> configurations) {
7671
this(resourceClass, name, generationAware, associatedReconcilerClassName, retry, rateLimiter,
77-
maxReconciliationInterval, onAddFilter, onUpdateFilter, genericFilter, cachePruneFunction,
72+
maxReconciliationInterval, onAddFilter, onUpdateFilter, genericFilter,
7873
namespaces, finalizer, labelSelector, configurations);
7974
setDependentResources(dependentResources);
8075
}
@@ -83,11 +78,9 @@ protected ResolvedControllerConfiguration(Class<P> resourceClass, String name,
8378
boolean generationAware, String associatedReconcilerClassName, Retry retry,
8479
RateLimiter rateLimiter, Duration maxReconciliationInterval,
8580
OnAddFilter<P> onAddFilter, OnUpdateFilter<P> onUpdateFilter, GenericFilter<P> genericFilter,
86-
UnaryOperator<P> cachePruneFunction,
8781
Set<String> namespaces, String finalizer, String labelSelector,
8882
Map<DependentResourceSpec, Object> configurations) {
89-
super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter,
90-
cachePruneFunction);
83+
super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter);
9184
this.name = ControllerConfiguration.ensureValidName(name, associatedReconcilerClassName);
9285
this.generationAware = generationAware;
9386
this.associatedReconcilerClassName = associatedReconcilerClassName;

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ResourceConfiguration.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44
import java.util.Collections;
55
import java.util.Optional;
66
import java.util.Set;
7-
import java.util.function.UnaryOperator;
87

98
import io.fabric8.kubernetes.api.model.HasMetadata;
109
import io.javaoperatorsdk.operator.OperatorException;
1110
import io.javaoperatorsdk.operator.ReconcilerUtils;
1211
import io.javaoperatorsdk.operator.api.reconciler.Constants;
13-
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
1412
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
1513
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
1614
import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
@@ -124,11 +122,4 @@ default Set<String> getEffectiveNamespaces() {
124122
}
125123
return targetNamespaces;
126124
}
127-
128-
/**
129-
* See {@link ControllerConfiguration#cachePruneFunction()} for details.
130-
*/
131-
default Optional<UnaryOperator<R>> cachePruneFunction() {
132-
return Optional.empty();
133-
}
134125
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.util.Objects;
44
import java.util.Optional;
55
import java.util.Set;
6-
import java.util.function.UnaryOperator;
76

87
import io.fabric8.kubernetes.api.model.HasMetadata;
98
import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration;
@@ -39,10 +38,8 @@ protected DefaultInformerConfiguration(String labelSelector,
3938
OnAddFilter<R> onAddFilter,
4039
OnUpdateFilter<R> onUpdateFilter,
4140
OnDeleteFilter<R> onDeleteFilter,
42-
GenericFilter<R> genericFilter,
43-
UnaryOperator<R> cachePruneFunction) {
44-
super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter,
45-
cachePruneFunction);
41+
GenericFilter<R> genericFilter) {
42+
super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter);
4643
this.followControllerNamespaceChanges = followControllerNamespaceChanges;
4744

4845
this.primaryToSecondaryMapper = primaryToSecondaryMapper;
@@ -106,7 +103,6 @@ class InformerConfigurationBuilder<R extends HasMetadata> {
106103
private OnDeleteFilter<R> onDeleteFilter;
107104
private GenericFilter<R> genericFilter;
108105
private boolean inheritControllerNamespacesOnChange = false;
109-
private UnaryOperator<R> cachePruneFunction;
110106

111107
private InformerConfigurationBuilder(Class<R> resourceClass) {
112108
this.resourceClass = resourceClass;
@@ -207,18 +203,12 @@ public InformerConfigurationBuilder<R> withGenericFilter(GenericFilter<R> generi
207203
return this;
208204
}
209205

210-
public InformerConfigurationBuilder<R> withCachePruneFunction(
211-
UnaryOperator<R> cachePruneFunction) {
212-
this.cachePruneFunction = cachePruneFunction;
213-
return this;
214-
}
215-
216206
public InformerConfiguration<R> build() {
217207
return new DefaultInformerConfiguration<>(labelSelector, resourceClass,
218208
primaryToSecondaryMapper,
219209
secondaryToPrimaryMapper,
220210
namespaces, inheritControllerNamespacesOnChange, onAddFilter, onUpdateFilter,
221-
onDeleteFilter, genericFilter, cachePruneFunction);
211+
onDeleteFilter, genericFilter);
222212
}
223213
}
224214

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import java.lang.annotation.Retention;
66
import java.lang.annotation.RetentionPolicy;
77
import java.lang.annotation.Target;
8-
import java.util.function.UnaryOperator;
98

109
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
1110
import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
@@ -119,25 +118,4 @@ MaxReconciliationInterval maxReconciliationInterval() default @MaxReconciliation
119118
* accessible no-arg constructor.
120119
*/
121120
Class<? extends RateLimiter> rateLimiter() default LinearRateLimiter.class;
122-
123-
/**
124-
* <p>
125-
* <b>This is an experimental feature, might be a subject of change and even removal in the
126-
* future.</b>
127-
* </p>
128-
* <p>
129-
* In order to optimize cache, thus set null on some attributes, this function can be set. Note
130-
* that this has subtle implications how updates on the resources should be handled. Notably only
131-
* patching of the resource can be used from that point, since update would remove not cached
132-
* parts of the resource.
133-
* </p>
134-
* <p>
135-
* Note that this feature does not work with Dependent Resources.
136-
* </p>
137-
*
138-
*
139-
*
140-
* @return function to remove parts of the resource.
141-
*/
142-
Class<? extends UnaryOperator> cachePruneFunction() default UnaryOperator.class;
143121
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
import io.fabric8.kubernetes.client.KubernetesClientException;
1313
import io.fabric8.kubernetes.client.dsl.MixedOperation;
1414
import io.fabric8.kubernetes.client.dsl.Resource;
15-
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
16-
import io.fabric8.kubernetes.client.dsl.base.PatchType;
1715
import io.javaoperatorsdk.operator.OperatorException;
1816
import io.javaoperatorsdk.operator.api.ObservedGenerationAware;
1917
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
@@ -36,7 +34,7 @@
3634
*/
3735
class ReconciliationDispatcher<P extends HasMetadata> {
3836

39-
public static final int MAX_FINALIZER_REMOVAL_RETRY = 10;
37+
public static final int MAX_UPDATE_RETRY = 10;
4038

4139
private static final Logger log = LoggerFactory.getLogger(ReconciliationDispatcher.class);
4240

@@ -295,8 +293,7 @@ private PostExecutionControl<P> handleCleanup(P originalResource, P resource,
295293
// cleanup is finished, nothing left to done
296294
final var finalizerName = configuration().getFinalizerName();
297295
if (deleteControl.isRemoveFinalizer() && resource.hasFinalizer(finalizerName)) {
298-
P customResource = conflictRetryingPatch(resource, originalResource,
299-
r -> r.removeFinalizer(finalizerName));
296+
P customResource = conflictRetryingUpdate(resource, r -> r.removeFinalizer(finalizerName));
300297
return PostExecutionControl.customResourceFinalizerRemoved(customResource);
301298
}
302299
}
@@ -315,8 +312,7 @@ private P updateCustomResourceWithFinalizer(P resourceForExecution, P originalRe
315312
log.debug(
316313
"Adding finalizer for resource: {} version: {}", getUID(originalResource),
317314
getVersion(originalResource));
318-
319-
return conflictRetryingPatch(resourceForExecution, originalResource,
315+
return conflictRetryingUpdate(resourceForExecution,
320316
r -> r.addFinalizer(configuration().getFinalizerName()));
321317
}
322318

@@ -330,8 +326,7 @@ ControllerConfiguration<P> configuration() {
330326
return controller.getConfiguration();
331327
}
332328

333-
public P conflictRetryingPatch(P resource, P originalResource,
334-
Function<P, Boolean> modificationFunction) {
329+
public P conflictRetryingUpdate(P resource, Function<P, Boolean> modificationFunction) {
335330
if (log.isDebugEnabled()) {
336331
log.debug("Removing finalizer on resource: {}", ResourceID.fromResource(resource));
337332
}
@@ -342,17 +337,17 @@ public P conflictRetryingPatch(P resource, P originalResource,
342337
if (Boolean.FALSE.equals(modified)) {
343338
return resource;
344339
}
345-
return customResourceFacade.serverSideApplyLockResource(resource, originalResource);
340+
return customResourceFacade.updateResource(resource);
346341
} catch (KubernetesClientException e) {
347342
log.trace("Exception during patch for resource: {}", resource);
348343
retryIndex++;
349344
// only retry on conflict (HTTP 409), otherwise fail
350345
if (e.getCode() != 409) {
351346
throw e;
352347
}
353-
if (retryIndex >= MAX_FINALIZER_REMOVAL_RETRY) {
348+
if (retryIndex >= MAX_UPDATE_RETRY) {
354349
throw new OperatorException(
355-
"Exceeded maximum (" + MAX_FINALIZER_REMOVAL_RETRY
350+
"Exceeded maximum (" + MAX_UPDATE_RETRY
356351
+ ") retry attempts to patch resource: "
357352
+ ResourceID.fromResource(resource));
358353
}
@@ -380,13 +375,6 @@ public R getResource(String namespace, String name) {
380375
}
381376
}
382377

383-
public R serverSideApplyLockResource(R resource, R originalResource) {
384-
var patchContext = PatchContext.of(PatchType.SERVER_SIDE_APPLY);
385-
patchContext.setForce(true);
386-
return resource(originalResource).patch(patchContext,
387-
resource);
388-
}
389-
390378
public R updateResource(R resource) {
391379
log.debug(
392380
"Trying to replace resource {}, version: {}",

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ private InformerWrapper<T> createEventSource(
113113
FilterWatchListDeletable<T, KubernetesResourceList<T>, Resource<T>> filteredBySelectorClient,
114114
ResourceEventHandler<T> eventHandler, String namespaceIdentifier) {
115115
var informer = filteredBySelectorClient.runnableInformer(0);
116-
configuration.cachePruneFunction()
117-
.ifPresent(f -> informer.itemStore(new TransformingItemStore<>(f)));
118116
var source =
119117
new InformerWrapper<>(informer, namespaceIdentifier);
120118
source.addEventHandler(eventHandler);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ public abstract class ManagedInformerEventSource<R extends HasMetadata, P extend
4343
protected ManagedInformerEventSource(
4444
MixedOperation<R, KubernetesResourceList<R>, Resource<R>> client, C configuration) {
4545
super(configuration.getResourceClass());
46-
temporaryResourceCache = new TemporaryResourceCache<>(this,
47-
configuration.cachePruneFunction().orElse(null));
46+
temporaryResourceCache = new TemporaryResourceCache<>(this);
4847
manager().initSources(client, configuration, this);
4948
this.configuration = configuration;
5049
}

0 commit comments

Comments
 (0)