/** * 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; 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 java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.hadoop.hdfs.protocol.LocatedBlock; import org.apache.hadoop.hdfs.protocol.LocatedBlocks; /** * Wrapper for LocatedBlocks with lock protection for concurrent updates. */ public class DFSLocatedBlocks extends LocatedBlocks { private volatile long fileLength = 0; // an optimization to get fileLength without locks private ReentrantReadWriteLock lock; public DFSLocatedBlocks(LocatedBlocks lbs) { super(lbs.getFileLength(), lbs.getLocatedBlocks(), lbs.isUnderConstruction()); this.fileLength = lbs.getFileLength(); lock = new ReentrantReadWriteLock(true); // fair } public DFSLocatedBlocks(long flength, List<LocatedBlock> blks, boolean isUnderConstuction) { super(flength, blks, isUnderConstuction); this.fileLength = flength; } /** * Get located blocks. */ public List<LocatedBlock> getLocatedBlocks() { readLock(); try { return super.getLocatedBlocks(); } finally { readUnlock(); } } /** * Get located block. */ public LocatedBlock get(int index) { readLock(); try { return super.get(index); } finally { readUnlock(); } } /** * Get number of located blocks. */ public int locatedBlockCount() { readLock(); try { return super.locatedBlockCount(); } finally { readUnlock(); } } /** * */ public long getFileLength() { return this.fileLength; } /** * Return ture if file was under construction when * this LocatedBlocks was constructed, false otherwise. */ public boolean isUnderConstruction() { readLock(); try { return super.isUnderConstruction(); } finally { readUnlock(); } } /** * Sets the file length of the file. */ public void setFileLength(long length) { writeLock(); try { super.setFileLength(length); this.fileLength = length; } finally { writeUnlock(); } } /** * Find block containing specified offset. * * @return block if found, or null otherwise. */ public int findBlock(long offset) { readLock(); try { return super.findBlock(offset); } finally { readUnlock(); } } public void insertRange(long offset, List<LocatedBlock> newBlocks) { writeLock(); try { // recheck if block is already in the cache. This has to be done // within the write lock, otherwise the insertion point could // have changed. int blockIdx = super.findBlock(offset); if (blockIdx < 0) { blockIdx = super.getInsertIndex(blockIdx); super.insertRange(blockIdx, newBlocks); } } finally { writeUnlock(); } } /** * Returns the block at exactly the given offset, if that block's location is * cached. * * @param offset the start offset of the block * @return the located block starting at the given offset or null if not * cached */ public LocatedBlock getBlockAt(long offset) { readLock(); try { int blockIdx = super.findBlock(offset); if (blockIdx < 0) return null; return super.getLocatedBlocks().get(blockIdx); } finally { readUnlock(); } } private void readLock() { lock.readLock().lock(); } private void readUnlock() { lock.readLock().unlock(); } private void writeLock() { lock.writeLock().lock(); } private void writeUnlock() { lock.writeLock().unlock(); } }