OffsetIndex和TimeIndex分析
来源:互联网 发布:中国平安管培生 知乎 编辑:程序博客网 时间:2024/04/29 00:24
为了提高查找消息的性能,为每一个日志文件添加2个索引索引文件:OffsetIndex 和 TimeIndex,她俩分别对应着磁盘上两个索引文件,与FileMessageSet共同构成一个LogSegment对象。
OffsetIndex索引文件的格式: 每一个索引项为8字节,其中相对offset占用4字节,消息的物理地址(position)占用4个字节
这样就实现了相对offset与物理地址的映射,相对offset表示消息相对于baseOffSet的偏移量,例如分段后的一个日志文件的baseOffset是32450,它的文件名就是32450.log,那么offset为32455的消息在相对offset就是32455-32450 = 5。
另外OffsetIndex是稀疏索引,也就是说不会存储所有的消息的相对offset和position
OffsetIndexhe核心字段:
file: 指向磁盘上的索引文件
baseOffset: 对应日志文件第一个消息的offset
mmap: 用来操作索引文件的MappedByteBuffer
lock: ReentrantLock对象,在mmap进行操作的时候需要加锁保护
_entries:当前索引文件索引项的个数
_maxEntries: 当前索引文件中最多能够保存索引项个数
_lastOffset: 保存最后一个索引项的offset
/**
* 因为会有多个handler线程并发写入索引文件,所以这些字段使用@volatile,保证线程之间的可见性
*/
@volatile
protected var mmap: MappedByteBuffer= {
// 如果索引文件不存在则创建返回true,否则存在返回false
val newlyCreated= _file.createNewFile()
val raf =new RandomAccessFile(_file,"rw")
try {
/* 如有必要进行预分配空间 */
if(newlyCreated) {
//maxIndexSize值大小对索引文件分配大小,分配结果是小于maxIndexSize *8
if(maxIndexSize< entrySize)
throw new IllegalArgumentException("Invalidmax index size: "+ maxIndexSize)
raf.setLength(roundDownToExactMultiple(maxIndexSize,entrySize))
}
/* 内存映射 */
val len= raf.length()
val idx = raf.getChannel.map(FileChannel.MapMode.READ_WRITE,0, len)
/* 蒋新创建的索引文件的position设置为0,从头开始写文件 */
if(newlyCreated)
idx.position(0)
else
// 对于原来就存在的索引文件,则将position移动到索引项的结束位置,防止数据覆盖
idx.position(roundDownToExactMultiple(idx.limit,entrySize))
idx
} finally {
CoreUtils.swallow(raf.close())
}
}
// 添加指定offset/location对到索引中def append(offset: Long, position: Int) { inLock(lock) { require(!isFull, "Attempt to append to a full index (size = " + _entries + ").") if (_entries == 0 || offset > _lastOffset) { debug("Adding index entry %d => %d to %s.".format(offset, position, file.getName)) mmap.putInt((offset - baseOffset).toInt) mmap.putInt(position) _entries += 1 _lastOffset = offset require(_entries * entrySize == mmap.position, entries + " entries but file position in index is " + mmap.position + ".") } else { throw new InvalidOffsetException("Attempt to append an offset (%d) to position %d no larger than the last offset appended (%d) to %s." .format(offset, entries, _lastOffset, file.getAbsolutePath)) } }}
查找索引:
// 查找那些大于或者等于给定的offset的offset和positiondef lookup(targetOffset: Long): OffsetPosition = { maybeLock(lock) { val idx = mmap.duplicate // 创建一个副本 val slot = indexSlotFor(idx, targetOffset, IndexSearchType.KEY) if(slot == -1) OffsetPosition(baseOffset, 0) else parseEntry(idx, slot).asInstanceOf[OffsetPosition] }}
// 查找那些大于或者等于指定offset存储在哪一个slot上的protected def indexSlotFor(idx: ByteBuffer, target: Long, searchEntity: IndexSearchEntity): Int = { // check if the index is empty if(_entries == 0) return -1 // check if the target offset is smaller than the least offset if(compareIndexEntry(parseEntry(idx, 0), target, searchEntity) > 0) return -1 // 二分查找算法 var lo = 0 var hi = _entries - 1 while(lo < hi) { val mid = ceil(hi/2.0 + lo/2.0).toInt val found = parseEntry(idx, mid) val compareResult = compareIndexEntry(found, target, searchEntity) if(compareResult > 0) hi = mid - 1 else if(compareResult < 0) lo = mid else return mid } lo}
TimeIndex索引文件格式:它是映射时间戳和相对offset, 时间戳和相对offset作为entry,供占用12字节,时间戳占用8字节,相对offset占用4字节,这个索引也是稀疏索引,没有保存全部的消息的entry
TimeIndex查找添加算法和OffsetIndex差不多,不再赘述
- OffsetIndex和TimeIndex分析
- 相关分析和回归分析
- 情感分析和倾向分析
- SWOT分析和PEST分析
- PHP 抓取和分析
- 安全策略和需求分析
- alexa分析和作弊
- 基金分析和推荐
- 索引分析和优化
- 程序员和需求分析
- 分析智能和六西格玛
- 协议设计和分析
- wait()和sleep()分析
- ARP简介和分析
- OverLoad和OverRide分析
- ServletContext和ServletConfig分析
- cascade和inverse分析
- 原理图和时序分析
- 无线通信开题报告-GuoKunpeng
- 设计模式之状态模式
- Android APK之间的调用返回值
- Android平台下JNI调用第三方so库
- Linux Kernel 学习笔记10:hook函数
- OffsetIndex和TimeIndex分析
- Windows下搭建TensorFlow环境2(CPU版本)
- Android ShraeSDK分享
- 一份不错的php面试题(附答案)
- Linux tar.gz文件不全时解压错误现象
- 反射
- antd-mobile
- HTML5的 input:file上传类型控制
- Android--自定义Button的样式以及动态渐变效果