提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
在消息处理后,会有内存回收的过程this.accumulator.deallocate(batch);
private void completeBatch(RecordBatch batch, Errors error, long baseOffset, long timestamp, long correlationId, long now) {
//如果响应里面带有异常 并且 这个请求是可以重试的
if (error != Errors.NONE && canRetry(batch, error)) {
// retry
log.warn("Got error produce response with correlation id {} on topic-partition {}, retrying ({} attempts left). Error: {}",
correlationId,
batch.topicPartition,
this.retries - batch.attempts - 1,
error);
//重新把发送失败等着批次 加入到队列里面。
this.accumulator.reenqueue(batch, now);
this.sensors.recordRetries(batch.topicPartition.topic(), batch.recordCount);
} else {
//这儿过来的数据:带有异常,但是不可以重试(1:压根就不让重试2:重试次数超了)
//其余的都走这个分支。
RuntimeException exception;
//如果响应里面带有 没有权限的异常
if (error == Errors.TOPIC_AUTHORIZATION_FAILED)
//自己封装一个异常信息(自定义了异常)
exception = new TopicAuthorizationException(batch.topicPartition.topic());
else
//
exception = error.exception();
// tell the user the result of their request
//TODO 核心代码 把异常的信息也给带过去了
//我们刚刚看的就是这儿的代码
//里面调用了用户传进来的回调函数
//回调函数调用了以后
//说明我们的一个完整的消息的发送流程就结束了。
batch.done(baseOffset, timestamp, exception);
//看起来这个代码就是要回收资源的。
this.accumulator.deallocate(batch);
if (error != Errors.NONE)
this.sensors.recordErrors(batch.topicPartition.topic(), batch.recordCount);
}
if (error.exception() instanceof InvalidMetadataException) {
if (error.exception() instanceof UnknownTopicOrPartitionException)
log.warn("Received unknown topic or partition error in produce request on partition {}. The " +
"topic/partition may not exist or the user may not have Describe access to it", batch.topicPartition);
metadata.requestUpdate();
}
// Unmute the completed partition.
if (guaranteeMessageOrder)
this.accumulator.unmutePartition(batch.topicPartition);
}
调用deallocate()
public void deallocate(RecordBatch batch) {
//从某个数据结构里面移除 已经成功处理的批次
incomplete.remove(batch);
//释放内存
free.deallocate(batch.records.buffer(), batch.records.initialCapacity());
}
public void deallocate(ByteBuffer buffer, int size) {
lock.lock();
try {
//如果你还回来的内存的大小 就等于一个批次的大小,
//我们的参数设置的内存是16K,你计算出来一个批次的大小也是16,申请的内存也是16k
if (size == this.poolableSize && size == buffer.capacity()) {
//内存里面的东西清空
buffer.clear();
//把内存放入到内存池
this.free.add(buffer);
} else {
//但是如果 我们释放的内存的大小
//不是一个批次的大小,那就把归为可用内存
//等着垃圾回收即可
this.availableMemory += size;
}
Condition moreMem = this.waiters.peekFirst();
if (moreMem != null)
//释放了内存(或者是还了内存以后)
//都会唤醒等待内存的线程。
//接下来是不是还是要唤醒正在等待分配内存的线程。
moreMem.signal();
} finally {
lock.unlock();
}
}