读书人

MongoDB Java Driver 源码分析(13):O

发布时间: 2012-07-15 20:20:06 作者: rapoo

MongoDB Java Driver 源码分析(13):OutputBuffer,BasicOutputBuffer 和 PoolOutputBuffer
  在之前的源代码分析中我们经常遇到神秘的 OutMessage 类的实例,并调用它的 writeInt,query 等方法与 MongoDB 数据库进行交互。
  但 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 ) );    }

读书人网 >其他数据库

热点推荐