/*
* 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.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.GridDirectMap;
import org.apache.ignite.internal.GridDirectTransient;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Information about partitions of all nodes in topology.
*/
public class GridDhtPartitionsFullMessage extends GridDhtPartitionsAbstractMessage {
/** */
private static final long serialVersionUID = 0L;
/** */
@GridToStringInclude
@GridDirectTransient
private Map<Integer, GridDhtPartitionFullMap> parts;
/** */
@GridDirectMap(keyType = Integer.class, valueType = Integer.class)
private Map<Integer, Integer> dupPartsData;
/** */
private byte[] partsBytes;
/** Partitions update counters. */
@GridToStringInclude
@GridDirectTransient
private Map<Integer, Map<Integer, T2<Long, Long>>> partCntrs;
/** Serialized partitions counters. */
private byte[] partCntrsBytes;
/** Topology version. */
private AffinityTopologyVersion topVer;
/** Exceptions. */
@GridToStringInclude
@GridDirectTransient
private Map<UUID, Exception> exs;
/** */
private byte[] exsBytes;
/** */
@GridDirectTransient
private transient boolean compress;
/**
* Required by {@link Externalizable}.
*/
public GridDhtPartitionsFullMessage() {
// No-op.
}
/**
* @param id Exchange ID.
* @param lastVer Last version.
* @param topVer Topology version.
*/
public GridDhtPartitionsFullMessage(@Nullable GridDhtPartitionExchangeId id,
@Nullable GridCacheVersion lastVer,
@NotNull AffinityTopologyVersion topVer) {
super(id, lastVer);
assert id == null || topVer.equals(id.topologyVersion());
this.topVer = topVer;
}
/**
* @param compress {@code True} if it is possible to use compression for message.
*/
public void compress(boolean compress) {
this.compress = compress;
}
/**
* @return Local partitions.
*/
public Map<Integer, GridDhtPartitionFullMap> partitions() {
if (parts == null)
parts = new HashMap<>();
return parts;
}
/**
* @param cacheId Cache ID.
* @return {@code True} if message contains full map for given cache.
*/
public boolean containsCache(int cacheId) {
return parts != null && parts.containsKey(cacheId);
}
/**
* @param cacheId Cache ID.
* @param fullMap Full partitions map.
* @param dupDataCache Optional ID of cache with the same partition state map.
*/
public void addFullPartitionsMap(int cacheId, GridDhtPartitionFullMap fullMap, @Nullable Integer dupDataCache) {
if (parts == null)
parts = new HashMap<>();
if (!parts.containsKey(cacheId)) {
parts.put(cacheId, fullMap);
if (dupDataCache != null) {
assert compress;
assert parts.containsKey(dupDataCache);
if (dupPartsData == null)
dupPartsData = new HashMap<>();
dupPartsData.put(cacheId, dupDataCache);
}
}
}
/**
* @param cacheId Cache ID.
* @param cntrMap Partition update counters.
*/
public void addPartitionUpdateCounters(int cacheId, Map<Integer, T2<Long, Long>> cntrMap) {
if (partCntrs == null)
partCntrs = new HashMap<>();
if (!partCntrs.containsKey(cacheId))
partCntrs.put(cacheId, cntrMap);
}
/**
* @param cacheId Cache ID.
* @return Partition update counters.
*/
@Override public Map<Integer, T2<Long, Long>> partitionUpdateCounters(int cacheId) {
if (partCntrs != null) {
Map<Integer, T2<Long, Long>> res = partCntrs.get(cacheId);
return res != null ? res : Collections.<Integer, T2<Long, Long>>emptyMap();
}
return Collections.emptyMap();
}
/**
*
*/
public Map<UUID, Exception> getExceptionsMap() {
return exs;
}
/**
* @param exs Exs.
*/
public void setExceptionsMap(Map<UUID, Exception> exs) {
this.exs = new HashMap<>(exs);
}
/** {@inheritDoc} */
@Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException {
super.prepareMarshal(ctx);
boolean marshal = (parts != null && partsBytes == null) ||
(partCntrs != null && partCntrsBytes == null) ||
(exs != null && exsBytes == null);
if (marshal) {
byte[] partsBytes0 = null;
byte[] partCntrsBytes0 = null;
byte[] exsBytes0 = null;
if (parts != null && partsBytes == null)
partsBytes0 = U.marshal(ctx, parts);
if (partCntrs != null && partCntrsBytes == null)
partCntrsBytes0 = U.marshal(ctx, partCntrs);
if (exs != null && exsBytes == null)
exsBytes0 = U.marshal(ctx, exs);
if (compress) {
assert !compressed();
try {
byte[] partsBytesZip = U.zip(partsBytes0);
byte[] partCntrsBytesZip = U.zip(partCntrsBytes0);
byte[] exsBytesZip = U.zip(exsBytes0);
partsBytes0 = partsBytesZip;
partCntrsBytes0 = partCntrsBytesZip;
exsBytes0 = exsBytesZip;
compressed(true);
}
catch (IgniteCheckedException e) {
U.error(ctx.logger(getClass()), "Failed to compress partitions data: " + e, e);
}
}
partsBytes = partsBytes0;
partCntrsBytes = partCntrsBytes0;
exsBytes = exsBytes0;
}
}
/**
* @return Topology version.
*/
@Override public AffinityTopologyVersion topologyVersion() {
return topVer;
}
/**
* @param topVer Topology version.
*/
public void topologyVersion(AffinityTopologyVersion topVer) {
this.topVer = topVer;
}
/** {@inheritDoc} */
@Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException {
super.finishUnmarshal(ctx, ldr);
if (partsBytes != null && parts == null) {
if (compressed())
parts = U.unmarshalZip(ctx.marshaller(), partsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
parts = U.unmarshal(ctx, partsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
if (dupPartsData != null) {
assert parts != null;
for (Map.Entry<Integer, Integer> e : dupPartsData.entrySet()) {
GridDhtPartitionFullMap map1 = parts.get(e.getKey());
GridDhtPartitionFullMap map2 = parts.get(e.getValue());
assert map1 != null : e.getKey();
assert map2 != null : e.getValue();
assert map1.size() == map2.size();
for (Map.Entry<UUID, GridDhtPartitionMap> e0 : map2.entrySet()) {
GridDhtPartitionMap partMap1 = map1.get(e0.getKey());
assert partMap1 != null && partMap1.map().isEmpty() : partMap1;
assert !partMap1.hasMovingPartitions() : partMap1;
GridDhtPartitionMap partMap2 = e0.getValue();
assert partMap2 != null;
for (Map.Entry<Integer, GridDhtPartitionState> stateEntry : partMap2.entrySet())
partMap1.put(stateEntry.getKey(), stateEntry.getValue());
}
}
}
}
if (parts == null)
parts = new HashMap<>();
if (partCntrsBytes != null && partCntrs == null) {
if (compressed())
partCntrs = U.unmarshalZip(ctx.marshaller(), partCntrsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
partCntrs = U.unmarshal(ctx, partCntrsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
}
if (partCntrs == null)
partCntrs = new HashMap<>();
if (exsBytes != null && exs == null){
if (compressed())
exs = U.unmarshalZip(ctx.marshaller(), exsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
exs = U.unmarshal(ctx, exsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
}
if (exs == null)
exs = new HashMap<>();
}
/** {@inheritDoc} */
@Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
writer.setBuffer(buf);
if (!super.writeTo(buf, writer))
return false;
if (!writer.isHeaderWritten()) {
if (!writer.writeHeader(directType(), fieldsCount()))
return false;
writer.onHeaderWritten();
}
switch (writer.state()) {
case 6:
if (!writer.writeMap("dupPartsData", dupPartsData, MessageCollectionItemType.INT, MessageCollectionItemType.INT))
return false;
writer.incrementState();
case 7:
if (!writer.writeByteArray("exsBytes", exsBytes))
return false;
writer.incrementState();
case 8:
if (!writer.writeByteArray("partCntrsBytes", partCntrsBytes))
return false;
writer.incrementState();
case 9:
if (!writer.writeByteArray("partsBytes", partsBytes))
return false;
writer.incrementState();
case 10:
if (!writer.writeMessage("topVer", topVer))
return false;
writer.incrementState();
}
return true;
}
/** {@inheritDoc} */
@Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
reader.setBuffer(buf);
if (!reader.beforeMessageRead())
return false;
if (!super.readFrom(buf, reader))
return false;
switch (reader.state()) {
case 6:
dupPartsData = reader.readMap("dupPartsData", MessageCollectionItemType.INT, MessageCollectionItemType.INT, false);
if (!reader.isLastRead())
return false;
reader.incrementState();
case 7:
exsBytes = reader.readByteArray("exsBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 8:
partCntrsBytes = reader.readByteArray("partCntrsBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 9:
partsBytes = reader.readByteArray("partsBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 10:
topVer = reader.readMessage("topVer");
if (!reader.isLastRead())
return false;
reader.incrementState();
}
return reader.afterMessageRead(GridDhtPartitionsFullMessage.class);
}
/** {@inheritDoc} */
@Override public short directType() {
return 46;
}
//todo
/** {@inheritDoc} */
@Override public byte fieldsCount() {
return 11;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridDhtPartitionsFullMessage.class, this, "partCnt", parts != null ? parts.size() : 0,
"super", super.toString());
}
}