All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.reactivex.mantis.remote.observable.ToDeltaEndpointInjector Maven / Gradle / Ivy

There is a newer version: 3.1.4
Show newest version
/*
 * Copyright 2019 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 io.reactivex.mantis.remote.observable;

import io.mantisrx.common.network.Endpoint;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.functions.Func1;


public class ToDeltaEndpointInjector implements EndpointInjector {

    private static final Logger logger = LoggerFactory.getLogger(ToDeltaEndpointInjector.class);

    private Observable> endpointObservable;
    private Observable reconcileChanges;

    public ToDeltaEndpointInjector(Observable> endpointObservable) {
        this(endpointObservable, Observable.empty());
    }

    public ToDeltaEndpointInjector(Observable> endpointObservable,
                                   Observable reconcileChanges) {
        this.endpointObservable = endpointObservable;
        this.reconcileChanges = reconcileChanges;
    }

    private String uniqueHost(String host, int port, String slotId) {
        return host + ":" + port + ":" + slotId;
    }

    private List changes(List previous, List current) {


        logger.info("Sets to evaluate for differences, current: " + current + " previous: " + previous);

        Map previousSet = new HashMap<>();
        // fill previous
        for (Endpoint endpoint : previous) {
            previousSet.put(uniqueHost(endpoint.getHost(), endpoint.getPort(),
                    endpoint.getSlotId()), endpoint);
        }

        // collect into two buckets: add, complete
        List toAdd = new LinkedList<>();
        Set completeCheck = new HashSet<>();
        for (Endpoint endpoint : current) {
            String id = uniqueHost(endpoint.getHost(), endpoint.getPort(),
                    endpoint.getSlotId());
            if (!previousSet.containsKey(id)) {
                EndpointChange ce = new EndpointChange(EndpointChange.Type.add, endpoint);
                toAdd.add(ce);
            } else {
                completeCheck.add(id);
            }
        }
        List toComplete = new LinkedList();
        // check if need to complete any from current set: set difference
        for (Map.Entry controlledEndpoint : previousSet.entrySet()) {
            if (!completeCheck.contains(controlledEndpoint.getKey())) {
                Endpoint ce = controlledEndpoint.getValue();
                EndpointChange ceToCompletd = new EndpointChange(EndpointChange.Type.complete, ce);
                toComplete.add(ceToCompletd);
            }
        }

        Map nextSet = new HashMap<>();
        // apply completes
        for (EndpointChange controlledEndpoint : toComplete) {
            nextSet.put(uniqueHost(controlledEndpoint.getEndpoint().getHost(), controlledEndpoint.getEndpoint().getPort(),
                    controlledEndpoint.getEndpoint().getSlotId()), controlledEndpoint);
        }
        // apply adds
        for (EndpointChange controlledEndpoint : toAdd) {
            nextSet.put(uniqueHost(controlledEndpoint.getEndpoint().getHost(), controlledEndpoint.getEndpoint().getPort(),
                    controlledEndpoint.getEndpoint().getSlotId()), controlledEndpoint);
        }
        logger.info("Differences to be applied: " + nextSet);
        return new ArrayList<>(nextSet.values());
    }

    @Override
    public Observable deltas() {
        return
                Observable.merge(
                        reconcileChanges,
                        endpointObservable
                                .startWith(Collections.emptyList())
                                .buffer(2, 1) // stagger current and previous
                                .flatMap(new Func1>, Observable>() {
                                    @Override
                                    public Observable call(List> previousAndCurrent) {
                                        if (previousAndCurrent.size() == 2) {
                                            List previous = previousAndCurrent.get(0);
                                            List current = previousAndCurrent.get(1);
                                            return Observable.from(changes(previous, current));
                                        } else {
                                            // skipping last entry, already processed on the
                                            //  last previousAndCurrent pair
                                            return Observable.empty();
                                        }
                                    }
                                }));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy