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; 023 024import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo; 025import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization; 026import org.apache.hadoop.hdfs.server.namenode.INode; 027import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo; 028import org.apache.hadoop.hdfs.server.namenode.INodeFile; 029import org.apache.hadoop.hdfs.server.namenode.INodeFileAttributes; 030import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotFSImageFormat.ReferenceMap; 031 032/** 033 * The difference of an {@link INodeFile} between two snapshots. 034 */ 035public class FileDiff extends 036 AbstractINodeDiff<INodeFile, INodeFileAttributes, FileDiff> { 037 038 /** The file size at snapshot creation time. */ 039 private final long fileSize; 040 /** A copy of the INodeFile block list. Used in truncate. */ 041 private BlockInfo[] blocks; 042 043 FileDiff(int snapshotId, INodeFile file) { 044 super(snapshotId, null, null); 045 fileSize = file.computeFileSize(); 046 blocks = null; 047 } 048 049 /** Constructor used by FSImage loading */ 050 FileDiff(int snapshotId, INodeFileAttributes snapshotINode, 051 FileDiff posteriorDiff, long fileSize) { 052 super(snapshotId, snapshotINode, posteriorDiff); 053 this.fileSize = fileSize; 054 blocks = null; 055 } 056 057 /** @return the file size in the snapshot. */ 058 public long getFileSize() { 059 return fileSize; 060 } 061 062 /** 063 * Copy block references into the snapshot 064 * up to the current {@link #fileSize}. 065 * Should be done only once. 066 */ 067 public void setBlocks(BlockInfo[] blocks) { 068 if(this.blocks != null) 069 return; 070 int numBlocks = 0; 071 for(long s = 0; numBlocks < blocks.length && s < fileSize; numBlocks++) 072 s += blocks[numBlocks].getNumBytes(); 073 this.blocks = Arrays.copyOf(blocks, numBlocks); 074 } 075 076 public BlockInfo[] getBlocks() { 077 return blocks; 078 } 079 080 @Override 081 void combinePosteriorAndCollectBlocks( 082 INode.ReclaimContext reclaimContext, INodeFile currentINode, 083 FileDiff posterior) { 084 FileWithSnapshotFeature sf = currentINode.getFileWithSnapshotFeature(); 085 assert sf != null : "FileWithSnapshotFeature is null"; 086 sf.updateQuotaAndCollectBlocks(reclaimContext, currentINode, posterior); 087 } 088 089 @Override 090 public String toString() { 091 return super.toString() + " fileSize=" + fileSize + ", rep=" 092 + (snapshotINode == null? "?": snapshotINode.getFileReplication()); 093 } 094 095 @Override 096 void write(DataOutput out, ReferenceMap referenceMap) throws IOException { 097 writeSnapshot(out); 098 out.writeLong(fileSize); 099 100 // write snapshotINode 101 if (snapshotINode != null) { 102 out.writeBoolean(true); 103 FSImageSerialization.writeINodeFileAttributes(snapshotINode, out); 104 } else { 105 out.writeBoolean(false); 106 } 107 } 108 109 @Override 110 void destroyDiffAndCollectBlocks(INode.ReclaimContext reclaimContext, 111 INodeFile currentINode) { 112 currentINode.getFileWithSnapshotFeature().updateQuotaAndCollectBlocks( 113 reclaimContext, currentINode, this); 114 } 115 116 public void destroyAndCollectSnapshotBlocks( 117 BlocksMapUpdateInfo collectedBlocks) { 118 if (blocks == null || collectedBlocks == null) { 119 return; 120 } 121 for (BlockInfo blk : blocks) { 122 collectedBlocks.addDeleteBlock(blk); 123 } 124 blocks = null; 125 } 126}