/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.metadata.sys;
import com.google.common.collect.ImmutableList;
import io.crate.analyze.WhereClause;
import io.crate.metadata.*;
import io.crate.metadata.shard.unassigned.UnassignedShard;
import io.crate.metadata.table.ColumnRegistrar;
import io.crate.metadata.table.StaticTableInfo;
import io.crate.types.*;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.routing.GroupShardsIterator;
import org.elasticsearch.cluster.routing.ShardIterator;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.index.shard.ShardId;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@Singleton
public class SysShardsTableInfo extends StaticTableInfo {
public static final TableIdent IDENT = new TableIdent(SysSchemaInfo.NAME, "shards");
private final ClusterService service;
public static class Columns {
public static final ColumnIdent ID = new ColumnIdent("id");
public static final ColumnIdent SCHEMA_NAME = new ColumnIdent("schema_name");
public static final ColumnIdent TABLE_NAME = new ColumnIdent("table_name");
public static final ColumnIdent PARTITION_IDENT = new ColumnIdent("partition_ident");
public static final ColumnIdent NUM_DOCS = new ColumnIdent("num_docs");
public static final ColumnIdent PRIMARY = new ColumnIdent("primary");
public static final ColumnIdent RELOCATING_NODE = new ColumnIdent("relocating_node");
public static final ColumnIdent SIZE = new ColumnIdent("size");
public static final ColumnIdent STATE = new ColumnIdent("state");
public static final ColumnIdent ROUTING_STATE = new ColumnIdent("routing_state");
public static final ColumnIdent ORPHAN_PARTITION = new ColumnIdent("orphan_partition");
public static final ColumnIdent RECOVERY = new ColumnIdent("recovery");
public static final ColumnIdent RECOVERY_STAGE = new ColumnIdent("recovery", ImmutableList.of("stage"));
public static final ColumnIdent RECOVERY_TYPE = new ColumnIdent("recovery", ImmutableList.of("type"));
public static final ColumnIdent RECOVERY_TOTAL_TIME =
new ColumnIdent("recovery", ImmutableList.of("total_time"));
public static final ColumnIdent RECOVERY_FILES = new ColumnIdent("recovery", ImmutableList.of("files"));
public static final ColumnIdent RECOVERY_FILES_USED =
new ColumnIdent("recovery", ImmutableList.of("files", "used"));
public static final ColumnIdent RECOVERY_FILES_REUSED =
new ColumnIdent("recovery", ImmutableList.of("files", "reused"));
public static final ColumnIdent RECOVERY_FILES_RECOVERED =
new ColumnIdent("recovery", ImmutableList.of("files", "recovered"));
public static final ColumnIdent RECOVERY_FILES_PERCENT =
new ColumnIdent("recovery", ImmutableList.of("files", "percent"));
public static final ColumnIdent RECOVERY_SIZE =
new ColumnIdent("recovery", ImmutableList.of("size"));
public static final ColumnIdent RECOVERY_SIZE_USED =
new ColumnIdent("recovery", ImmutableList.of("size", "used"));
public static final ColumnIdent RECOVERY_SIZE_REUSED =
new ColumnIdent("recovery", ImmutableList.of("size", "reused"));
public static final ColumnIdent RECOVERY_SIZE_RECOVERED =
new ColumnIdent("recovery", ImmutableList.of("size", "recovered"));
public static final ColumnIdent RECOVERY_SIZE_PERCENT =
new ColumnIdent("recovery", ImmutableList.of("size", "percent"));
public static final ColumnIdent PATH = new ColumnIdent("path");
public static final ColumnIdent BLOB_PATH = new ColumnIdent("blob_path");
public static final ColumnIdent MIN_LUCENE_VERSION = new ColumnIdent("min_lucene_version");
}
public static class ReferenceIdents {
/**
* Implementations have to be registered in
* - {@link io.crate.metadata.shard.ShardReferenceResolver}
* - {@link io.crate.metadata.shard.blob.BlobShardReferenceResolver}
* - {@link io.crate.operation.reference.sys.shard.unassigned.UnassignedShardsExpressionFactories}
*/
public static final ReferenceIdent ID = new ReferenceIdent(IDENT, Columns.ID);
public static final ReferenceIdent SCHEMA_NAME = new ReferenceIdent(IDENT, Columns.SCHEMA_NAME);
public static final ReferenceIdent TABLE_NAME = new ReferenceIdent(IDENT, Columns.TABLE_NAME);
public static final ReferenceIdent PARTITION_IDENT = new ReferenceIdent(IDENT, Columns.PARTITION_IDENT);
public static final ReferenceIdent NUM_DOCS = new ReferenceIdent(IDENT, Columns.NUM_DOCS);
public static final ReferenceIdent PRIMARY = new ReferenceIdent(IDENT, Columns.PRIMARY);
public static final ReferenceIdent RELOCATING_NODE = new ReferenceIdent(IDENT, Columns.RELOCATING_NODE);
public static final ReferenceIdent SIZE = new ReferenceIdent(IDENT, Columns.SIZE);
public static final ReferenceIdent STATE = new ReferenceIdent(IDENT, Columns.STATE);
public static final ReferenceIdent ROUTING_STATE = new ReferenceIdent(IDENT, Columns.ROUTING_STATE);
public static final ReferenceIdent ORPHAN_PARTITION = new ReferenceIdent(IDENT, Columns.ORPHAN_PARTITION);
public static final ReferenceIdent RECOVERY = new ReferenceIdent(IDENT, Columns.RECOVERY);
public static final ReferenceIdent PATH = new ReferenceIdent(IDENT, Columns.PATH);
public static final ReferenceIdent BLOB_PATH = new ReferenceIdent(IDENT, Columns.BLOB_PATH);
public static final ReferenceIdent MIN_LUCENE_VERSION = new ReferenceIdent(IDENT, Columns.MIN_LUCENE_VERSION);
}
private static final ImmutableList<ColumnIdent> PRIMARY_KEY = ImmutableList.of(
Columns.SCHEMA_NAME,
Columns.TABLE_NAME,
Columns.ID,
Columns.PARTITION_IDENT
);
private final TableColumn nodesTableColumn;
@Inject
public SysShardsTableInfo(ClusterService service, SysNodesTableInfo sysNodesTableInfo) {
super(IDENT, new ColumnRegistrar(IDENT, RowGranularity.SHARD)
.register(Columns.SCHEMA_NAME, StringType.INSTANCE)
.register(Columns.TABLE_NAME, StringType.INSTANCE)
.register(Columns.ID, IntegerType.INSTANCE)
.register(Columns.PARTITION_IDENT, StringType.INSTANCE)
.register(Columns.NUM_DOCS, LongType.INSTANCE)
.register(Columns.PRIMARY, BooleanType.INSTANCE)
.register(Columns.RELOCATING_NODE, StringType.INSTANCE)
.register(Columns.SIZE, LongType.INSTANCE)
.register(Columns.STATE, StringType.INSTANCE)
.register(Columns.ROUTING_STATE, StringType.INSTANCE)
.register(Columns.ORPHAN_PARTITION, BooleanType.INSTANCE)
.register(Columns.RECOVERY, ObjectType.INSTANCE)
.register(Columns.RECOVERY_STAGE, StringType.INSTANCE)
.register(Columns.RECOVERY_TYPE, StringType.INSTANCE)
.register(Columns.RECOVERY_TOTAL_TIME, LongType.INSTANCE)
.register(Columns.RECOVERY_SIZE, ObjectType.INSTANCE)
.register(Columns.RECOVERY_SIZE_USED, LongType.INSTANCE)
.register(Columns.RECOVERY_SIZE_REUSED, LongType.INSTANCE)
.register(Columns.RECOVERY_SIZE_RECOVERED, LongType.INSTANCE)
.register(Columns.RECOVERY_SIZE_PERCENT, FloatType.INSTANCE)
.register(Columns.RECOVERY_FILES, ObjectType.INSTANCE)
.register(Columns.RECOVERY_FILES_USED, IntegerType.INSTANCE)
.register(Columns.RECOVERY_FILES_REUSED, IntegerType.INSTANCE)
.register(Columns.RECOVERY_FILES_RECOVERED, IntegerType.INSTANCE)
.register(Columns.RECOVERY_FILES_PERCENT, FloatType.INSTANCE)
.register(Columns.PATH, DataTypes.STRING)
.register(Columns.BLOB_PATH, DataTypes.STRING)
.register(Columns.MIN_LUCENE_VERSION, StringType.INSTANCE)
.putInfoOnly(SysNodesTableInfo.SYS_COL_IDENT, SysNodesTableInfo.tableColumnInfo(IDENT)),
PRIMARY_KEY);
this.service = service;
nodesTableColumn = sysNodesTableInfo.tableColumn();
}
@Override
public Reference getReference(ColumnIdent columnIdent) {
Reference info = super.getReference(columnIdent);
if (info == null) {
return nodesTableColumn.getReference(this.ident(), columnIdent);
}
return info;
}
private void processShardRouting(Map<String, Map<String, List<Integer>>> routing, ShardRouting shardRouting, ShardId shardId) {
String node;
int id;
String index = shardId.getIndex().getName();
if (shardRouting == null) {
node = service.localNode().getId();
id = UnassignedShard.markUnassigned(shardId.id());
} else {
node = shardRouting.currentNodeId();
id = shardRouting.id();
}
Map<String, List<Integer>> nodeMap = routing.get(node);
if (nodeMap == null) {
nodeMap = new TreeMap<>();
routing.put(node, nodeMap);
}
List<Integer> shards = nodeMap.get(index);
if (shards == null) {
shards = new ArrayList<>();
nodeMap.put(index, shards);
}
shards.add(id);
}
@Override
public RowGranularity rowGranularity() {
return RowGranularity.SHARD;
}
/**
* Retrieves the routing for sys.shards
* <p>
* This routing contains ALL shards of ALL indices.
* Any shards that are not yet assigned to a node will have a NEGATIVE shard id (see {@link UnassignedShard}
*/
@Override
public Routing getRouting(WhereClause whereClause, @Nullable String preference) {
// TODO: filter on whereClause
Map<String, Map<String, List<Integer>>> locations = new TreeMap<>();
ClusterState state = service.state();
String[] concreteIndices = state.metaData().getConcreteAllIndices();
GroupShardsIterator groupShardsIterator = state.getRoutingTable().allAssignedShardsGrouped(concreteIndices, true, true);
for (final ShardIterator shardIt : groupShardsIterator) {
final ShardRouting shardRouting = shardIt.nextOrNull();
processShardRouting(locations, shardRouting, shardIt.shardId());
}
return new Routing(locations);
}
}