com.netflix.eureka2.client.registry.EurekaClientRegistryImpl Maven / Gradle / Ivy
/*
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.eureka2.client.registry;
import com.netflix.eureka2.client.metric.EurekaClientRegistryMetrics;
import com.netflix.eureka2.datastore.NotificationsSubject;
import com.netflix.eureka2.interests.ChangeNotification;
import com.netflix.eureka2.interests.IndexRegistry;
import com.netflix.eureka2.interests.IndexRegistryImpl;
import com.netflix.eureka2.interests.InstanceInfoInitStateHolder;
import com.netflix.eureka2.interests.Interest;
import com.netflix.eureka2.interests.ModifyNotification;
import com.netflix.eureka2.interests.MultipleInterests;
import com.netflix.eureka2.registry.Delta;
import com.netflix.eureka2.registry.InstanceInfo;
import rx.Observable;
import rx.functions.Func1;
import javax.inject.Inject;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import static com.netflix.eureka2.interests.ChangeNotification.Kind;
/**
* @author Tomasz Bak
*/
public class EurekaClientRegistryImpl implements EurekaClientRegistry {
private final NotificationsSubject notificationSubject; // subject for all changes in the registry
private final IndexRegistry indexRegistry;
private final EurekaClientRegistryMetrics metrics;
private final ConcurrentHashMap internalStore;
@Inject
public EurekaClientRegistryImpl(EurekaClientRegistryMetrics metrics) {
this.metrics = metrics;
this.metrics.setRegistrySizeMonitor(new Callable() {
@Override
public Integer call() throws Exception {
return internalStore.size();
}
});
internalStore = new ConcurrentHashMap<>();
indexRegistry = new IndexRegistryImpl<>();
notificationSubject = NotificationsSubject.create();
}
@Override
public Observable register(InstanceInfo instanceInfo) {
internalStore.put(instanceInfo.getId(), instanceInfo);
notificationSubject.onNext(new ChangeNotification<>(Kind.Add, instanceInfo));
return Observable.empty();
}
@Override
public Observable unregister(InstanceInfo instanceInfo) {
InstanceInfo removed = internalStore.remove(instanceInfo.getId());
if (removed != null) {
notificationSubject.onNext(new ChangeNotification(Kind.Delete, instanceInfo));
}
return Observable.empty();
}
@Override
public Observable update(InstanceInfo updatedInfo, Set> deltas) {
InstanceInfo previous = internalStore.put(updatedInfo.getId(), updatedInfo);
if (previous == null) {
notificationSubject.onNext(new ChangeNotification<>(Kind.Add, updatedInfo));
} else {
notificationSubject.onNext(new ModifyNotification(updatedInfo, deltas));
}
return Observable.empty();
}
/**
* Return a snapshot of the current registry for the passed {@code interest} as a stream of {@link InstanceInfo}s.
* This view of the snapshot is eventual consistent and any instances that successfully registers while the
* stream is being processed might be added to the stream. Note that this stream terminates as opposed to
* forInterest.
*
* @return A stream of {@link InstanceInfo}s for the passed {@code interest}. The stream represent a snapshot
* of the registry for the interest.
*/
@Override
public Observable forSnapshot(final Interest interest) {
return Observable.from(internalStore.values())
.filter(new Func1() {
@Override
public Boolean call(InstanceInfo instanceInfo) {
return instanceInfo != null && interest.matches(instanceInfo);
}
});
}
/**
* Return an observable of all matching InstanceInfo for the current registry snapshot,
* as {@link ChangeNotification}s
* @param interest
* @return an observable of all matching InstanceInfo for the current registry snapshot,
* as {@link ChangeNotification}s
*/
@Override
public Observable> forInterest(Interest interest) {
try {
// TODO: this method can be run concurrently from different channels, unless we run everything on single server event loop.
notificationSubject.pause(); // Pause notifications till we get a snapshot of current registry (registry.values())
if (interest instanceof MultipleInterests) {
return indexRegistry.forCompositeInterest((MultipleInterests) interest, this);
} else {
return indexRegistry.forInterest(interest, notificationSubject,
new InstanceInfoInitStateHolder(getSnapshotForInterest(interest)));
}
} finally {
notificationSubject.resume();
}
}
private Iterator> getSnapshotForInterest(final Interest interest) {
return new FilteredIterator(interest, internalStore.values().iterator());
}
@Override
public Observable shutdown() {
return indexRegistry.shutdown();
}
private static class FilteredIterator implements Iterator> {
private final Interest interest;
private final Iterator delegate;
private ChangeNotification next;
private FilteredIterator(Interest interest, Iterator delegate) {
this.interest = interest;
this.delegate = delegate;
}
@Override
public boolean hasNext() {
if (null != next) {
return true;
}
while (delegate.hasNext()) { // Iterate till we get a matching item.
InstanceInfo possibleNext = delegate.next();
ChangeNotification notification = new ChangeNotification<>(Kind.Add, possibleNext);
if (notification != null && interest.matches(notification.getData())) {
next = notification;
return true;
}
}
return false;
}
@Override
public ChangeNotification next() {
if (hasNext()) {
ChangeNotification next = this.next;
this.next = null; // Forces hasNext() to peek the next item.
return next;
}
throw new NoSuchElementException("No more notifications.");
}
@Override
public void remove() {
throw new UnsupportedOperationException("Remove not supported for this iterator.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy