首页 > 其它语言 > hadoop-common源码分析

hadoop-common源码分析

hadoop将java的基本类型进行封装,对整型进行编码时,分为固定长度格式、可变长度格式。可变长度格式使用一种比较灵活的编码方式,对与较小的数(尤其是负数)可以节省空间存储。

VIntWritable

public class VIntWritable implements WritableComparable<VIntWritable> {
  private int value;

//getter //setter
  @Override
  public void readFields(DataInput in) throws IOException {
    value = WritableUtils.readVInt(in);
  }

  @Override
  public void write(DataOutput out) throws IOException {
    WritableUtils.writeVInt(out, value);
  }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

WritableUtils.writeVLong

  public static void writeVInt(DataOutput stream, int i) throws IOException {
    writeVLong(stream, i);
  }
  public static void writeVLong(DataOutput stream, long i) throws IOException {
    if (i >= -112 && i <= 127) {
      stream.writeByte((byte)i);
      return;
    }

    int len = -112;
    if (i < 0) {
      i ^= -1L; // take one's complement'
      len = -120;
    }

    long tmp = i;
    while (tmp != 0) {
      tmp = tmp >> 8;
      len--;
    }

    stream.writeByte((byte)len);

    len = (len < -120) ? -(len + 120) : -(len + 112);

    for (int idx = len; idx != 0; idx--) {
      int shiftbits = (idx - 1) * 8;
      long mask = 0xFFL << shiftbits;
      System.out.println(((i & mask) >> shiftbits));
      stream.writeByte((byte)((i & mask) >> shiftbits));
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  1. 如果i在 [-112 ~ 127] 之间,直接转换为byte类型存储。
  2. 如果i小于-112时,将其转换成正数(异或-1L),将标识量len 设置-120;否则len为-112
  3. 移位要存储的数据,同时len进行自减(len即做了标示量,又统计了移位次数)。
  4. 将标识量写到输出流。
  5. 重置len,将len设置为移位个数。
  6. 进行循环,将数据每8位写到输出流(大端模式),具体分析for循环。

WritableUtils.readVLong

  public static long readVLong(DataInput stream) throws IOException {
    byte firstByte = stream.readByte();
    int len = decodeVIntSize(firstByte);
    if (len == 1) {
      return firstByte;
    }
    long i = 0;
    for (int idx = 0; idx < len-1; idx++) {
      byte b = stream.readByte();
      i = i << 8;
      i = i | (b & 0xFF);
    }
    return (isNegativeVInt(firstByte) ? (i ^ -1L) : i);
  }
  public static int decodeVIntSize(byte value) {
    if (value >= -112) {
      return 1;
    } else if (value < -120) {
      return -119 - value;
    }
    return -111 - value;
  } 
  public static boolean isNegativeVInt(byte value) {
    return value < -120 || (value >= -112 && value < 0);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  1. 读取一个byte类型
  2. 判断读出数据如果大于-112,说明不是标志量,可以直接返回原始数据,如果小于-120或者在[-112 ~ -120]之间,说明为标识量,需要判断返回移动位数。
  3. 通过得到移动的位数,每次移动8位,异或移位。还原数据。
  4. 判断表示量,如果在小于-120 或者在[0 ~ -112]之间,证明是负数,将得到的数据进行异或-1L得到最终值。

总结:

  1. 在存储正数时,为了防止类型过大,而存储值小的,hadoop将数据每8位转换成byte进行存储。
  2. 在存储负数时,由于负数存储需要以补码形式(反码+1),浪费太多的空间,所以hadoop先将负数与-1L异或,得到正数进行存储,所以在存储过程中,需要一个标识来标记数字正负,即len,它同时标识了需要移动位数和正负。

本文固定链接: http://www.devba.com/index.php/archives/6296.html | 开发吧

报歉!评论已关闭.