大衆點評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
			}
		}
	}
相關文章
相關標籤/搜索