大众点评Cat源码分析(三)——数据文件(MessageTree)读写磁盘详细逻辑

1、MessageTree数据文件存储逻辑图

输入图片说明

2、MessageTree写入磁盘的逻辑

代码以下:数据库

/**
	 *  m_indexFile \data\appdatas\cat\bucket\dump\20171204\10\cat-10.15.83.181-10.15.83.181.idx
	 * @param block
	 * @throws IOException
	 * @description 
	 * 一、获取block块内树的棵数,遍历每一棵树
	 * 二、按照 6B(前4B写入整个block在dataFile中的其实位置,后2B写每一棵树在block内的偏移)写索引文件
	 * 三、将block的长度,做为一个int类型写入到dataFile
	 * 四、将block的data,接着写入dataFile
	 */
	public synchronized void writeBlock(MessageBlock block) throws IOException {
		int len = block.getBlockSize();//块内MessageTree的个数
		byte[] data = block.getData();//块内全部树的字节
		int blockSize = 0;
		//遍历块内每个树,对应的index,和树的size(字节)
		for (int i = 0; i < len; i++) {
			int seq = block.getIndex(i);
			int size = block.getSize(i);

			m_indexFile.seek(seq * 6L);//取6位,前4位是messageId的最后一个字段的index,后面是这个消息对应的size的偏移量
			m_indexFile.writeInt(m_blockAddress);//这几棵数的块内地址是同样的,可是,索引地址不同
			m_indexFile.writeShort(blockSize);//块内的偏移量
			blockSize += size;//block的总大小,字节数
		}

		m_dataFile.writeInt(data.length);//数据偏移的前面四个字节,是数据长度,接下来才是消息自己
		m_dataFile.write(data);
		m_blockAddress += data.length + 4;//偏移量+4个字节
	}

3、MessageTree从磁盘中读出的逻辑

代码以下:app

/**
	 * m_dataFile  \data\appdatas\cat\bucket\dump\20171204\09\cat-10.15.83.181-10.15.83.181
	 * @param index
	 * @return
	 * @throws IOException
	 * 读逻辑:
	 *    一、根据index找到索引文件的起始位置
	 *    二、读6B,前4B是数据文件的数据库的起始位置,后2B是MessageTree块内的偏移地址
	 *    三、找到数据文件块的起始地址,读取一个int类型数据,这个是整个数据块的长度
	 *    四、接着读取这么长的数据,即为整个数据块,对应MessageBlock
	 *    五、在数据块内,skip到MessageTree的块内地址
	 *    六、读取一个整型,这个整型即为MessageTree的长度,接着读出这棵消息树
	 */
	public byte[] readMessage(int index) throws IOException {
		int blockAddress = 0;
		int blockOffset = 0;
		byte[] buf;

		m_indexFile.seek(index * 6L);
		blockAddress = m_indexFile.readInt();
		blockOffset = m_indexFile.readShort() & 0xFFFF;

		m_dataFile.seek(blockAddress);
		buf = new byte[m_dataFile.readInt()];
		m_dataFile.readFully(buf);

		ByteArrayInputStream bais = new ByteArrayInputStream(buf);
		DataInputStream in = new DataInputStream(new GZIPInputStream(bais));

		try {
			in.skip(blockOffset);
			int len = in.readInt();

			byte[] data = new byte[len];

			in.readFully(data);
			return data;
		} finally {
			try {
				in.close();
			} catch (Exception e) {
				// ignore it
			}
		}
	}
相关文章
相关标签/搜索