org.apache.hadoop.hdfs.protocol.LocatedBlocks.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.protocol.LocatedBlocks.java

Source

/**
 * 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.hadoop.hdfs.protocol;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import com.facebook.swift.codec.ThriftConstructor;
import com.facebook.swift.codec.ThriftField;
import com.facebook.swift.codec.ThriftStruct;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hdfs.DFSClient;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableFactories;
import org.apache.hadoop.io.WritableFactory;

/**
 * Collection of blocks with their locations and the file length.
 */
@ThriftStruct
public class LocatedBlocks implements Writable {
    public static final Log LOG = LogFactory.getLog(LocatedBlocks.class);
    private long fileLength;
    private List<LocatedBlock> blocks; // array of blocks with prioritized locations
    private boolean underConstruction;

    private static final Comparator<LocatedBlock> BLOCK_START_OFFSET_COMPARATOR = new Comparator<LocatedBlock>() {
        @Override
        public int compare(LocatedBlock a, LocatedBlock b) {
            long aBeg = a.getStartOffset();
            long bBeg = b.getStartOffset();
            if (aBeg < bBeg)
                return -1;
            if (aBeg > bBeg)
                return 1;
            return 0;
        }
    };

    public LocatedBlocks() {
        fileLength = 0;
        blocks = null;
        underConstruction = false;
    }

    @ThriftConstructor
    public LocatedBlocks(@ThriftField(1) long fileLength, @ThriftField(2) List<LocatedBlock> locatedBlocks,
            @ThriftField(3) boolean isUnderConstuction) {
        this.fileLength = fileLength;
        blocks = locatedBlocks;
        underConstruction = isUnderConstuction;
    }

    /** Shallow copy constructor */
    public <V extends LocatedBlocks> LocatedBlocks(V other) {
        this(other.getFileLength(), other.getLocatedBlocks(), other.isUnderConstruction());
    }

    /**
     * Get located blocks.
     */
    @ThriftField(2)
    public List<LocatedBlock> getLocatedBlocks() {
        return blocks;
    }

    /**
     * Get located block.
     */
    public LocatedBlock get(int index) {
        return blocks.get(index);
    }

    /**
     * Get number of located blocks.
     */
    public int locatedBlockCount() {
        return blocks == null ? 0 : blocks.size();
    }

    /**
     *
     */
    @ThriftField(1)
    public long getFileLength() {
        return this.fileLength;
    }

    /**
     * Return true if the file was under construction when
     * this LocatedBlocks was constructed, false otherwise.
     */
    @ThriftField(3)
    public boolean isUnderConstruction() {
        return underConstruction;
    }

    /**
     * Sets the file length of the file.
     */
    public void setFileLength(long length) {
        this.fileLength = length;
    }

    /**
     * If file is under construction, set block size of the last block. It updates
     * file length in the same time.
     */
    public synchronized void setLastBlockSize(long blockId, long blockSize) {
        assert blocks.size() > 0;
        LocatedBlock last = blocks.get(blocks.size() - 1);
        if (underConstruction && blockSize > last.getBlockSize()) {
            assert blockId == last.getBlock().getBlockId();
            this.setFileLength(this.getFileLength() + blockSize - last.getBlockSize());
            last.setBlockSize(blockSize);

            if (LOG.isDebugEnabled()) {
                LOG.debug("DFSClient setting last block " + last + " to length " + blockSize + " filesize is now "
                        + getFileLength());
            }
        }
    }

    /**
     * Find block containing the specified offset, or insertion point (encoded as
     * -i-1) of the given offset among starting offsets of the blocks if there is
     * no exact match. A nonnegative return value means an exact match.
     *
     * @return the index of the block starting with the given offset if there is
     *         an exact match, or <b>-i-1</b>, where i is is the insertion point
     *         of the given offset (as defined in
     *         {@link Collections#binarySearch(List, Object, Comparator)}).
     */
    protected int binarySearchBlockStartOffsets(long offset) {
        LocatedBlock key = new LocatedBlock();
        key.setStartOffset(offset);
        return Collections.binarySearch(blocks, key, BLOCK_START_OFFSET_COMPARATOR);
    }

