/* * 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.ignite.internal.processors.cache.distributed.dht.preloader; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import static org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState.MOVING; /** * Partition map. */ public class GridDhtPartitionMap implements Comparable<GridDhtPartitionMap>, Externalizable { /** */ private static final long serialVersionUID = 0L; /** Node ID. */ protected UUID nodeId; /** Update sequence number. */ protected long updateSeq; /** Topology version. */ protected AffinityTopologyVersion top; /** */ protected Map<Integer, GridDhtPartitionState> map; /** */ private volatile int moving; /** * Empty constructor required for {@link Externalizable}. */ public GridDhtPartitionMap() { // No-op. } /** * @param nodeId Node ID. * @param updateSeq Update sequence number. * @param top Topology version. * @param m Map to copy. * @param onlyActive If {@code true}, then only active states will be included. */ public GridDhtPartitionMap(UUID nodeId, long updateSeq, AffinityTopologyVersion top, Map<Integer, GridDhtPartitionState> m, boolean onlyActive) { assert nodeId != null; assert updateSeq > 0; this.nodeId = nodeId; this.updateSeq = updateSeq; this.top = top; map = U.newHashMap(m.size()); for (Map.Entry<Integer, GridDhtPartitionState> e : m.entrySet()) { GridDhtPartitionState state = e.getValue(); if (!onlyActive || state.active()) put(e.getKey(), state); } } /** * @param nodeId Node ID. * @param updateSeq Update sequence number. * @param top Topology version. * @param map Map. * @param moving Number of moving partitions. */ private GridDhtPartitionMap(UUID nodeId, long updateSeq, AffinityTopologyVersion top, Map<Integer, GridDhtPartitionState> map, int moving) { this.nodeId = nodeId; this.updateSeq = updateSeq; this.top = top; this.map = map; this.moving = moving; } /** * @return Copy with empty partition state map. */ public GridDhtPartitionMap emptyCopy() { return new GridDhtPartitionMap(nodeId, updateSeq, top, U.<Integer, GridDhtPartitionState>newHashMap(0), 0); } /** * @param part Partition. * @param state Partition state. */ public void put(Integer part, GridDhtPartitionState state) { GridDhtPartitionState old = map.put(part, state); if (old == MOVING) moving--; if (state == MOVING) moving++; } /** * @return {@code true} If partition map contains moving partitions. */ public boolean hasMovingPartitions() { assert moving >= 0 : moving; return moving != 0; } /** * @param part Partition. * @return Partition state. */ public GridDhtPartitionState get(Integer part) { return map.get(part); } /** * @param part Partition. * @return {@code True} if contains given partition. */ public boolean containsKey(Integer part) { return map.containsKey(part); } /** * @return Entries. */ public Set<Map.Entry<Integer, GridDhtPartitionState>> entrySet() { return map.entrySet(); } /** * @return Map size. */ public int size() { return map.size(); } /** * @return Partitions. */ public Set<Integer> keySet() { return map.keySet(); } /** * @return Underlying map. */ public Map<Integer, GridDhtPartitionState> map() { return map; } /** * @return Node ID. */ public UUID nodeId() { return nodeId; } /** * @return Update sequence. */ public long updateSequence() { return updateSeq; } /** * @param updateSeq New update sequence value. * @param topVer Current topology version. * @return Old update sequence value. */ public long updateSequence(long updateSeq, AffinityTopologyVersion topVer) { long old = this.updateSeq; assert updateSeq >= old : "Invalid update sequence [cur=" + old + ", new=" + updateSeq + ']'; this.updateSeq = updateSeq; top = topVer; return old; } /** * @return Topology version. */ public AffinityTopologyVersion topologyVersion() { return top; } /** {@inheritDoc} */ @Override public int compareTo(GridDhtPartitionMap o) { assert nodeId.equals(o.nodeId); return Long.compare(updateSeq, o.updateSeq); } /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { U.writeUuid(out, nodeId); out.writeLong(updateSeq); int size = map.size(); out.writeInt(size); int i = 0; for (Map.Entry<Integer, GridDhtPartitionState> entry : map.entrySet()) { int ordinal = entry.getValue().ordinal(); assert ordinal == (ordinal & 0x7); assert entry.getKey() < CacheConfiguration.MAX_PARTITIONS_COUNT : entry.getKey(); out.writeByte(ordinal); out.writeShort(entry.getKey()); i++; } assert i == size; if (top != null) { out.writeLong(topologyVersion().topologyVersion()); out.writeInt(topologyVersion().minorTopologyVersion()); } else { out.writeLong(0); out.writeInt(0); } } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { nodeId = U.readUuid(in); updateSeq = in.readLong(); int size = in.readInt(); map = U.newHashMap(size); for (int i = 0; i < size; i++) { int ordinal = in.readByte(); int part = in.readShort(); put(part, GridDhtPartitionState.fromOrdinal(ordinal)); } long ver = in.readLong(); int minorVer = in.readInt(); if (ver != 0) top = new AffinityTopologyVersion(ver, minorVer); } /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; GridDhtPartitionMap other = (GridDhtPartitionMap)o; return other.nodeId.equals(nodeId) && other.updateSeq == updateSeq; } /** {@inheritDoc} */ @Override public int hashCode() { return 31 * nodeId.hashCode() + (int)(updateSeq ^ (updateSeq >>> 32)); } /** * @return Full string representation. */ public String toFullString() { return S.toString(GridDhtPartitionMap.class, this, "size", size(), "map", map.toString(), "top", top); } /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtPartitionMap.class, this, "size", size()); } }