Zookeeper原理分析之存储结构TxnLog

Zookeeper事物日志文件用于记录事物操作,如添加,删除节点等等,都会在事务日志中记录一条记录。下面我们就详细分析一下txnLog事务日志文件。

txnLog事务日志文件文件由三部分组成:

  • 日志文件头FileHeader
  • TxnList代表记录记录集合
  • ZeroPad文件尾部

FileHeader

public class FileHeader implements Record {
  private int magic;//(ZKLG) 常量代表文件魔数
  private int version;//常量2 
  private long dbid;//常量,默认0
}

头文件是固定长度 16 = 4 + 4 + 8数据,它的值也固定。

TxnList

TxnList代表记录记录集合,txn代表一条记录,把一条txn添加到日志文件代码如下:

	//序列化TxnHeader Record记录到byte[]
    byte[] buf = Util.marshallTxnEntry(hdr, txn);
    if (buf == null || buf.length == 0) {
        throw new IOException("Faulty serialization for header " +
                "and txn");
    }
    Checksum crc = makeChecksumAlgorithm();
	//根据指定数组更新校验值
    crc.update(buf, 0, buf.length);
    oa.writeLong(crc.getValue(), "txnEntryCRC");
	 //将TxnHeader Record数据写入到输出流
   //1.先计算buf数据长度写入
   //2.写入buf数组数据
   //3.记录尾部以’B’字符结尾,写入0x42
    Util.writeTxnBytes(oa, buf);

checksum校验位计算,是由Adler32校验算法计算TxnHeader Record序列化后的字节码.TxnHeader的定义如下:

public class TxnHeader implements Record {
  private long clientId;
  private int cxid;// 与客户端交互的xid
  private long zxid;// 服务器端生成的事务id
  private long time;
  private int type;  // 事务操作的类型
}

Record:事务记录的内容,由jute规范定义了序列化反序列化流程,各个事务操作都实现了Record接口,下面看下创建的事务操作记录

public class CreateTxn implements Record {
  private String path;//创建路径
  private byte[] data;//节点数据内容
  private java.util.List<org.apache.zookeeper.data.ACL> acl;//节点权限
  private boolean ephemeral; //是否临时节点
  private int parentCVersion;//父节点的版本号
  //序列化过程

	public void serialize(OutputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(this,tag);
    a_.writeString(path,"path");
    a_.writeBuffer(data,"data");
    {
      a_.startVector(acl,"acl");
      if (acl!= null) {          int len1 = acl.size();
          for(int vidx1 = 0; vidx1<len1; vidx1++) {
            org.apache.zookeeper.data.ACL e1 = (org.apache.zookeeper.data.ACL) acl.get(vidx1);
    a_.writeRecord(e1,"e1");
          }
      }
      a_.endVector(acl,"acl");
    }
    a_.writeBool(ephemeral,"ephemeral");
    a_.writeInt(parentCVersion,"parentCVersion");
    a_.endRecord(this,tag);
  }
 //反序列化过程
 public void deserialize(InputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(tag);
    path=a_.readString("path");
    data=a_.readBuffer("data");
    {
      Index vidx1 = a_.startVector("acl");
      if (vidx1!= null) {          acl=new java.util.ArrayList<org.apache.zookeeper.data.ACL>();
          for (; !vidx1.done(); vidx1.incr()) {
    org.apache.zookeeper.data.ACL e1;
    e1= new org.apache.zookeeper.data.ACL();
    a_.readRecord(e1,"e1");
            acl.add(e1);
          }
      }
    a_.endVector("acl");
    }
    ephemeral=a_.readBool("ephemeral");
    parentCVersion=a_.readInt("parentCVersion");
    a_.endRecord(tag);
}

每条事务记录尾部以’B’字符结尾就是0x42

ZeroPad文件尾部

每个文件尾部都用一个字符 0 填充, 工具Util.padLogFile扩充文件的时候在尾部填写上

    public static long padLogFile(FileOutputStream f,long currentSize,
            long preAllocSize) throws IOException{
        long position = f.getChannel().position();
        if (position + 4096 >= currentSize) {
            currentSize = currentSize + preAllocSize;
            fill.position(0);
            f.getChannel().write(fill, currentSize-fill.remaining());
        }
        return currentSize;
    }
posted @ 2018-02-03 11:06  木易森林  阅读(823)  评论(0编辑  收藏  举报