    public void insertRange(List<LocatedBlock> newBlocks) {
        // Is there anything to insert?
        if (newBlocks.isEmpty())
            return;

        // Find where to start inserting the new blocks.
        final int insertIdx = getInsertIndex(binarySearchBlockStartOffsets(newBlocks.get(0).getStartOffset()));

        final List<LocatedBlock> oldBlocks = blocks; // for readability

        if (insertIdx >= oldBlocks.size()) {
            oldBlocks.addAll(newBlocks);
            return;
        }

        // Merged blocks from both old and new block arrays.
        List<LocatedBlock> mergedBlocks = new ArrayList<LocatedBlock>(newBlocks.size());

        int numOldBlocks = oldBlocks.size();
        int numNewBlocks = newBlocks.size();

        int oldIdx = insertIdx;
        int newIdx = 0;

        LocatedBlock oldBlk = oldBlocks.get(oldIdx);
        LocatedBlock newBlk = newBlocks.get(newIdx);

        long oldOff = oldBlk.getStartOffset();
        long newOff = newBlk.getStartOffset();

        // Merge newBlocks with a sub-list of oldBlocks.
        while (newIdx < numNewBlocks) {
            boolean advanceOld = false;
            boolean advanceNew = false;
            if (newOff <= oldOff) {
                // We always take the new block if two offsets are the same.
                mergedBlocks.add(newBlk);
                advanceOld = newOff == oldOff;
                advanceNew = true;
            } else {
                mergedBlocks.add(oldBlk);
                advanceOld = true;
            }

            if (advanceOld) {
                ++oldIdx;
                if (oldIdx < numOldBlocks) {
                    oldBlk = oldBlocks.get(oldIdx);
                    oldOff = oldBlk.getStartOffset();
                } else {
                    oldBlk = null;
                    oldOff = Long.MAX_VALUE;
                }
            }

            if (advanceNew) {
                ++newIdx;
                if (newIdx < numNewBlocks) {
                    newBlk = newBlocks.get(newIdx);
                    newOff = newBlk.getStartOffset();
                }
                // otherwise, we will break out of the loop
            }
        }

        // We have finished our merge of the sublist of the old blocks array
        // starting from insertIdx (inclusive) to the current value of oldIdx
        // (exclusive) with newBlocks. Now replace that sublist with the new merged
        // sublist.

        List<LocatedBlock> subList = oldBlocks.subList(insertIdx, oldIdx);
        subList.clear();
        subList.addAll(mergedBlocks);
    }

    public static int getInsertIndex(int binSearchResult) {
        return binSearchResult >= 0 ? binSearchResult : -(binSearchResult + 1);
    }

    //////////////////////////////////////////////////
    // Writable
    //////////////////////////////////////////////////
    static { // register a ctor
        WritableFactories.setFactory(LocatedBlocks.class, new WritableFactory() {
            public Writable newInstance() {
                return new LocatedBlocks();
            }
        });
    }

    public void write(DataOutput out) throws IOException {
        out.writeLong(this.fileLength);
        out.writeBoolean(underConstruction);
        // write located blocks
        int nrBlocks = locatedBlockCount();
        out.writeInt(nrBlocks);
        if (nrBlocks == 0) {
            return;
        }
        for (LocatedBlock blk : this.blocks) {
            blk.write(out);
        }
    }

    public void readFields(DataInput in) throws IOException {
        this.fileLength = in.readLong();
        underConstruction = in.readBoolean();
        // read located blocks
        int nrBlocks = in.readInt();
        this.blocks = new ArrayList<LocatedBlock>(nrBlocks);
        for (int idx = 0; idx < nrBlocks; idx++) {
            LocatedBlock blk = new LocatedBlock();
            blk.readFields(in);
            this.blocks.add(blk);
        }
    }

    @Override
    public String toString() {
        return getLocatedBlocks().toString();
    }

}