001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hdfs.server.namenode.snapshot;
019
020import java.io.DataOutput;
021import java.io.IOException;
022import java.util.Arrays;
023import java.util.List;
024
025import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoContiguous;
026import org.apache.hadoop.hdfs.server.blockmanagement.BlockStoragePolicySuite;
027import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization;
028import org.apache.hadoop.hdfs.server.namenode.INode;
029import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
030import org.apache.hadoop.hdfs.server.namenode.INodeFile;
031import org.apache.hadoop.hdfs.server.namenode.INodeFileAttributes;
032import org.apache.hadoop.hdfs.server.namenode.QuotaCounts;
033import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap;
034
035/**
036 * The difference of an {@link INodeFile} between two snapshots.
037 */
038public class FileDiff extends
039    AbstractINodeDiff<INodeFile, INodeFileAttributes, FileDiff> {
040
041  /** The file size at snapshot creation time. */
042  private final long fileSize;
043  /** A copy of the INodeFile block list. Used in truncate. */
044  private BlockInfoContiguous[] blocks;
045
046  FileDiff(int snapshotId, INodeFile file) {
047    super(snapshotId, null, null);
048    fileSize = file.computeFileSize();
049    blocks = null;
050  }
051
052  /** Constructor used by FSImage loading */
053  FileDiff(int snapshotId, INodeFileAttributes snapshotINode,
054      FileDiff posteriorDiff, long fileSize) {
055    super(snapshotId, snapshotINode, posteriorDiff);
056    this.fileSize = fileSize;
057    blocks = null;
058  }
059
060  /** @return the file size in the snapshot. */
061  public long getFileSize() {
062    return fileSize;
063  }
064
065  /**
066   * Copy block references into the snapshot
067   * up to the current {@link #fileSize}.
068   * Should be done only once.
069   */
070  public void setBlocks(BlockInfoContiguous[] blocks) {
071    if(this.blocks != null)
072      return;
073    int numBlocks = 0;
074    for(long s = 0; numBlocks < blocks.length && s < fileSize; numBlocks++)
075      s += blocks[numBlocks].getNumBytes();
076    this.blocks = Arrays.copyOf(blocks, numBlocks);
077  }
078
079  public BlockInfoContiguous[] getBlocks() {
080    return blocks;
081  }
082
083  @Override
084  QuotaCounts combinePosteriorAndCollectBlocks(
085      BlockStoragePolicySuite bsps, INodeFile currentINode,
086      FileDiff posterior, BlocksMapUpdateInfo collectedBlocks,
087      final List<INode> removedINodes) {
088    FileWithSnapshotFeature sf = currentINode.getFileWithSnapshotFeature();
089    assert sf != null : "FileWithSnapshotFeature is null";
090    return sf.updateQuotaAndCollectBlocks(
091        bsps, currentINode, posterior, collectedBlocks, removedINodes);
092  }
093  
094  @Override
095  public String toString() {
096    return super.toString() + " fileSize=" + fileSize + ", rep="
097        + (snapshotINode == null? "?": snapshotINode.getFileReplication());
098  }
099
100  @Override
101  void write(DataOutput out, ReferenceMap referenceMap) throws IOException {
102    writeSnapshot(out);
103    out.writeLong(fileSize);
104
105    // write snapshotINode
106    if (snapshotINode != null) {
107      out.writeBoolean(true);
108      FSImageSerialization.writeINodeFileAttributes(snapshotINode, out);
109    } else {
110      out.writeBoolean(false);
111    }
112  }
113
114  @Override
115  QuotaCounts destroyDiffAndCollectBlocks(BlockStoragePolicySuite bsps, INodeFile currentINode,
116      BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) {
117    return currentINode.getFileWithSnapshotFeature()
118        .updateQuotaAndCollectBlocks(bsps, currentINode, this, collectedBlocks,
119            removedINodes);
120  }
121
122  public void destroyAndCollectSnapshotBlocks(
123      BlocksMapUpdateInfo collectedBlocks) {
124    if(blocks == null || collectedBlocks == null)
125      return;
126    for(BlockInfoContiguous blk : blocks)
127      collectedBlocks.addDeleteBlock(blk);
128    blocks = null;
129  }
130}