Skip to content

Commit b0855d9

Browse files
committed
wip
Signed-off-by: csviri <a_meszaros@apple.com>
1 parent 59b38b5 commit b0855d9

6 files changed

Lines changed: 41 additions & 14 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private <R> Void stopEventSource(EventSource<R, P> eventSource) {
148148
return null;
149149
}
150150

151-
@SuppressWarnings("rawtypes")
151+
@SuppressWarnings({"rawtypes", "unchecked"})
152152
public final synchronized <R> void registerEventSource(EventSource<R, P> eventSource)
153153
throws OperatorException {
154154
Objects.requireNonNull(eventSource, "EventSource must not be null");

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@ private void initSources() {
9999
final var targetNamespaces =
100100
configuration.getInformerConfig().getEffectiveNamespaces(controllerConfiguration);
101101
if (InformerConfiguration.allNamespacesWatched(targetNamespaces)) {
102-
var source = createEventSourceForNamespace(WATCH_ALL_NAMESPACES);
102+
var source = getAndStartEventSourceForNamespace(WATCH_ALL_NAMESPACES);
103103
log.debug("Registered {} -> {} for any namespace", this, source);
104104
} else {
105105
targetNamespaces.forEach(
106106
ns -> {
107107
// todo should we start parallel
108-
final var source = createEventSourceForNamespace(ns);
108+
final var source = getAndStartEventSourceForNamespace(ns);
109109

110110
log.debug("Registered {} -> {} for namespace: {}", this, source, ns);
111111
});
@@ -139,18 +139,20 @@ public void changeNamespaces(Set<String> namespaces) {
139139
.boundedExecuteAndWaitForAllToComplete(
140140
newNamespaces.stream(),
141141
ns -> {
142-
final var source = createEventSourceForNamespace(ns);
142+
final var source = getAndStartEventSourceForNamespace(ns);
143143
log.debug("Registered new {} -> {} for namespace: {}", this, source, ns);
144144
return null;
145145
},
146146
ns -> "InformerStarter-" + ns + "-" + configuration.getResourceClass().getSimpleName());
147147
}
148148

149-
private InformerWrapper<R> createEventSourceForNamespace(String namespaceIdentifier) {
149+
private InformerWrapper<R> getAndStartEventSourceForNamespace(String namespaceIdentifier) {
150150
final InformerWrapper<R> source;
151151
InformerClassifier<R> classifier = getClassifier(namespaceIdentifier);
152152
var informer =
153153
informerPool.getInformer(configuration.getInformerConfig().getName(), classifier);
154+
informerPool.start(informer, classifier);
155+
154156
source =
155157
new InformerWrapper<>(
156158
informer, namespaceIdentifier, controllerConfiguration.getConfigurationService());

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,24 @@ protected SharedIndexInformer createInformer(InformerClassifier<?> classifier) {
145145
return informer;
146146
}
147147

148-
protected void start(
149-
SharedIndexInformer<? extends HasMetadata> informer,
150-
InformerClassifier<?> informerClassifier) {
148+
/**
149+
* Fires (but does not wait for) the informer's start. This is cheap/non-blocking (the actual
150+
* list+watch happens asynchronously), so it is safe to call while holding a pool-internal lock.
151+
* Doing so atomically with the informer's creation/reference-count bookkeeping is what prevents a
152+
* concurrent {@code releaseInformer} from stopping the informer before it is ever started.
153+
*/
154+
protected void triggerStart(
155+
SharedIndexInformer<? extends HasMetadata> informer, InformerClassifier<?> classifier) {
156+
log.debug(
157+
"Starting informer for namespace: {} resource: {}",
158+
classifier.namespaceIdentifier(),
159+
informer.getApiTypeClass().getSimpleName());
160+
informer.start();
161+
}
162+
163+
@Override
164+
public <R extends HasMetadata> void start(
165+
SharedIndexInformer<R> informer, InformerClassifier<R> informerClassifier) {
151166
// change thread name for easier debugging
152167
final var thread = Thread.currentThread();
153168
final var name = thread.getName();
@@ -159,10 +174,8 @@ protected void start(
159174
+ " "
160175
+ thread.getId());
161176
final var resourceName = informer.getApiTypeClass().getSimpleName();
162-
log.debug(
163-
"Starting informer for namespace: {} resource: {}",
164-
informerClassifier.namespaceIdentifier(),
165-
resourceName);
177+
// idempotent: if the informer was already started (e.g. by the pool when it was
178+
// created/reused), this just returns the existing start future without restarting it
166179
var start = informer.start();
167180
// note that in case we don't put here timeout and stopOnInformerErrorDuringStartup is
168181
// false, and there is a rbac issue the get never returns; therefore operator never really

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ public class AlwaysCreateInformerPool extends AbstractInformerPool {
3636
public <R extends HasMetadata> SharedIndexInformer<R> getInformer(
3737
String name, InformerClassifier<R> classifier) {
3838
var informer = createInformer(classifier);
39-
start(informer, classifier);
4039
informers.put(new ClassifierWithName(name, classifier), informer);
4140
return informer;
4241
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ public <R extends HasMetadata> SharedIndexInformer<R> getInformer(
6767
classifier.informerListLimit()));
6868
counters.get(classifier).incrementAndGet();
6969
}
70+
// fire the start while still holding the lock so a concurrent releaseInformer() can't stop
71+
// this informer before it has ever been started; the caller is responsible for actually
72+
// waiting on it via start(), which is not done here to avoid blocking the pool lock for the
73+
// (potentially slow) cache sync
74+
triggerStart(informer, classifier);
7075
}
71-
start(informer, classifier);
7276
return informer;
7377
}
7478

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ public interface InformerPool {
3131
<R extends HasMetadata> SharedIndexInformer<R> getInformer(
3232
String name, InformerClassifier<R> classifier);
3333

34+
/**
35+
* Starts the informer (if not already started) and blocks until its cache has synced, or the
36+
* configured {@link ConfigurationService#cacheSyncTimeout()} elapses. Callers are expected to
37+
* invoke this after {@link #getInformer(String, InformerClassifier)} returns; the pool itself
38+
* only registers/reference-counts the informer and does not block on cache sync internally.
39+
*/
40+
<R extends HasMetadata> void start(
41+
SharedIndexInformer<R> informer, InformerClassifier<R> classifier);
42+
3443
<R extends HasMetadata> Optional<SharedIndexInformer<R>> releaseInformer(
3544
String name, InformerClassifier<R> classifier);
3645

0 commit comments

Comments
 (0)