Package tachyon.client

Source Code of tachyon.client.FileOutStream

package tachyon.client;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tachyon.Constants;
import tachyon.UnderFileSystem;
import tachyon.util.CommonUtils;

/**
* <code>FileOutStream</code> implementation of TachyonFile. It can only be gotten by calling the
* methods in <code>tachyon.client.TachyonFile</code>, but can not be initialized by the client
* code.
*/
public class FileOutStream extends OutStream {
  private static final Logger LOG = LoggerFactory.getLogger(Constants.LOGGER_TYPE);

  private final long mBlockCapacityByte;

  private BlockOutStream mCurrentBlockOutStream;
  private long mCurrentBlockId;
  private long mCurrentBlockLeftByte;
  private List<BlockOutStream> mPreviousBlockOutStreams;
  private long mCachedBytes;

  private OutputStream mCheckpointOutputStream = null;
  private String mUnderFsFile = null;

  private boolean mClosed = false;
  private boolean mCancel = false;

  /**
   * @param file the output file
   * @param opType the OutStream's write type
   * @param ufsConf the under file system configuration
   * @throws IOException
   */
  FileOutStream(TachyonFile file, WriteType opType, Object ufsConf) throws IOException {
    super(file, opType);

    mBlockCapacityByte = file.getBlockSizeByte();

    // TODO Support and test append.
    mCurrentBlockOutStream = null;
    mCurrentBlockId = -1;
    mCurrentBlockLeftByte = 0;
    mPreviousBlockOutStreams = new ArrayList<BlockOutStream>();
    mCachedBytes = 0;

    if (mWriteType.isThrough()) {
      mUnderFsFile = CommonUtils.concat(mTachyonFS.createAndGetUserUfsTempFolder(), mFile.mFileId);
      UnderFileSystem underfsClient = UnderFileSystem.get(mUnderFsFile, ufsConf);
      if (mBlockCapacityByte > Integer.MAX_VALUE) {
        throw new IOException("BLOCK_CAPCAITY (" + mBlockCapacityByte + ") can not bigger than "
            + Integer.MAX_VALUE);
      }
      mCheckpointOutputStream = underfsClient.create(mUnderFsFile, (int) mBlockCapacityByte);
    }
  }

  @Override
  public void cancel() throws IOException {
    mCancel = true;
    close();
  }

  @Override
  public void close() throws IOException {
    if (!mClosed) {
      if (mCurrentBlockOutStream != null) {
        mPreviousBlockOutStreams.add(mCurrentBlockOutStream);
      }

      Boolean canComplete = false;
      if (mWriteType.isThrough()) {
        if (mCancel) {
          mCheckpointOutputStream.close();
          UnderFileSystem underFsClient = UnderFileSystem.get(mUnderFsFile);
          underFsClient.delete(mUnderFsFile, false);
        } else {
          mCheckpointOutputStream.flush();
          mCheckpointOutputStream.close();
          mTachyonFS.addCheckpoint(mFile.mFileId);
          canComplete = true;
        }
      }

      if (mWriteType.isCache()) {
        try {
          if (mCancel) {
            for (BlockOutStream bos : mPreviousBlockOutStreams) {
              bos.cancel();
            }
          } else {
            for (BlockOutStream bos : mPreviousBlockOutStreams) {
              bos.close();
            }
            canComplete = true;
          }
        } catch (IOException ioe) {
          if (mWriteType.isMustCache()) {
            LOG.error(ioe.getMessage(), ioe);
            throw new IOException("Fail to cache: " + mWriteType, ioe);
          } else {
            LOG.warn("Fail to cache for: ", ioe);
          }
        }
      }

      if (canComplete) {
        if (mWriteType.isAsync()) {
          mTachyonFS.asyncCheckpoint(mFile.mFileId);
        }
        mTachyonFS.completeFile(mFile.mFileId);
      }
    }

    mClosed = true;
  }

  @Override
  public void flush() throws IOException {
    // TODO We only flush the checkpoint output stream. Flush for RAMFS block streams.
    if (mWriteType.isThrough()) {
      mCheckpointOutputStream.flush();
    }
  }

  private void getNextBlock() throws IOException {
    if (mCurrentBlockId != -1) {
      if (mCurrentBlockLeftByte != 0) {
        throw new IOException("The current block still has space left, no need to get new block");
      }
      mPreviousBlockOutStreams.add(mCurrentBlockOutStream);
    }

    if (mWriteType.isCache()) {
      mCurrentBlockId = mFile.getBlockIdBasedOnOffset(mCachedBytes);
      mCurrentBlockLeftByte = mBlockCapacityByte;

      mCurrentBlockOutStream =
          new BlockOutStream(mFile, mWriteType, (int) (mCachedBytes / mBlockCapacityByte));
    }
  }

  @Override
  public void write(byte[] b) throws IOException {
    write(b, 0, b.length);
  }

  @Override
  public void write(byte[] b, int off, int len) throws IOException {
    if (b == null) {
      throw new NullPointerException();
    } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
        || ((off + len) < 0)) {
      throw new IndexOutOfBoundsException();
    }

    if (mWriteType.isCache()) {
      try {
        int tLen = len;
        int tOff = off;
        while (tLen > 0) {
          if (mCurrentBlockLeftByte == 0) {
            getNextBlock();
          } else if (mCurrentBlockLeftByte < 0 || mCurrentBlockOutStream == null) {
            throw new IOException("mCurrentBlockLeftByte " + mCurrentBlockLeftByte + " "
                + mCurrentBlockOutStream);
          }
          if (mCurrentBlockLeftByte >= tLen) {
            mCurrentBlockOutStream.write(b, tOff, tLen);
            mCurrentBlockLeftByte -= tLen;
            mCachedBytes += tLen;
            tOff += tLen;
            tLen = 0;
          } else {
            mCurrentBlockOutStream.write(b, tOff, (int) mCurrentBlockLeftByte);
            tOff += mCurrentBlockLeftByte;
            tLen -= mCurrentBlockLeftByte;
            mCachedBytes += mCurrentBlockLeftByte;
            mCurrentBlockLeftByte = 0;
          }
        }
      } catch (IOException e) {
        if (mWriteType.isMustCache()) {
          LOG.error(e.getMessage(), e);
          throw new IOException("Fail to cache: " + mWriteType, e);
        } else {
          LOG.warn("Fail to cache for: ", e);
        }
      }
    }

    if (mWriteType.isThrough()) {
      mCheckpointOutputStream.write(b, off, len);
    }
  }

  @Override
  public void write(int b) throws IOException {
    if (mWriteType.isCache()) {
      try {
        if (mCurrentBlockId == -1 || mCurrentBlockLeftByte == 0) {
          getNextBlock();
        }
        // TODO Cache the exception here.
        mCurrentBlockOutStream.write(b);
        mCurrentBlockLeftByte --;
        mCachedBytes ++;
      } catch (IOException e) {
        if (mWriteType.isMustCache()) {
          LOG.error(e.getMessage(), e);
          throw new IOException("Fail to cache: " + mWriteType, e);
        } else {
          LOG.warn("Fail to cache for: ", e);
        }
      }
    }

    if (mWriteType.isThrough()) {
      mCheckpointOutputStream.write(b);
    }
  }
}
TOP

Related Classes of tachyon.client.FileOutStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.