模擬實現mapreduce中環形緩衝區的讀寫過程

稻草一根發表於2017-04-07

原型:

在mapreduce中,map task呼叫map處理邏輯將處理後的key和value利用outputcollector.collect()放入一個環形緩衝區中,那麼這個緩衝區是有一定大小的,那麼如果放入的內容很多很多的時候怎麼辦呢?其實hadoop裡面有這麼個機制,在緩衝區達到某一個值或者比率的時候,比如80%,那麼hadoop會利用Spiller.spill()將這個80%的資料讀出來按照HashPartitioner.getPartitioner()來進行分割槽並按照key進行快速排序,然後kv鍵值對會繼續向緩衝區中存放,形成一個環形儲存邏輯,只要達到80%就將這塊取出來,那麼緩衝區就會一直可用。


模擬實現:

定義了一個容量為100的字串陣列來模擬環形緩衝區。另外還定義了一個size用來決定原型中比率,預設值給的80.start用來記錄這個80內容的起始位置,一個布林型別的引數為true時意味著緩衝區中已經超過80,需要開始進行Spiller.spill()。

程式主要是兩個程式,第一個程式是不斷地將原始檔按行讀取,存入陣列中,當資料達到80的時候,將布林型別標記置為true,並設定起始位置,不需要考慮其他情況,當達到100的時候,會繼續往陣列中寫入資料,從0開始,不斷迴圈,知道檔案讀取完畢。

第二個程式會不斷去驗證標記位的值,如果為true,就會獲得當前起始位置,將標記位置為false,然後遍歷這80的資料,存入到某個編號檔案中,讀取完畢後會再次去嗅探標記位。


程式碼實現:

package com.season.spill;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class FileJobSubmitter {

	public static final String FILE_READ ="F:\\io\\BufferInput\\season.txt";
	
	public static String[] CIRCLE_BUFFER = new String[100];

	public static int BUFFER_SIZE = 80;

	public static int BUFFER_START = 0;

	public static int BUFFER_COUNTS = 0;
	
	public static boolean READ_FLAG = false;

	public static int FILE_ID = 1000;

	public static void main(String[] args) {

		ReadFileToCircleBuffer rf = new ReadFileToCircleBuffer();
		Thread rfThread = new Thread(rf);

		WriteFileFromBuffer wf = new WriteFileFromBuffer();
		Thread wfThread = new Thread(wf);

		rfThread.start();
		wfThread.start();
	}

	static class ReadFileToCircleBuffer implements Runnable {

		@Override
		public void run() {
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(FILE_READ))));
				String lenTxt = null;
				int i = 0 ;
				while((lenTxt = br.readLine()) != null ){
					
					CIRCLE_BUFFER[i] = lenTxt;
					
					BUFFER_COUNTS++;
					if(BUFFER_COUNTS == 80){
						BUFFER_START = i < 79 ? 20 + i : i-79 ;
						READ_FLAG = true ;
						BUFFER_COUNTS = 0 ;
					}
					System.out.println("內容:"+lenTxt+" flag="+ READ_FLAG + " start="+ BUFFER_START+" 總數=" + BUFFER_COUNTS+" i = "+ i);
					
					i = i==99?0:i+1; 
					
					
					Thread.sleep(1000);
				}
				BUFFER_START = i < BUFFER_COUNTS -1 ? 100 - BUFFER_COUNTS  + i : i- BUFFER_COUNTS + 1 ;
				READ_FLAG = true ;
				BUFFER_SIZE = BUFFER_COUNTS;
				
				
				br.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	static class WriteFileFromBuffer implements Runnable {

		@Override
		public void run() {

			while (true) {
				try {
					if (READ_FLAG) {
						READ_FLAG = false;
						BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("F:\\io\\BufferOutput\\part-" + FILE_ID + "size80.txt"))));
						// 將起點開始的80個記錄存入檔案中
						int start = BUFFER_START;
						for (int i = 0; i < BUFFER_SIZE; i++) {
							System.out.println( "*******存入:"+CIRCLE_BUFFER[start]);
							String temp = CIRCLE_BUFFER[start];
							
							bw.write(temp);
							bw.newLine();
							Thread.sleep(500);
							start = start==99?0:start+1;
						}
						bw.close();
						FILE_ID++;
					}

					Thread.sleep(1000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

		}

	}

}

總結:

其中有些輸出是為了檢視當前的進度來驗證程式的準確性。經過這次小小的練習,收穫頗豐,又將一些很少用到的基本知識複習了一般,不乏有長時間不用忘記的,其實,應該多拿出一些時間來實現某些簡單的小程式鞏固自己的基礎知識,拓實自己。

相關文章