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

com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser Maven / Gradle / Ivy

Go to download

Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and much more.

The newest version!
/*
 * Copyright 2011-2016 the original author or authors.
 *
 * 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.lambdaworks.redis.cluster.models.partitions;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.lambdaworks.redis.LettuceStrings;
import com.lambdaworks.redis.RedisException;
import com.lambdaworks.redis.RedisURI;
import com.lambdaworks.redis.internal.HostAndPort;
import com.lambdaworks.redis.internal.LettuceLists;

/**
 * Parser for node information output of {@code CLUSTER NODES} and {@code CLUSTER SLAVES}.
 * 
 * @author Mark Paluch
 * @since 3.0
 */
public class ClusterPartitionParser {

    public static final String CONNECTED = "connected";

    private static final String TOKEN_SLOT_IN_TRANSITION = "[";
    private static final char TOKEN_NODE_SEPARATOR = '\n';
    private static final Pattern TOKEN_PATTERN = Pattern.compile(Character.toString(TOKEN_NODE_SEPARATOR));
    private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
    private static final Pattern DASH_PATTERN = Pattern.compile("\\-");
    private static final Map FLAG_MAPPING;

    static {
        Map map = new HashMap<>();

        map.put("noflags", RedisClusterNode.NodeFlag.NOFLAGS);
        map.put("myself", RedisClusterNode.NodeFlag.MYSELF);
        map.put("master", RedisClusterNode.NodeFlag.MASTER);
        map.put("slave", RedisClusterNode.NodeFlag.SLAVE);
        map.put("fail?", RedisClusterNode.NodeFlag.EVENTUAL_FAIL);
        map.put("fail", RedisClusterNode.NodeFlag.FAIL);
        map.put("handshake", RedisClusterNode.NodeFlag.HANDSHAKE);
        map.put("noaddr", RedisClusterNode.NodeFlag.NOADDR);
        FLAG_MAPPING = Collections.unmodifiableMap(map);
    }

    /**
     * Utility constructor.
     */
    private ClusterPartitionParser() {

    }

    /**
     * Parse partition lines into Partitions object.
     * 
     * @param nodes output of CLUSTER NODES
     * @return the partitions object.
     */
    public static Partitions parse(String nodes) {
        Partitions result = new Partitions();

        try {
            List mappedNodes = TOKEN_PATTERN.splitAsStream(nodes).filter(s -> !s.isEmpty())
                    .map(ClusterPartitionParser::parseNode)
                    .collect(Collectors.toList());
            result.addAll(mappedNodes);
        } catch (Exception e) {
            throw new RedisException("Cannot parse " + nodes, e);
        }

        return result;
    }

    private static RedisClusterNode parseNode(String nodeInformation) {

        Iterator iterator = SPACE_PATTERN.splitAsStream(nodeInformation).iterator();

        String nodeId = iterator.next();
        boolean connected = false;
        RedisURI uri = null;

        String hostAndPortPart = iterator.next();
        if(hostAndPortPart.contains("@")) {
            hostAndPortPart = hostAndPortPart.substring(0, hostAndPortPart.indexOf('@'));
        }

        HostAndPort hostAndPort = HostAndPort.parseCompat(hostAndPortPart);

        if (LettuceStrings.isNotEmpty(hostAndPort.getHostText())) {
            uri = RedisURI.Builder.redis(hostAndPort.getHostText(), hostAndPort.getPort()).build();
        }

        String flags = iterator.next();
        List flagStrings = LettuceLists.newList(flags.split("\\,"));

        Set nodeFlags = readFlags(flagStrings);

        String slaveOfString = iterator.next(); // (nodeId or -)
        String slaveOf = "-".equals(slaveOfString) ? null : slaveOfString;

        long pingSentTs = getLongFromIterator(iterator, 0);
        long pongReceivedTs = getLongFromIterator(iterator, 0);
        long configEpoch = getLongFromIterator(iterator, 0);

        String connectedFlags = iterator.next(); // "connected" : "disconnected"

        if (CONNECTED.equals(connectedFlags)) {
            connected = true;
        }

        List slotStrings = LettuceLists.newList(iterator); // slot, from-to [slot->-nodeID] [slot-<-nodeID]
        List slots = readSlots(slotStrings);

        RedisClusterNode partition = new RedisClusterNode(uri, nodeId, connected, slaveOf, pingSentTs, pongReceivedTs,
                configEpoch, slots, nodeFlags);

        return partition;

    }

    private static Set readFlags(List flagStrings) {

        Set flags = new HashSet<>();
        for (String flagString : flagStrings) {
            if (FLAG_MAPPING.containsKey(flagString)) {
                flags.add(FLAG_MAPPING.get(flagString));
            }
        }
        return Collections.unmodifiableSet(flags);
    }

    private static List readSlots(List slotStrings) {

        List slots = new ArrayList<>();
        for (String slotString : slotStrings) {

            if (slotString.startsWith(TOKEN_SLOT_IN_TRANSITION)) {
                // not interesting
                continue;

            }

            if (slotString.contains("-")) {
                // slot range
                Iterator it = DASH_PATTERN.splitAsStream(slotString).iterator();
                int from = Integer.parseInt(it.next());
                int to = Integer.parseInt(it.next());

                for (int slot = from; slot <= to; slot++) {
                    slots.add(slot);

                }
                continue;
            }

            slots.add(Integer.parseInt(slotString));
        }

        return Collections.unmodifiableList(slots);
    }

    private static long getLongFromIterator(Iterator iterator, long defaultValue) {
        if (iterator.hasNext()) {
            Object object = iterator.next();
            if (object instanceof String) {
                return Long.parseLong((String) object);
            }
        }
        return defaultValue;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy