| /* |
| * 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); |
| } |
| } |