org.apache.solr.common.cloud.Slice.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.common.cloud.Slice.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.solr.common.cloud;

import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.apache.solr.common.cloud.Replica.Type;
import org.noggit.JSONWriter;

import static org.apache.solr.common.util.Utils.toJSONString;

/**
 * A Slice contains immutable information about a logical shard (all replicas that share the same shard id).
 */
public class Slice extends ZkNodeProps implements Iterable<Replica> {
    public final String collection;

    /** Loads multiple slices into a Map from a generic Map that probably came from deserialized JSON. */
    public static Map<String, Slice> loadAllFromMap(String collection, Map<String, Object> genericSlices) {
        if (genericSlices == null)
            return Collections.emptyMap();
        Map<String, Slice> result = new LinkedHashMap<>(genericSlices.size());
        for (Map.Entry<String, Object> entry : genericSlices.entrySet()) {
            String name = entry.getKey();
            Object val = entry.getValue();
            if (val instanceof Slice) {
                result.put(name, (Slice) val);
            } else if (val instanceof Map) {
                result.put(name, new Slice(name, null, (Map<String, Object>) val, collection));
            }
        }
        return result;
    }

    @Override
    public Iterator<Replica> iterator() {
        return replicas.values().iterator();
    }

    /** The slice's state. */
    public enum State {

        /** The normal/default state of a shard. */
        ACTIVE,

        /**
         * A shard is put in that state after it has been successfully split. See
         * <a href="https://lucene.apache.org/solr/guide/collections-api.html#splitshard">
         * the reference guide</a> for more details.
         */
        INACTIVE,

        /**
         * When a shard is split, the new sub-shards are put in that state while the
         * split operation is in progress. It's also used when the shard is undergoing data restoration.
         * A shard in this state still receives
         * update requests from the parent shard leader, however does not participate
         * in distributed search.
         */
        CONSTRUCTION,

        /**
         * Sub-shards of a split shard are put in that state, when they need to
         * create replicas in order to meet the collection's replication factor. A
         * shard in that state still receives update requests from the parent shard
         * leader, however does not participate in distributed search.
         */
        RECOVERY,

        /**
         * Sub-shards of a split shard are put in that state when the split is deemed failed
         * by the overseer even though all replicas are active because either the leader node is
         * no longer live or has a different ephemeral owner (zk session id). Such conditions can potentially
         * lead to data loss. See SOLR-9438 for details. A shard in that state will neither receive
         * update requests from the parent shard leader, nor participate in distributed search.
         */
        RECOVERY_FAILED;

        @Override
        public String toString() {
            return super.toString().toLowerCase(Locale.ROOT);
        }

        /** Converts the state string to a State instance. */
        public static State getState(String stateStr) {
            return State.valueOf(stateStr.toUpperCase(Locale.ROOT));
        }
    }

    public static final String REPLICAS = "replicas";
    public static final String RANGE = "range";
    public static final String LEADER = "leader"; // FUTURE: do we want to record the leader as a slice property in the JSON (as opposed to isLeader as a replica property?)
    public static final String PARENT = "parent";

    private final String name;
    private final DocRouter.Range range;
    private final Integer replicationFactor; // FUTURE: optional per-slice override of the collection replicationFactor
    private final Map<String, Replica> replicas;
    private final Replica leader;
    private final State state;
    private final String parent;
    private final Map<String, RoutingRule> routingRules;

