RecordAccumulator中最终存放消息的对象MemoryRecords。MemoryRecords表示的是多个消息的集合,其中封装了Java NIO ByteBuffer类,MemoryRecords主要字段有:
public class MemoryRecords implements Records {
private final static int WRITE_LIMIT_FOR_READABLE_ONLY = -1;
// 压缩器,支持GZIP,SNAPPY,LZ4三种压缩方式
// Compressor有ByteBufferOutputStream bufferStream字段,集成了java.io.OutputStream,封装了ByteBuffer,会进行自动扩容。
// 扩容后,Compressor里ByteBufferOutputStream会指向一个新的Bytebuffer对象,会与MemoryRecords.buffer不一样。
private final Compressor compressor;
// buffer中最多可以写入多少个字节的数据
private final int writeLimit;
// buffer大小
private final int initialCapacity;
// 用来保存消息的java.nio.ByteBuffer
private ByteBuffer buffer;
// 此MemoryRecords是只读模式,还是可写模式。在MemoryRecords发送前时,会设置成只读模式
private boolean writable;
//判断MemoryRecords是否为可写模式,然后调用Compressor.put(java.nio.ByteBuffer)方法把消息写到ByteBuffer中
public void append(long offset, Record record)
//根据Compressor估计已经写的字节数,只是个估计,可能会导致ByteBuffer扩容情况。
public boolean hasRoomFor(byte[] key, byte[] value)
// Close this batch for no more appends
// 当出现ByteBuffer扩容的情况,MemoryRecords.buffer和ByteBufferOutputStream.buffer指向的已经不是不是一个ButeBuffer对象。
// close方法会把MemoryRecords.buffer指向扩容后的ByteBuffer对象
public void close()
// 对于可读的MemoryRecords,返回的是MemoryRecords.buffer.limit,对于可写的,返回ByteBufferOutputStream.buffer字段的大小。
public int sizeInBytes()
}
看MemoryRecords的构造函数:
public class MemoryRecords implements Records {
// Construct a writable memory records
private MemoryRecords(ByteBuffer buffer, CompressionType type, boolean writable, int writeLimit) {
// 根据入参赋值writable、writeLimit
this.writable = writable;
this.writeLimit = writeLimit;
// Java NIO中ByteBuffer的capacity
this.initialCapacity = buffer.capacity();
if (this.writable) {// 如果writable为true,即处于可写状态
this.buffer = null;
// 利用入参ByteBuffer类型的buffer和CompressionType类型的type构造Compressor实例compressor
this.compressor = new Compressor(buffer, type);
} else {
// buffer设置为入参ByteBuffer类型的buffer
this.buffer = buffer;
// compressor设置为null
this.compressor = null;
}
}
}
append函数把消息添加到MemoryRecords中。
public class MemoryRecords implements Records {
public long append(long offset, long timestamp, byte[] key, byte[] value) {
// 首先判断MemoryRecords的可写标志位writable
if (!writable)
throw new IllegalStateException("Memory records is not writable");
// 根据key、value通过Record的recordSize()方法计算记录大小size
int size = Record.recordSize(key, value);
// 压缩器compressor中记录偏移量offset、记录大小size、记录key和value
compressor.putLong(offset);
compressor.putInt(size);
// putRecord最后会把消息放在appendStream中。
long crc = compressor.putRecord(timestamp, key, value);
// 而已写入未压缩总大小writtenUncompresse是记录大小size再加上size所占大小(int类型)和offset所占大小(long类型)之和,也就是额外的Int+Long为12
compressor.recordWritten(size + Records.LOG_OVERHEAD);
return crc;
}
}
hasRoomFor方法判断是否还能写入。
public class MemoryRecords implements Records {
public boolean hasRoomFor(byte[] key, byte[] value) {
if (!this.writable)
return false;
// 判断写入的数据大小是否为0,是0的话,直接用capacity判断,不是的话用writeLimit判断。
return this.compressor.numRecordsWritten() == 0 ?
this.initialCapacity >= Records.LOG_OVERHEAD + Record.recordSize(key, value) :
//estimatedBytesWritten预估消息压缩后大小
this.writeLimit >= this.compressor.estimatedBytesWritten() + Records.LOG_OVERHEAD + Record.recordSize(key, value);
}
}