content: /*
   * 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.carbondata.core.datastore.block;
  
  import java.io.IOException;
  import java.io.Serializable;
  import java.nio.charset.Charset;
  import java.util.Arrays;
  import java.util.Comparator;
  
  import org.apache.carbondata.core.constants.CarbonCommonConstants;
  import org.apache.carbondata.core.datastore.impl.FileFactory;
  import org.apache.carbondata.core.index.Segment;
  import org.apache.carbondata.core.indexstore.BlockletDetailInfo;
  import org.apache.carbondata.core.metadata.ColumnarFormatVersion;
  import org.apache.carbondata.core.metadata.blocklet.DataFileFooter;
  import org.apache.carbondata.core.util.ByteUtil;
  import org.apache.carbondata.core.util.path.CarbonTablePath;
  import org.apache.carbondata.core.util.path.CarbonTablePath.DataFileUtil;
  
  import org.apache.hadoop.fs.FileSystem;
  import org.apache.hadoop.fs.Path;
  
  /**
   * class will be used to pass the block detail detail will be passed form driver
   * to all the executor to load the b+ tree
   */
  public class TableBlockInfo implements Distributable, Serializable {
  
    /**
     * serialization id
     */
    private static final long serialVersionUID = -6502868998599821172L;
  
    /**
     * full qualified file path of the block
     */
    private String filePath;
  
    /**
     * file size of the block
     */
    private long fileSize;
  
    /**
     * block offset in the file
     */
    private long blockOffset;
  
    /**
     * length of the block
     */
    private long blockLength;
  
    /**
     * id of the segment this will be used to sort the blocks
     */
    private Segment segment;
  
    private String[] locations;
  
    private ColumnarFormatVersion version;
  
    /**
     * delete delta files path for this block
     */
    private String[] deletedDeltaFilePath;
  
    private BlockletDetailInfo detailInfo;
  
    private String indexWriterPath;
  
    private transient DataFileFooter dataFileFooter;
  
    /**
     * Carbon Data file written version
     */
    private String carbonDataFileWrittenVersion = null;
  
    /**
     * comparator to sort by block size in descending order.
     * Since each line is not exactly the same, the size of a InputSplit may differs,
     * so we allow some deviation for these splits.
     */
    public static final Comparator<Distributable> DATA_SIZE_DESC_COMPARATOR =
        new Comparator<Distributable>() {
          @Override
          public int compare(Distributable o1, Distributable o2) {
            long diff =
                ((TableBlockInfo) o1).getBlockLength() - ((TableBlockInfo) o2).getBlockLength();
            return diff < 0 ? 1 : (diff == 0 ? 0 : -1);
          }
        };
  
    public TableBlockInfo(String filePath, long blockOffset, String segmentId,
        String[] locations, long blockLength, ColumnarFormatVersion version,
        String[] deletedDeltaFilePath) {
      this.filePath = FileFactory.getUpdatedFilePath(filePath);
      this.blockOffset = blockOffset;
      this.segment = Segment.toSegment(segmentId);
      this.locations = locations;
      this.blockLength = blockLength;
      this.version = version;
      this.deletedDeltaFilePath = deletedDeltaFilePath;
    }
  
    public TableBlockInfo() {
  
    }
  
    /**
     * Create copy of TableBlockInfo object
     */
    public TableBlockInfo copy() {
      TableBlockInfo info = new TableBlockInfo();
      info.filePath = filePath;
      info.blockOffset = blockOffset;
      info.blockLength = blockLength;
      info.segment = segment;
      info.locations = locations;
      info.version = version;
      info.deletedDeltaFilePath = deletedDeltaFilePath;
      info.detailInfo = detailInfo.copy();
      info.indexWriterPath = indexWriterPath;
      info.carbonDataFileWrittenVersion = carbonDataFileWrittenVersion;
      return info;
    }
  
    /**
     * @return the filePath
     */
    public String getFilePath() {
      return filePath;
    }
  
    /**
     * @return the blockOffset
     */
    public long getBlockOffset() {
      return blockOffset;
    }
  
    public void setBlockOffset(long blockOffset) {
      this.blockOffset = blockOffset;
    }
  
    /**
     * @return the segmentId
     */
    public String getSegmentId() {
      if (segment == null) {
        return null;
      } else {
        return segment.getSegmentNo();
      }
    }
  
    public Segment getSegment() {
      return segment;
    }
  
    /**
     * @return the blockLength
     */
    public long getBlockLength() {
      if (blockLength == 0) {
        Path path = new Path(filePath);
        try {
          FileSystem fs = path.getFileSystem(FileFactory.getConfiguration());
          blockLength = fs.listStatus(path)[0].getLen();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
      return blockLength;
    }
  
    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (!(obj instanceof TableBlockInfo)) {
        return false;
      }
      TableBlockInfo other = (TableBlockInfo) obj;
      if (!segment.equals(other.segment)) {
        return false;
      }
      if (blockOffset != other.blockOffset) {
        return false;
      }
      if (blockLength != other.blockLength) {
        return false;
      }
  
      if (null == filePath || null == other.filePath) {
        return  false;
      }
  
      if (!new Path(filePath).equals(new Path(other.filePath))) {
        return false;
      }
  
      return true;
    }
  
    /**
     * Below method will used to compare to TableBlockInfos object this will
     * used for sorting Comparison logic is: 1. compare segment id if segment id
     * is same 2. compare task id if task id is same 3. compare offsets of the
     * block
     */
    @Override
    public int compareTo(Distributable other) {
  
      int compareResult = 0;
      // get the segment id
      // convert segment ID to double.
  
      double seg1 = Double.parseDouble(segment.getSegmentNo());
      double seg2 = Double.parseDouble(((TableBlockInfo) other).segment.getSegmentNo());
      if (seg1 - seg2 < 0) {
        return -1;
      }
      if (seg1 - seg2 > 0) {
        return 1;
      }
  
      // Comparing the time task id of the file to other
      // if both the task id of the file is same then we need to compare the
      // offset of
      // the file
      if (CarbonTablePath.isCarbonDataFile(filePath)) {
        int compare = ByteUtil.compare(DataFileUtil.getTaskNo(filePath)
                .getBytes(Charset.forName(CarbonCommonConstants.DEFAULT_CHARSET)),
            DataFileUtil.getTaskNo(((TableBlockInfo) other).filePath)
                .getBytes(Charset.forName(CarbonCommonConstants.DEFAULT_CHARSET)));
        if (compare != 0) {
          return compare;
        }
        // compare the part no of both block info
        int firstPartNo = Integer.parseInt(DataFileUtil.getPartNo(filePath));
        int SecondPartNo =
            Integer.parseInt(DataFileUtil.getPartNo(((TableBlockInfo) other).filePath));
        compareResult = firstPartNo - SecondPartNo;
      } else {
        compareResult = filePath.compareTo(((TableBlockInfo) other).getFilePath());
      }
      if (compareResult != 0) {
        return compareResult;
      }
      //compare result is not 0 then return
      // if part no is also same then compare the offset and length of the block
      if (blockOffset + blockLength
          < ((TableBlockInfo) other).blockOffset + ((TableBlockInfo) other).blockLength) {
        return -1;
      } else if (blockOffset + blockLength
          > ((TableBlockInfo) other).blockOffset + ((TableBlockInfo) other).blockLength) {
        return 1;
      }
      return 0;
    }
  
    @Override
    public int hashCode() {
      int result = filePath.hashCode();
      result = 31 * result + (int) (blockOffset ^ (blockOffset >>> 32));
      result = 31 * result + (int) (blockLength ^ (blockLength >>> 32));
      result = 31 * result + segment.hashCode();
      result = 31 * result;
      return result;
    }
  
    @Override
    public String[] getLocations() {
      return locations;
    }
  
    public ColumnarFormatVersion getVersion() {
      return version;
    }
  
    public void setVersion(ColumnarFormatVersion version) {
      this.version = version;
    }
  
    public String[] getDeletedDeltaFilePath() {
      return deletedDeltaFilePath;
    }
  
    public void setFilePath(String filePath) {
      this.filePath = filePath;
    }
  
    public long getFileSize() {
      return fileSize;
    }
  
    public void setFileSize(long fileSize) {
      this.fileSize = fileSize;
    }
  
    public BlockletDetailInfo getDetailInfo() {
      return detailInfo;
    }
  
    public void setDetailInfo(BlockletDetailInfo detailInfo) {
      this.detailInfo = detailInfo;
    }
  
    public String getIndexWriterPath() {
      return indexWriterPath;
    }
  
    public void setIndexWriterPath(String indexWriterPath) {
      this.indexWriterPath = indexWriterPath;
    }
  
    public DataFileFooter getDataFileFooter() {
      return dataFileFooter;
    }
  
    public void setDataFileFooter(DataFileFooter dataFileFooter) {
      this.dataFileFooter = dataFileFooter;
    }
  
    @Override
    public String toString() {
      final StringBuilder sb = new StringBuilder("TableBlockInfo{");
      sb.append("filePath='").append(filePath).append('\'');
      sb.append(", blockOffset=").append(blockOffset);
      sb.append(", blockLength=").append(blockLength);
      sb.append(", segment='").append(segment.toString()).append('\'');
      sb.append(", locations=").append(Arrays.toString(locations));
      sb.append('}');
      return sb.toString();
    }
  
    public String getCarbonDataFileWrittenVersion() {
      return carbonDataFileWrittenVersion;
    }
  
    public void setCarbonDataFileWrittenVersion(String carbonDataFileWrittenVersion) {
      this.carbonDataFileWrittenVersion = carbonDataFileWrittenVersion;
    }
  
  }
  