Skip to content

Commit 527a090

Browse files
committed
feat: cache desired state
Signed-off-by: Chris Laprun <claprun@redhat.com>
1 parent 470ac9e commit 527a090

File tree

4 files changed

+59
-44
lines changed

4 files changed

+59
-44
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public abstract class AbstractDependentResource<R, P extends HasMetadata>
3333
private final boolean updatable = this instanceof Updater;
3434
private final boolean deletable = this instanceof Deleter;
3535
private final DependentResourceReconciler<R, P> dependentResourceReconciler;
36+
private final ThreadLocal<R> desiredCache = new ThreadLocal<>();
3637
protected Creator<R, P> creator;
3738
protected Updater<R, P> updater;
3839
protected String name;
@@ -67,52 +68,56 @@ public ReconcileResult<R> reconcile(P primary, Context<P> context) {
6768
}
6869

6970
protected ReconcileResult<R> reconcile(P primary, R actualResource, Context<P> context) {
70-
if (creatable() || updatable()) {
71-
if (actualResource == null) {
72-
if (creatable) {
73-
var desired = desired(primary, context);
74-
throwIfNull(desired, primary, "Desired");
75-
logForOperation("Creating", primary, desired);
76-
var createdResource = handleCreate(desired, primary, context);
77-
return ReconcileResult.resourceCreated(createdResource);
78-
}
79-
} else {
80-
if (updatable()) {
81-
final Matcher.Result<R> match = match(actualResource, primary, context);
82-
if (!match.matched()) {
83-
final var desired = match.computedDesired().orElseGet(() -> desired(primary, context));
84-
throwIfNull(desired, primary, "Desired");
85-
logForOperation("Updating", primary, desired);
86-
var updatedResource = handleUpdate(actualResource, desired, primary, context);
87-
return ReconcileResult.resourceUpdated(updatedResource);
71+
try {
72+
if (creatable() || updatable()) {
73+
if (actualResource == null) {
74+
if (creatable) {
75+
var desired = cachedDesired(primary, context);
76+
throwIfNull(desired, primary, "Desired");
77+
logForOperation("Creating", primary, desired);
78+
var createdResource = handleCreate(desired, primary, context);
79+
return ReconcileResult.resourceCreated(createdResource);
80+
}
81+
} else {
82+
if (updatable()) {
83+
final Result<R> match = match(actualResource, primary, context);
84+
if (!match.matched()) {
85+
final var desired =
86+
match.computedDesired().orElseGet(() -> cachedDesired(primary, context));
87+
throwIfNull(desired, primary, "Desired");
88+
logForOperation("Updating", primary, desired);
89+
var updatedResource = handleUpdate(actualResource, desired, primary, context);
90+
return ReconcileResult.resourceUpdated(updatedResource);
91+
} else {
92+
log.debug(
93+
"Update skipped for dependent {} as it matched the existing one",
94+
actualResource instanceof HasMetadata
95+
? ResourceID.fromResource((HasMetadata) actualResource)
96+
: getClass().getSimpleName());
97+
}
98+
} else {
99+
log.debug(
100+
"Update skipped for dependent {} implement Updater interface to modify it",
101+
actualResource instanceof HasMetadata
102+
? ResourceID.fromResource((HasMetadata) actualResource)
103+
: getClass().getSimpleName());
104+
}
105+
}
88106
} else {
89107
log.debug(
90-
"Update skipped for dependent {} as it matched the existing one",
91-
actualResource instanceof HasMetadata
92-
? ResourceID.fromResource((HasMetadata) actualResource)
93-
: getClass().getSimpleName());
108+
"Dependent {} is read-only, implement Creator and/or Updater interfaces to modify it",
109+
getClass().getSimpleName());
94110
}
95-
} else {
96-
log.debug(
97-
"Update skipped for dependent {} implement Updater interface to modify it",
98-
actualResource instanceof HasMetadata
99-
? ResourceID.fromResource((HasMetadata) actualResource)
100-
: getClass().getSimpleName());
101-
}
111+
return ReconcileResult.noOperation(actualResource);
112+
} finally {
113+
desiredCache.remove();
102114
}
103-
} else {
104-
log.debug(
105-
"Dependent {} is read-only, implement Creator and/or Updater interfaces to modify it",
106-
getClass().getSimpleName());
107-
}
108-
return ReconcileResult.noOperation(actualResource);
109115
}
110116

111117
public abstract Result<R> match(R resource, P primary, Context<P> context);
112118

113119
@Override
114120
public Optional<R> getSecondaryResource(P primary, Context<P> context) {
115-
116121
var secondaryResources = context.getSecondaryResources(resourceType());
117122
if (secondaryResources.isEmpty()) {
118123
return Optional.empty();
@@ -136,7 +141,7 @@ public Optional<R> getSecondaryResource(P primary, Context<P> context) {
136141
*/
137142
protected Optional<R> selectTargetSecondaryResource(
138143
Set<R> secondaryResources, P primary, Context<P> context) {
139-
R desired = desired(primary, context);
144+
R desired = cachedDesired(primary, context);
140145
var targetResources = secondaryResources.stream().filter(r -> r.equals(desired)).toList();
141146
if (targetResources.size() > 1) {
142147
throw new IllegalStateException(
@@ -199,6 +204,16 @@ protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
199204
return updated;
200205
}
201206

207+
protected R cachedDesired(P primary, Context<P> context) {
208+
var desired = desiredCache.get();
209+
if (desired != null) {
210+
return desired;
211+
}
212+
desired = desired(primary, context);
213+
desiredCache.set(desired);
214+
return desired;
215+
}
216+
202217
protected R desired(P primary, Context<P> context) {
203218
throw new IllegalStateException(
204219
"desired method must be implemented if this DependentResource can be created and/or"

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ protected void handleExplicitStateCreation(P primary, R created, Context<P> cont
8383

8484
@Override
8585
public Matcher.Result<R> match(R resource, P primary, Context<P> context) {
86-
var desired = desired(primary, context);
86+
var desired = cachedDesired(primary, context);
8787
return Matcher.Result.computed(resource.equals(desired), desired);
8888
}
8989

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> m
123123
Context<P> context,
124124
boolean labelsAndAnnotationsEquality,
125125
String... ignorePaths) {
126-
final var desired = dependentResource.desired(primary, context);
126+
final var desired = dependentResource.cachedDesired(primary, context);
127127
return match(desired, actualResource, labelsAndAnnotationsEquality, context, ignorePaths);
128128
}
129129

@@ -135,7 +135,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> m
135135
boolean specEquality,
136136
boolean labelsAndAnnotationsEquality,
137137
String... ignorePaths) {
138-
final var desired = dependentResource.desired(primary, context);
138+
final var desired = dependentResource.cachedDesired(primary, context);
139139
return match(
140140
desired, actualResource, labelsAndAnnotationsEquality, specEquality, context, ignorePaths);
141141
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public R update(R actual, R desired, P primary, Context<P> context) {
107107

108108
@Override
109109
public Result<R> match(R actualResource, P primary, Context<P> context) {
110-
final var desired = desired(primary, context);
110+
final var desired = cachedDesired(primary, context);
111111
return match(actualResource, desired, primary, context);
112112
}
113113

@@ -286,16 +286,16 @@ protected Optional<R> selectTargetSecondaryResource(
286286
* @return id of the target managed resource
287287
*/
288288
protected ResourceID targetSecondaryResourceID(P primary, Context<P> context) {
289-
return ResourceID.fromResource(desired(primary, context));
289+
return ResourceID.fromResource(cachedDesired(primary, context));
290290
}
291291

292292
protected boolean addOwnerReference() {
293293
return garbageCollected;
294294
}
295295

296296
@Override
297-
protected R desired(P primary, Context<P> context) {
298-
return super.desired(primary, context);
297+
protected R cachedDesired(P primary, Context<P> context) {
298+
return super.cachedDesired(primary, context);
299299
}
300300

301301
@Override

0 commit comments

Comments
 (0)