/* * 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 tachyon.master; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.databind.ObjectWriter; import tachyon.Pair; import tachyon.thrift.BlockInfoException; import tachyon.thrift.ClientBlockInfo; import tachyon.thrift.ClientFileInfo; import tachyon.thrift.NetAddress; import tachyon.thrift.SuspectedFileSizeException; /** * Tachyon file system's file representation in master. */ public class InodeFile extends Inode { /** * Create a new InodeFile from an image JSON element * * @param ele * the image JSON element * @return the created inode file. * @throws IOException */ static InodeFile loadImage(ImageElement ele) throws IOException { long creationTimeMs = ele.getLong("creationTimeMs"); int fileId = ele.getInt("id"); String fileName = ele.getString("name"); int parentId = ele.getInt("parentId"); long blockSizeByte = ele.getLong("blockSizeByte"); long length = ele.getLong("length"); boolean isComplete = ele.getBoolean("complete"); boolean isPinned = ele.getBoolean("pin"); boolean isCache = ele.getBoolean("cache"); String ufsPath = ele.getString("ufsPath"); int dependencyId = ele.getInt("depId"); InodeFile inode = new InodeFile(fileName, fileId, parentId, blockSizeByte, creationTimeMs); try { inode.setLength(length); } catch (Exception e) { throw new IOException(e); } inode.setComplete(isComplete); inode.setPinned(isPinned); inode.setCache(isCache); inode.setUfsPath(ufsPath); inode.setDependencyId(dependencyId); return inode; } private final long BLOCK_SIZE_BYTE; private long mLength = 0; private boolean mIsComplete = false; private boolean mCache = false; private String mUfsPath = ""; private List<BlockInfo> mBlocks = new ArrayList<BlockInfo>(3); private int mDependencyId; public InodeFile(String name, int id, int parentId, long blockSizeByte, long creationTimeMs) { super(name, id, parentId, false, creationTimeMs); BLOCK_SIZE_BYTE = blockSizeByte; mDependencyId = -1; } public synchronized void addBlock(BlockInfo blockInfo) throws BlockInfoException { if (mIsComplete) { throw new BlockInfoException("The file is complete: " + this); } if (mBlocks.size() > 0 && mBlocks.get(mBlocks.size() - 1).LENGTH != BLOCK_SIZE_BYTE) { throw new BlockInfoException("BLOCK_SIZE_BYTE is " + BLOCK_SIZE_BYTE + ", but the " + "previous block size is " + mBlocks.get(mBlocks.size() - 1).LENGTH); } if (blockInfo.getInodeFile() != this) { throw new BlockInfoException("InodeFile unmatch: " + this + " != " + blockInfo); } if (blockInfo.BLOCK_INDEX != mBlocks.size()) { throw new BlockInfoException("BLOCK_INDEX unmatch: " + mBlocks.size() + " != " + blockInfo); } if (blockInfo.OFFSET != mBlocks.size() * BLOCK_SIZE_BYTE) { throw new BlockInfoException("OFFSET unmatch: " + mBlocks.size() * BLOCK_SIZE_BYTE + " != " + blockInfo); } if (blockInfo.LENGTH > BLOCK_SIZE_BYTE) { throw new BlockInfoException("LENGTH too big: " + BLOCK_SIZE_BYTE + " " + blockInfo); } mLength += blockInfo.LENGTH; mBlocks.add(blockInfo); } public synchronized void addLocation(int blockIndex, long workerId, NetAddress workerAddress) throws BlockInfoException { if (blockIndex < 0 || blockIndex >= mBlocks.size()) { throw new BlockInfoException("BlockIndex " + blockIndex + " out of bounds." + toString()); } mBlocks.get(blockIndex).addLocation(workerId, workerAddress); } @Override public ClientFileInfo generateClientFileInfo(String path) { ClientFileInfo ret = new ClientFileInfo(); ret.id = getId(); ret.name = getName(); ret.path = path; ret.ufsPath = mUfsPath; ret.length = mLength; ret.blockSizeByte = BLOCK_SIZE_BYTE; ret.creationTimeMs = getCreationTimeMs(); ret.isComplete = isComplete(); ret.isFolder = false; ret.isPinned = isPinned(); ret.isCache = mCache; ret.blockIds = getBlockIds(); ret.dependencyId = mDependencyId; ret.inMemoryPercentage = getInMemoryPercentage(); return ret; } public long getBlockIdBasedOnOffset(long offset) { int index = (int) (offset / BLOCK_SIZE_BYTE); return BlockInfo.computeBlockId(getId(), index); } public synchronized List<Long> getBlockIds() { List<Long> ret = new ArrayList<Long>(mBlocks.size()); for (int k = 0; k < mBlocks.size(); k ++) { ret.add(mBlocks.get(k).BLOCK_ID); } return ret; } public synchronized List<Pair<Long, Long>> getBlockIdWorkerIdPairs() { List<Pair<Long, Long>> ret = new ArrayList<Pair<Long, Long>>(); for (BlockInfo info : mBlocks) { ret.addAll(info.getBlockIdWorkerIdPairs()); } return ret; } public List<BlockInfo> getBlockList() { return mBlocks; } public synchronized List<NetAddress> getBlockLocations(int blockIndex) throws BlockInfoException { if (blockIndex < 0 || blockIndex > mBlocks.size()) { throw new BlockInfoException("BlockIndex is out of the boundry: " + blockIndex); } return mBlocks.get(blockIndex).getLocations(); } public long getBlockSizeByte() { return BLOCK_SIZE_BYTE; } public synchronized String getUfsPath() { return mUfsPath; } public synchronized ClientBlockInfo getClientBlockInfo(int blockIndex) throws BlockInfoException { if (blockIndex < 0 || blockIndex > mBlocks.size()) { throw new BlockInfoException("BlockIndex is out of the boundry: " + blockIndex); } return mBlocks.get(blockIndex).generateClientBlockInfo(); } /** * Get file's all blocks' ClientBlockInfo information. * * @return all blocks ClientBlockInfo */ public synchronized List<ClientBlockInfo> getClientBlockInfos() { List<ClientBlockInfo> ret = new ArrayList<ClientBlockInfo>(mBlocks.size()); for (BlockInfo tInfo : mBlocks) { ret.add(tInfo.generateClientBlockInfo()); } return ret; } public synchronized int getDependencyId() { return mDependencyId; } private synchronized int getInMemoryPercentage() { if (mLength == 0) { return 100; } long inMemoryLength = 0; for (BlockInfo info : mBlocks) { if (info.isInMemory()) { inMemoryLength += info.LENGTH; } } return (int) (inMemoryLength * 100 / mLength); } public synchronized long getLength() { return mLength; } public synchronized long getNewBlockId() { return BlockInfo.computeBlockId(getId(), mBlocks.size()); } public synchronized int getNumberOfBlocks() { return mBlocks.size(); } public synchronized boolean hasCheckpointed() { return !mUfsPath.equals(""); } public synchronized boolean isCache() { return mCache; } public synchronized boolean isComplete() { return mIsComplete; } public synchronized boolean isFullyInMemory() { return getInMemoryPercentage() == 100; } public synchronized void removeLocation(int blockIndex, long workerId) throws BlockInfoException { if (blockIndex < 0 || blockIndex >= mBlocks.size()) { throw new BlockInfoException("BlockIndex " + blockIndex + " out of bounds." + toString()); } mBlocks.get(blockIndex).removeLocation(workerId); } public synchronized void setCache(boolean cache) { // TODO this related logic is not complete right. fix this. mCache = cache; } public synchronized void setUfsPath(String ufsPath) { mUfsPath = ufsPath; } public synchronized void setComplete() { mIsComplete = true; } public synchronized void setComplete(boolean complete) { mIsComplete = complete; } public synchronized void setDependencyId(int dependencyId) { mDependencyId = dependencyId; } public synchronized void setLength(long length) throws SuspectedFileSizeException, BlockInfoException { if (isComplete()) { throw new SuspectedFileSizeException("InodeFile length was set previously."); } if (length < 0) { throw new SuspectedFileSizeException("InodeFile new length " + length + " is illegal."); } mLength = 0; while (length >= BLOCK_SIZE_BYTE) { addBlock(new BlockInfo(this, mBlocks.size(), BLOCK_SIZE_BYTE)); length -= BLOCK_SIZE_BYTE; } if (length > 0) { addBlock(new BlockInfo(this, mBlocks.size(), (int) length)); } mIsComplete = true; } @Override public String toString() { StringBuilder sb = new StringBuilder("InodeFile("); sb.append(super.toString()).append(", LENGTH: ").append(mLength); sb.append(", UfsPath: ").append(mUfsPath); sb.append(", mBlocks: ").append(mBlocks); sb.append(", DependencyId:").append(mDependencyId).append(")"); return sb.toString(); } @Override public synchronized void writeImage(ObjectWriter objWriter, DataOutputStream dos) throws IOException { ImageElement ele = new ImageElement(ImageElementType.InodeFile) .withParameter("creationTimeMs", getCreationTimeMs()).withParameter("id", getId()) .withParameter("name", getName()).withParameter("parentId", getParentId()) .withParameter("blockSizeByte", getBlockSizeByte()) .withParameter("length", getLength()).withParameter("complete", isComplete()) .withParameter("pin", isPinned()).withParameter("cache", isCache()) .withParameter("ufsPath", getUfsPath()).withParameter("depId", getDependencyId()); writeElement(objWriter, dos, ele); } }