com.ca.apm.mongo.ShardCluster.java Source code

Java tutorial

Introduction

Here is the source code for com.ca.apm.mongo.ShardCluster.java

Source

/*
 *
 * Copyright (c) 2014 CA. All rights reserved.
 *
 * 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.
    
 * IN NO EVENT WILL CA BE LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY LOSS
 * OR DAMAGE, DIRECT OR INDIRECT, FROM THE USE OF THIS MATERIAL,
 * INCLUDING WITHOUT LIMITATION, LOST PROFITS, BUSINESS INTERRUPTION, GOODWILL,
 * OR LOST DATA, EVEN IF CA IS EXPRESSLY ADVISED OF SUCH LOSS OR DAMAGE.
 *
 */
package com.ca.apm.mongo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.logging.Level;

import org.bson.BasicBSONObject;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;

public final class ShardCluster extends Topology {

    public ShardCluster(final Properties props, final String h, final int p, final Logger l) {
        super(props, h, p, l, ClusterType.SHARDED_CLUSTER);
    }

    private String host = dbHost;
    private int port = dbPort;

    public void discoverServers(final String nodeType) throws Exception {

        List<String> shardRouters = null;
        List<String> shardServers = null;
        List<String> cfgServers = null;

        logger.log(Level.FINE, "Shard Cluster Node Type: {0}", nodeType);

        if ("shardRouter".equals(nodeType)) {

            shardServers = getShardsFromMongos(host, port);
            shardRouters = getMongosFromConfig(host, port);
            cfgServers = getConfigServersFromMongos(host, port);

        } else if ("shardConfigServer".equals(nodeType)) {

            shardRouters = getMongosFromConfig(host, port);
            for (String shardRouter : shardRouters) {
                MongoServer ms = new MongoServer(shardRouter);
                cfgServers = getConfigServersFromMongos(ms.getHost(), ms.getPort());
                break;
            }
            shardServers = getShardsFromConfig(host, port);

        } else if ("shardMember".equals(nodeType)) {

            cfgServers = getConfigServersFromShard(host, port);
            for (String cfgServer : cfgServers) {
                MongoServer ms = new MongoServer(cfgServer);
                shardRouters = getMongosFromConfig(ms.getHost(), ms.getPort());
                break;
            }
            for (String cfgServer : cfgServers) {
                MongoServer ms = new MongoServer(cfgServer);
                shardServers = getShardsFromConfig(ms.getHost(), ms.getPort());
                break;
            }

        } else {
            throw new RuntimeException("UnKnown Cluster node type!");
        }

        members.addAll(shardRouters);
        members.addAll(shardServers);
        members.addAll(cfgServers);
    }

    private List<String> getShardsFromMongos(final String host, final int port) throws Exception {

        final List<String> shardResult = new ArrayList<String>();

        final CommandResult cr = dbAdminCmd(host, port, "listShards");

        if (cr.ok()) {
            final BasicDBList shardList = (BasicDBList) cr.get("shards");
            for (Object obj : shardList) {
                final BasicDBObject bdbo = (BasicDBObject) obj;
                String shards = bdbo.getString("host");
                if (shards.indexOf("/") != -1) {
                    final String[] shardMembers = shards.split("/")[1].split(",");
                    for (String member : shardMembers) {
                        final MongoServer ms = new MongoServer(member);
                        shardResult.addAll(discoverReplicas(ms.getHost(), ms.getPort()));
                    }
                } else {
                    // single node shard
                    shardResult.add(shards);
                }
            }
        }
        return shardResult;
    }

    private List<String> getShardsFromConfig(final String host, final int port) {

        final List<String> shardList = new ArrayList<String>();

        MongoClient dbClient = null;

        try {
            dbClient = setupDbClient(host, port);

            final DB configDB = dbClient.getDB("config");
            final DBCursor shardsCursor = configDB.getCollectionFromString("shards").find();
            while (shardsCursor.hasNext()) {
                final DBObject dbo = shardsCursor.next();
                String shards = (String) dbo.get("host");
                String[] shardMembers = getShardMembers(shards);
                for (String member : shardMembers) {
                    shardList.add(member);
                }
            }
        } catch (Exception e) {
            logger.log(Level.WARNING, "Exception getting shards from cfg servers: {0}", e);
        } finally {
            if (dbClient != null) {
                dbClient.close();
            }
        }
        return shardList;
    }

    private List<String> getMongosFromConfig(final String host, final int port) {

        final List<String> shardRouters = new ArrayList<String>();

        MongoClient dbClient = null;

        try {
            dbClient = setupDbClient(host, port);
            final DB configDB = dbClient.getDB("config");
            final DBCursor mongosCursor = configDB.getCollectionFromString("mongos").find();
            while (mongosCursor.hasNext()) {
                final DBObject dbo = mongosCursor.next();
                final String mongos = (String) dbo.get("_id");
                shardRouters.add(mongos);
            }
        } catch (Exception e) {
            logger.log(Level.WARNING, "Exception getting mongos from cfg server(s): {0}", e);
        } finally {
            if (dbClient != null) {
                dbClient.close();
            }
        }
        return shardRouters;
    }

    private List<String> getConfigServersFromMongos(final String host, final int port) throws Exception {
        final List<String> cfgServers = new ArrayList<String>();

        final BasicBSONObject parsed = getParsedCmdLineOpts(host, port);

        final BasicBSONObject sharding = (BasicBSONObject) parsed.get("sharding");
        String cfgServerString;
        if (sharding != null)
            cfgServerString = sharding.getString("configDB");
        else
            cfgServerString = (String) parsed.get("configDB");
        addCommaSeparatedHosts(cfgServers, cfgServerString);

        return cfgServers;
    }

    private List<String> getConfigServersFromShard(final String host, final int port) throws Exception {

        final List<String> cfgServers = new ArrayList<String>();

        String cHost = host;
        int cPort = port;

        final CommandResult isMaster = dbAdminCmd(cHost, cPort, "isMaster");

        // we can't run the DB command "shardingState" from a node
        // which isn't a master.  This should only apply to non-primary
        // replica members, so find the primary and run the command on it.
        if (!isMaster.getBoolean("ismaster")) {
            if (isMaster.containsField("primary")) {
                final String primary = isMaster.getString("primary");
                final MongoServer ms = new MongoServer(primary);
                cHost = ms.getHost();
                cPort = ms.getPort();
            }
        }

        CommandResult shardState = dbAdminCmd(cHost, cPort, "shardingState");

        if (shardState.ok()) {
            final String cfgSrvs = shardState.getString("configServer");
            addCommaSeparatedHosts(cfgServers, cfgSrvs);
        }
        return cfgServers;
    }

    private String[] getShardMembers(final String shardString) {
        String shards = shardString;
        if (shards.indexOf("/") != -1) {
            shards = shards.split("/")[1];
        }
        return shards.split(",");
    }

    private void addCommaSeparatedHosts(final Collection<String> c, final String hosts) {
        if (hosts != null) {
            for (String host : hosts.split(",")) {
                c.add(host);
            }
        }
    }

    private BasicBSONObject getParsedCmdLineOpts(final String host, final int port) throws Exception {

        BasicBSONObject parsed = null;

        final CommandResult clOptions = dbAdminCmd(host, port, "getCmdLineOpts");

        if (clOptions.ok()) {
            parsed = (BasicBSONObject) clOptions.get("parsed");
        } else {
            throw new RuntimeException("Failed to get command line options!");
        }
        return parsed;
    }
}