    /**
     * @param name  The name of the slice
     * @param replicas The replicas of the slice.  This is used directly and a copy is not made.  If null, replicas will be constructed from props.
     * @param props  The properties of the slice - a shallow copy will always be made.
     */
    public Slice(String name, Map<String, Replica> replicas, Map<String, Object> props, String collection) {
        super(props == null ? new LinkedHashMap<String, Object>(2) : new LinkedHashMap<>(props));
        this.name = name;
        this.collection = collection;

        Object rangeObj = propMap.get(RANGE);
        if (propMap.get(ZkStateReader.STATE_PROP) != null) {
            this.state = State.getState((String) propMap.get(ZkStateReader.STATE_PROP));
        } else {
            this.state = State.ACTIVE; //Default to ACTIVE
            propMap.put(ZkStateReader.STATE_PROP, state.toString());
        }
        DocRouter.Range tmpRange = null;
        if (rangeObj instanceof DocRouter.Range) {
            tmpRange = (DocRouter.Range) rangeObj;
        } else if (rangeObj != null) {
            // Doesn't support custom implementations of Range, but currently not needed.
            tmpRange = DocRouter.DEFAULT.fromString(rangeObj.toString());
        }
        range = tmpRange;

        /** debugging.  this isn't an error condition for custom sharding.
        if (range == null) {
          System.out.println("###### NO RANGE for " + name + " props=" + props);
        }
        **/

        if (propMap.containsKey(PARENT) && propMap.get(PARENT) != null)
            this.parent = (String) propMap.get(PARENT);
        else
            this.parent = null;

        replicationFactor = null; // future

        // add the replicas *after* the other properties (for aesthetics, so it's easy to find slice properties in the JSON output)
        this.replicas = replicas != null ? replicas
                : makeReplicas(collection, name, (Map<String, Object>) propMap.get(REPLICAS));
        propMap.put(REPLICAS, this.replicas);

        Map<String, Object> rules = (Map<String, Object>) propMap.get("routingRules");
        if (rules != null) {
            this.routingRules = new HashMap<>();
            for (Map.Entry<String, Object> entry : rules.entrySet()) {
                Object o = entry.getValue();
                if (o instanceof Map) {
                    Map map = (Map) o;
                    RoutingRule rule = new RoutingRule(entry.getKey(), map);
                    routingRules.put(entry.getKey(), rule);
                } else {
                    routingRules.put(entry.getKey(), (RoutingRule) o);
                }
            }
        } else {
            this.routingRules = null;
        }

        leader = findLeader();
    }

    private Map<String, Replica> makeReplicas(String collection, String slice,
            Map<String, Object> genericReplicas) {
        if (genericReplicas == null)
            return new HashMap<>(1);
        Map<String, Replica> result = new LinkedHashMap<>(genericReplicas.size());
        for (Map.Entry<String, Object> entry : genericReplicas.entrySet()) {
            String name = entry.getKey();
            Object val = entry.getValue();
            Replica r;
            if (val instanceof Replica) {
                r = (Replica) val;
            } else {
                r = new Replica(name, (Map<String, Object>) val, collection, slice);
            }
            result.put(name, r);
        }
        return result;
    }

    private Replica findLeader() {
        for (Replica replica : replicas.values()) {
            if (replica.getStr(LEADER) != null) {
                assert replica.getType() == Type.TLOG
                        || replica.getType() == Type.NRT : "Pull replica should not become leader!";
                return replica;
            }
        }
        return null;
    }

    public String getCollection() {
        return collection;
    }

    /**
     * Return slice name (shard id).
     */
    public String getName() {
        return name;
    }

    /**
     * Gets the list of all replicas for this slice.
     */
    public Collection<Replica> getReplicas() {
        return replicas.values();
    }

    /**
     * Gets all replicas that match a predicate
     */
    public List<Replica> getReplicas(Predicate<Replica> pred) {
        return replicas.values().stream().filter(pred).collect(Collectors.toList());
    }

    /**
     * Gets the list of replicas that have a type present in s
     */
    public List<Replica> getReplicas(EnumSet<Replica.Type> s) {
        return this.getReplicas(r -> s.contains(r.getType()));
    }

    /**
     * Get the map of coreNodeName to replicas for this slice.
     */
    public Map<String, Replica> getReplicasMap() {
        return replicas;
    }

    public Map<String, Replica> getReplicasCopy() {
        return new LinkedHashMap<>(replicas);
    }

    public Replica getLeader() {
        return leader;
    }

    public Replica getReplica(String replicaName) {
        return replicas.get(replicaName);
    }

    public DocRouter.Range getRange() {
        return range;
    }

    public State getState() {
        return state;
    }

    public String getParent() {
        return parent;
    }

    public Map<String, RoutingRule> getRoutingRules() {
        return routingRules;
    }

    @Override
    public String toString() {
        return name + ':' + toJSONString(propMap);
    }

    @Override
    public void write(JSONWriter jsonWriter) {
        jsonWriter.write(propMap);
    }

}