package cassandra.metadata;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CopyOnWriteArrayList;
import static io.netty.util.internal.PlatformDependent.newConcurrentHashMap;
public abstract class Metadata extends MetadataEntity {
private static final ColumnComparator COLUMN_COMPARATOR = new ColumnComparator();
private static final Iterator<Map.Entry<Partitioner.Token, InetAddress>> EMPTY_RING_ITERATOR = Collections.<Map.Entry<Partitioner.Token, InetAddress>>emptyList().iterator();
private InetAddress local;
private String clusterName;
private String partitioner;
private final ConcurrentMap<InetAddress, PeerMetadata> peers;
private final ConcurrentMap<String, KeyspaceMetadata> keyspaces;
private final ConcurrentMap<String, ConcurrentMap<String, TableMetadata>> tables;
private final ConcurrentMap<String, ConcurrentMap<String, ColumnMetadata>> columns;
private final ConcurrentMap<String, CopyOnWriteArrayList<InetAddress>> dc2Endpoints;
private final ConcurrentMap<String, ConcurrentMap<String, CopyOnWriteArrayList<InetAddress>>> rack2Endpoints;
private final ConcurrentSkipListMap<Partitioner.Token, InetAddress> tokenring;
protected Metadata() {
peers = newConcurrentHashMap();
keyspaces = newConcurrentHashMap();
tables = newConcurrentHashMap();
columns = newConcurrentHashMap();
dc2Endpoints = newConcurrentHashMap();
rack2Endpoints = newConcurrentHashMap();
tokenring = new ConcurrentSkipListMap<Partitioner.Token, InetAddress>();
}
@JsonIgnore
protected InetAddress getLocal() {
return local;
}
protected void setLocal(InetAddress local) {
this.local = local;
}
public String getClusterName() {
return clusterName;
}
protected void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
@JsonProperty("partitioner")
public String getPartitionerClass() {
return partitioner;
}
@JsonIgnore
public Partitioner getPartitioner() {
return Partitioner.getPartitioner(partitioner);
}
protected void setPartitioner(String partitioner) {
this.partitioner = partitioner;
}
@JsonProperty("data_center")
public String getDatacenter() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getDatacenter();
}
public String getRack() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getRack();
}
public UUID getHostId() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getHostId();
}
public UUID getSchemaVersion() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getSchemaVersion();
}
@JsonIgnore
public Set<String> getTokens() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getTokens();
}
public String getReleaseVersion() {
if (!hasPeer(local)) {
return null;
}
return getPeer(local).getReleaseVersion();
}
@JsonIgnore
public Map<String, CopyOnWriteArrayList<InetAddress>> getDatacenterEndpoints() {
return dc2Endpoints;
}
@JsonIgnore
public Map<String, ConcurrentMap<String, CopyOnWriteArrayList<InetAddress>>> getDatacenterRacks() {
return rack2Endpoints;
}
@JsonIgnore
public Iterator<Map.Entry<Partitioner.Token, InetAddress>> getRingIterator(Partitioner.Token start) {
if (tokenring.isEmpty()) {
return EMPTY_RING_ITERATOR;
}
Partitioner.Token startToken = tokenring.ceilingKey(start);
if (startToken == null) {
startToken = tokenring.firstKey();
}
return tokenring.tailMap(startToken).entrySet().iterator();
}
@JsonIgnore
public int getRingSize() {
return tokenring.size();
}
@JsonIgnore
public List<PeerMetadata> getPeers() {
return new ArrayList<PeerMetadata>(peers.values());
}
@JsonIgnore
public boolean hasPeer(InetAddress endpoint) {
return getPeer(endpoint) != null;
}
@JsonIgnore
public PeerMetadata getPeer(InetAddress endpoint) {
return peers.get(endpoint);
}
protected void addPeer(PeerMetadata peer) {
peers.put(peer.getAddress(), peer);
if (peer.hasDatacenter()) {
CopyOnWriteArrayList<InetAddress> dc2EndpointList = dc2Endpoints.get(peer.getDatacenter());
if (dc2EndpointList == null) {
CopyOnWriteArrayList<InetAddress> newDc2EndpointList = new CopyOnWriteArrayList<InetAddress>();
dc2EndpointList = dc2Endpoints.putIfAbsent(peer.getDatacenter(), newDc2EndpointList);
if (dc2EndpointList == null) {
dc2EndpointList = newDc2EndpointList;
}
}
dc2EndpointList.addIfAbsent(peer.getAddress());
if (peer.hasRack()) {
ConcurrentMap<String, CopyOnWriteArrayList<InetAddress>> rack2EndpointMap = rack2Endpoints.get(peer.getDatacenter());
if (rack2EndpointMap == null) {
ConcurrentMap<String, CopyOnWriteArrayList<InetAddress>> newRack2EndpointMap = newConcurrentHashMap();
rack2EndpointMap = rack2Endpoints.putIfAbsent(peer.getDatacenter(), newRack2EndpointMap);
if (rack2EndpointMap == null) {
rack2EndpointMap = newRack2EndpointMap;
}
}
CopyOnWriteArrayList<InetAddress> rack2EndpointList = rack2EndpointMap.get(peer.getRack());
if (rack2EndpointList == null) {
CopyOnWriteArrayList<InetAddress> newRack2EndpointList = new CopyOnWriteArrayList<InetAddress>();
rack2EndpointList = rack2EndpointMap.putIfAbsent(peer.getRack(), newRack2EndpointList);
if (rack2EndpointList == null) {
rack2EndpointList = newRack2EndpointList;
}
}
rack2EndpointList.add(peer.getAddress());
}
}
for (String tokenString : peer.getTokens()) {
Partitioner partitioner = getPartitioner();
if (partitioner != null) {
Partitioner.Token token = partitioner.getToken(tokenString);
tokenring.put(token, peer.getAddress());
}
}
}
protected void setPeerAsUp(InetAddress endpoint) {
PeerMetadata peer = peers.get(endpoint);
if (peer != null && peer.isDown()) {
PeerMetadata up = PeerMetadata.newBuilder().mergeFrom(peer).setDown(false).build();
peers.put(endpoint, up);
}
}
protected void setPeerAsDown(InetAddress endpoint) {
PeerMetadata peer = peers.get(endpoint);
if (peer != null && peer.isUp()) {
PeerMetadata down = PeerMetadata.newBuilder().mergeFrom(peer).setDown(true).build();
peers.put(endpoint, down);
}
}
protected void removePeer(InetAddress endpoint) {
peers.remove(endpoint);
for (List<InetAddress> endpoints : dc2Endpoints.values()) {
endpoints.remove(endpoint);
}
for (Map<String, CopyOnWriteArrayList<InetAddress>> map : rack2Endpoints.values()) {
for (List<InetAddress> endpoints : map.values()) {
endpoints.remove(endpoint);
}
}
Iterator<InetAddress> iterator = tokenring.values().iterator();
while (iterator.hasNext()) {
InetAddress ep = iterator.next();
if (endpoint.equals(ep)) {
iterator.remove();
}
}
}
@JsonIgnore
public List<KeyspaceMetadata> getKeyspaces() {
return new ArrayList<KeyspaceMetadata>(keyspaces.values());
}
@JsonIgnore
public boolean hasKeyspace(String keyspace) {
return getKeyspace(keyspace) != null;
}
@JsonIgnore
public KeyspaceMetadata getKeyspace(String keyspace) {
return keyspaces.get(keyspace);
}
protected void addKeyspace(KeyspaceMetadata keyspace) {
keyspaces.put(keyspace.getName(), keyspace);
}
protected void removeKeyspace(String keyspace) {
keyspaces.remove(keyspace);
tables.remove(keyspace);
}
@JsonIgnore
public List<TableMetadata> getTables() {
List<TableMetadata> list = new ArrayList<TableMetadata>();
for (Map<String, TableMetadata> map : tables.values()) {
list.addAll(map.values());
}
return list;
}
@JsonIgnore
public List<TableMetadata> getTables(String keyspace) {
Map<String, TableMetadata> map = tables.get(keyspace);
if (map == null) {
return Collections.emptyList();
}
return new ArrayList<TableMetadata>(map.values());
}
@JsonIgnore
public boolean hasTable(String keyspace, String table) {
return getTable(keyspace, table) != null;
}
@JsonIgnore
public TableMetadata getTable(String keyspace, String table) {
Map<String, TableMetadata> map = tables.get(keyspace);
if (map == null) {
return null;
}
return map.get(table);
}
protected void addTable(TableMetadata table) {
String keyspace = table.getKeyspaceName();
if (hasKeyspace(keyspace)) {
Map<String, TableMetadata> map = tables.get(keyspace);
if (map == null) {
ConcurrentMap<String, TableMetadata> newmap = newConcurrentHashMap();
map = tables.putIfAbsent(keyspace, newmap);
if (map == null) {
map = newmap;
}
}
map.put(table.getName(), table);
}
}
protected void removeTable(String keyspace, String table) {
Map<String, TableMetadata> map = tables.get(keyspace);
if (map != null) {
map.remove(table);
}
removeColumns(keyspace, table);
}
@JsonIgnore
public List<ColumnMetadata> getColumns(String keyspace, String table) {
Map<String, ColumnMetadata> map = columns.get(globalTable(keyspace, table));
if (map == null) {
return Collections.emptyList();
}
List<ColumnMetadata> list = new ArrayList<ColumnMetadata>(map.values());
Collections.sort(list, COLUMN_COMPARATOR);
return list;
}
@JsonIgnore
public boolean hasColumn(String keyspace, String table, String column) {
return getColumn(keyspace, table, column) != null;
}
@JsonIgnore
public ColumnMetadata getColumn(String keyspace, String table, String column) {
Map<String, ColumnMetadata> map = columns.get(globalTable(keyspace, table));
if (map == null) {
return null;
}
return map.get(column);
}
protected void addColumn(ColumnMetadata column) {
String keyspace = column.getKeyspace();
String table = column.getTable();
if (hasTable(keyspace, table)) {
String globalTalble = globalTable(keyspace, table);
Map<String, ColumnMetadata> map = columns.get(globalTalble);
if (map == null) {
ConcurrentMap<String, ColumnMetadata> newmap = newConcurrentHashMap();
map = columns.putIfAbsent(globalTalble, newmap);
if (map == null) {
map = newmap;
}
}
map.put(column.getName(), column);
}
}
protected void addColumns(ColumnMetadata... columns) {
for (ColumnMetadata column : columns) {
addColumn(column);
}
}
protected void removeColumn(String keyspace, String table, String column) {
String globalTable = globalTable(keyspace, table);
Map<String, ColumnMetadata> map = columns.get(globalTable);
if (map != null) {
map.remove(column);
}
}
protected void removeColumns(String keyspace, String table) {
columns.remove(globalTable(keyspace, table));
}
protected void clear() {
local = null;
clusterName = null;
partitioner = null;
peers.clear();
keyspaces.clear();
tables.clear();
columns.clear();
dc2Endpoints.clear();
rack2Endpoints.clear();
tokenring.clear();
}
protected static String globalTable(String keyspace, String table) {
return String.format("%s.%s", keyspace, table);
}
private static class ColumnComparator implements Comparator<ColumnMetadata> {
@Override
public int compare(ColumnMetadata c1, ColumnMetadata c2) {
return ColumnMetadata.compareTo(c1, c2);
}
}
}