/* * 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.igfs; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.apache.ignite.binary.BinaryObjectException; import org.apache.ignite.binary.BinaryRawReader; import org.apache.ignite.binary.BinaryRawWriter; import org.apache.ignite.binary.BinaryReader; import org.apache.ignite.binary.BinaryWriter; import org.apache.ignite.binary.Binarylizable; import org.apache.ignite.internal.binary.BinaryUtils; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageWriter; import org.jetbrains.annotations.Nullable; /** * Affinity range. */ public class IgfsFileAffinityRange implements Message, Externalizable, Binarylizable { /** */ private static final long serialVersionUID = 0L; /** Initial range status, right after creation. */ public static final int RANGE_STATUS_INITIAL = 0; /** Moving range state. Fragmentizer started blocks copy. */ public static final int RANGE_STATUS_MOVING = 1; /** Fragmentizer finished block copy for this range. */ public static final int RANGE_STATUS_MOVED = 2; /** Range affinity key. */ private IgniteUuid affKey; /** {@code True} if currently being moved by fragmentizer. */ @SuppressWarnings("RedundantFieldInitialization") private int status = RANGE_STATUS_INITIAL; /** Range start offset (divisible by block size). */ private long startOff; /** Range end offset (endOff + 1 divisible by block size). */ private long endOff; /** Field kept for backward compatibility. */ private boolean done; /** * Empty constructor required by {@link Externalizable}. */ public IgfsFileAffinityRange() { // No-op. } /** * @param startOff Start offset. * @param endOff End offset. * @param affKey Affinity key. */ IgfsFileAffinityRange(long startOff, long endOff, IgniteUuid affKey) { this.startOff = startOff; this.endOff = endOff; this.affKey = affKey; } /** * Creates new range with updated status. * * @param other Initial range. * @param status Updated status. */ IgfsFileAffinityRange(IgfsFileAffinityRange other, int status) { startOff = other.startOff; endOff = other.endOff; affKey = other.affKey; this.status = status; } /** * @return Affinity key for this range. */ public IgniteUuid affinityKey() { return affKey; } /** * @return Range start offset. */ public long startOffset() { return startOff; } /** * @return Range end offset. */ public long endOffset() { return endOff; } /** * @param blockStartOff Block start offset to check. * @return {@code True} if block with given start offset belongs to this range. */ public boolean belongs(long blockStartOff) { return blockStartOff >= startOff && blockStartOff < endOff; } /** * @param blockStartOff Block start offset to check. * @return {@code True} if block with given start offset is located before this range. */ public boolean less(long blockStartOff) { return blockStartOff < startOff; } /** * @param blockStartOff Block start offset to check. * @return {@code True} if block with given start offset is located after this range. */ public boolean greater(long blockStartOff) { return blockStartOff > endOff; } /** * @return If range is empty, i.e. has zero length. */ public boolean empty() { return startOff == endOff; } /** * @return Range status. */ public int status() { return status; } /** * Expands this range by given block. * * @param blockStartOff Offset of block start. * @param expansionSize Block size. */ public void expand(long blockStartOff, int expansionSize) { // If we are expanding empty range. if (endOff == startOff) { assert endOff == blockStartOff : "Failed to expand range [endOff=" + endOff + ", blockStartOff=" + blockStartOff + ", expansionSize=" + expansionSize + ']'; endOff += expansionSize - 1; } else { assert endOff == blockStartOff - 1; endOff += expansionSize; } } /** * Splits range into collection if smaller ranges with length equal to {@code maxSize}. * * @param maxSize Split part maximum size. * @return Collection of range parts. */ public Collection<IgfsFileAffinityRange> split(long maxSize) { long len = endOff - startOff + 1; if (len > maxSize) { int size = (int)(len / maxSize + 1); Collection<IgfsFileAffinityRange> res = new ArrayList<>(size); long pos = startOff; while (pos < endOff + 1) { long end = Math.min(pos + maxSize - 1, endOff); IgfsFileAffinityRange part = new IgfsFileAffinityRange(pos, end, affKey); part.status = status; res.add(part); pos = end + 1; } return res; } else return Collections.singletonList(this); } /** * Tries to concatenate this range with a given one. If ranges are not adjacent, will return {@code null}. * * @param range Range to concatenate with. * @return Concatenation result or {@code null} if ranges are not adjacent. */ @Nullable public IgfsFileAffinityRange concat(IgfsFileAffinityRange range) { if (endOff + 1 != range.startOff || !F.eq(affKey, range.affKey) || status != RANGE_STATUS_INITIAL) return null; return new IgfsFileAffinityRange(startOff, range.endOff, affKey); } /** * Checks if range regions are equal. * * @param other Other range to check against. * @return {@code True} if range regions are equal. */ public boolean regionEqual(IgfsFileAffinityRange other) { return startOff == other.startOff && endOff == other.endOff; } /** {@inheritDoc} */ @Override public void onAckReceived() { // No-op. } /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { U.writeGridUuid(out, affKey); out.writeInt(status); out.writeLong(startOff); out.writeLong(endOff); } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { affKey = U.readGridUuid(in); status = in.readInt(); startOff = in.readLong(); endOff = in.readLong(); } /** {@inheritDoc} */ @Override public void writeBinary(BinaryWriter writer) throws BinaryObjectException { writeRawBinary(writer.rawWriter()); } /** {@inheritDoc} */ @Override public void readBinary(BinaryReader reader) throws BinaryObjectException { readRawBinary(reader.rawReader()); } /** * Writes fields to provided writer. * * @param writer Writer. * @throws BinaryObjectException If fails. */ public void writeRawBinary(BinaryRawWriter writer) throws BinaryObjectException { BinaryUtils.writeIgniteUuid(writer, affKey); writer.writeInt(status); writer.writeLong(startOff); writer.writeLong(endOff); } /** * Reads fields from provided reader. * * @param reader Reader. * @throws BinaryObjectException If fails. */ public void readRawBinary(BinaryRawReader reader) throws BinaryObjectException { affKey = BinaryUtils.readIgniteUuid(reader); status = reader.readInt(); startOff = reader.readLong(); endOff = reader.readLong(); } /** {@inheritDoc} */ @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) { writer.setBuffer(buf); if (!writer.isHeaderWritten()) { if (!writer.writeHeader(directType(), fieldsCount())) return false; writer.onHeaderWritten(); } switch (writer.state()) { case 0: if (!writer.writeIgniteUuid("affKey", affKey)) return false; writer.incrementState(); case 1: if (!writer.writeBoolean("done", done)) return false; writer.incrementState(); case 2: if (!writer.writeLong("endOff", endOff)) return false; writer.incrementState(); case 3: if (!writer.writeLong("startOff", startOff)) return false; writer.incrementState(); case 4: if (!writer.writeInt("status", status)) return false; writer.incrementState(); } return true; } /** {@inheritDoc} */ @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) { reader.setBuffer(buf); if (!reader.beforeMessageRead()) return false; switch (reader.state()) { case 0: affKey = reader.readIgniteUuid("affKey"); if (!reader.isLastRead()) return false; reader.incrementState(); case 1: done = reader.readBoolean("done"); if (!reader.isLastRead()) return false; reader.incrementState(); case 2: endOff = reader.readLong("endOff"); if (!reader.isLastRead()) return false; reader.incrementState(); case 3: startOff = reader.readLong("startOff"); if (!reader.isLastRead()) return false; reader.incrementState(); case 4: status = reader.readInt("status"); if (!reader.isLastRead()) return false; reader.incrementState(); } return reader.afterMessageRead(IgfsFileAffinityRange.class); } /** {@inheritDoc} */ @Override public short directType() { return 68; } /** {@inheritDoc} */ @Override public byte fieldsCount() { return 5; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(IgfsFileAffinityRange.class, this); } }