MongoDB Java Driver 源碼分析(13):OutputBuffer,BasicOutputBuffer 和 PoolOutputBuffer
Posted on 2012-04-15 16:27 zljpp 閱讀(178) 評論(0) 編輯 收藏
在之前的源代碼分析中我們經常遇到神秘的 OutMessage 類的實例,并調用它的 writeInt,query 等方法與 MongoDB 數據庫進行交互。
但 OutMessage 繼承了 BSONEncoder 類,而 BSONEncoder 的 writeInt 等方法實際上是委托給 OutputBuffer 類的實例執行的。
因此為了弄清楚 OutMessage 類的實例的行為,我們需要先了解 OutputBuffer 類的主要邏輯。
OutputBuffer 類是一個抽象類,有兩個子類: BasicOutputBuffer 和 PoolOutputBuffer。
OutputBuffer 的作用是緩沖對將要寫入到輸出流中的數據進行緩沖,準備好后通過 pipe 方法將數據輸出到輸出流中。
子類主要實現了抽象方法 write 和 pipe:
BasicOutputBuffer 類的 write 方法的實現如下:
BasicOutputBuffer 類的 pipe 方法的實現如下:
PoolOutputBuffer 類的 write 方法實現如下:
PoolOutputBuffer 類的 pipe 方法實現如下:
基于子類實現的 write 方法,OutputBuffer 實現了一系列 write* 方法
但 OutMessage 繼承了 BSONEncoder 類,而 BSONEncoder 的 writeInt 等方法實際上是委托給 OutputBuffer 類的實例執行的。
因此為了弄清楚 OutMessage 類的實例的行為,我們需要先了解 OutputBuffer 類的主要邏輯。
BasicOutputBuffer 和 PoolOutputBuffer 的 write 和 pipe 方法的實現
OutputBuffer 類是一個抽象類,有兩個子類: BasicOutputBuffer 和 PoolOutputBuffer。
OutputBuffer 的作用是緩沖對將要寫入到輸出流中的數據進行緩沖,準備好后通過 pipe 方法將數據輸出到輸出流中。
子類主要實現了抽象方法 write 和 pipe:
public abstract void write(byte[] b, int off, int len); public abstract void write(int b); public abstract int pipe( OutputStream out );
BasicOutputBuffer 類的 write 方法的實現如下:
// 寫入數據到緩沖區 public void write(byte[] b, int off, int len){ // 保證緩沖區空間足夠 // 不夠則開辟新的空間 _ensure( len ); // 復制數據到緩沖區 System.arraycopy( b , off , _buffer , _cur , len ); // 改變代表偏移量和緩沖區大小的數字 _cur += len; _size = Math.max( _cur , _size ); } // 保證緩沖區空間足夠 // 不夠則開辟新的空間 void _ensure( int more ){ // 計算需要的大小 final int need = _cur + more; // 目前的緩沖區大小足夠。 // 不再開辟新的空間 if ( need < _buffer.length ) return; // 新的緩沖區大小是原來的兩倍 int newSize = _buffer.length*2; // 如果仍然不夠,開辟更大的空間 if ( newSize <= need ) newSize = need + 128; // 創建數組 byte[] n = new byte[newSize]; // 將緩沖區中數據復制到數組中 System.arraycopy( _buffer , 0 , n , 0 , _size ); // 以新的數組作為緩沖區 _buffer = n; } // 只寫入一個字節 public void write(int b){ // 保證有一個字節的空間 _ensure(1); // 將 int 型數據的低 8 位保存到緩沖區 _buffer[_cur++] = (byte)(0xFF&b); // 修改表示緩沖區數據大小的數值 _size = Math.max( _cur , _size ); }
BasicOutputBuffer 類的 pipe 方法的實現如下:
public int pipe( OutputStream out ) throws IOException { // 將緩沖區中的數據寫入輸出流中 out.write( _buffer , 0 , _size ); // 返回緩沖區大小 return _size; }
PoolOutputBuffer 類的 write 方法實現如下:
public void write(byte[] b, int off, int len){ while ( len > 0 ){ // 獲取一塊當前緩沖區空間 byte[] bs = _cur(); // 計算本次寫入大小 int space = Math.min( bs.length - _cur.y , len ); // 將數據復制緩沖區 System.arraycopy( b , off , bs , _cur.y , space ); // 修改偏移量等后續工作 _cur.inc( space ); len -= space; off += space; // 其他后續處理 // 如緩沖區滿時,創建下一個緩沖區塊等 _afterWrite(); } } // 只寫入一個字節 public void write(int b){ // 獲取緩沖區空間 byte[] bs = _cur(); // 將 int 型數值的低 8 為保存到緩沖區 bs[_cur.getAndInc()] = (byte)(b&0xFF); // 后續處理 _afterWrite(); }
PoolOutputBuffer 類的 pipe 方法實現如下:
public int pipe( OutputStream out ) throws IOException { if ( out == null ) throw new NullPointerException( "out is null" ); int total = 0; for ( int i=-1; i<_fromPool.size(); i++ ){ // 獲取對象池中指定索引的數據 byte[] b = _get( i ); // 獲取對象池中指定索引的數據的大小 int amt = _end.len( i ); // 將數據寫入到輸出流中 out.write( b , 0 , amt ); // 增加表示總數據大小的數值 total += amt; } return total; }
OutputBuffer 類的 write* 方法
基于子類實現的 write 方法,OutputBuffer 實現了一系列 write* 方法
// 寫入 int 型 public void writeInt( int x ){ // 寫入第 1 個字節(第 1 - 8 位) write( x >> 0 ); // 寫入第 2 個字節(第 9 - 16 位) write( x >> 8 ); // 寫入第 3 個字節(第 17 - 24 位) write( x >> 16 ); // 寫入第 4 個字節(第 25 - 32 位) write( x >> 24 ); } // 按“大端”(Big End) 法 寫入 int 型 public void writeIntBE( int x ){ // 寫入第 4 個字節(第 25 - 32 位) write( x >> 24 ); // 寫入第 3 個字節(第 17 - 24 位) write( x >> 16 ); // 寫入第 2 個字節(第 9 - 16 位) write( x >> 8 ); // 寫入第 1 個字節(第 1 - 8 位) write( x ); } // 指定位置寫入 int 型數據 public void writeInt( int pos , int x ){ // 獲取當前位置 final int save = getPosition(); // 設置當前位置 setPosition( pos ); // 寫入 int 型數據 writeInt( x ); // 恢復當前位置 setPosition( save ); } // 寫入 long 型數值 public void writeLong( long x ){ // 寫入第 1 個字節(第 1 - 8 位) write( (byte)(0xFFL & ( x >> 0 ) ) ); // 寫入第 2 個字節(第 9 - 16 位) write( (byte)(0xFFL & ( x >> 8 ) ) ); // 寫入第 3 個字節(第 17 - 24 位) write( (byte)(0xFFL & ( x >> 16 ) ) ); // 寫入第 4 個字節(第 25 - 32 位) write( (byte)(0xFFL & ( x >> 24 ) ) ); // 寫入第 5 個字節(第 33 - 40 位) write( (byte)(0xFFL & ( x >> 32 ) ) ); // 寫入第 6 個字節(第 41 - 48 位) write( (byte)(0xFFL & ( x >> 40 ) ) ); // 寫入第 7 個字節(第 49 - 56 位) write( (byte)(0xFFL & ( x >> 48 ) ) ); // 寫入第 8 個字節(第 57 - 64 位) write( (byte)(0xFFL & ( x >> 56 ) ) ); } // 寫入 double 型數值 public void writeDouble( double x ){ // 將 double 型轉為 long 型 (IEEE 754 表示法) 后寫入 writeLong( Double.doubleToRawLongBits( x ) ); }