indexFile(索引文件)和 ConsumeQueue(消费队列),都是为了更快的查找而建立的索引,后者是根据topic,前者是根据key。在ReputMessageService(一个ServiceThread的实现类)的doReput方法中,

会循环遍历每一条新收到的消息,

DefaultMessageStore.this.doDispatch(dispatchRequest)-->CommitLogDispatcherBuildIndex/CommitLogDispatcherBuildConsumeQueue.doDispatch,

先看前者,到了indexService.buildIndex,key分为两种,一种是UniqKey,系统自动生成的,相当于uuid?在之前的事务消息里提到过?还有一种是自定义的key,放在message的property中的

indexFile的数据结构最关键:20个字节的header + 500万*4个字节的slotSize + 2000万 * 20个字节的indexSize,先用hash值对500万取余确定slot位置,

4字节的slot里放的是indexCount,也就是后面每一个index在2000万个indexSize中的排序。

而indexSize中,20个字节里放的是4字节的hash值+8个字节的消息实际位移+4个字节一个时间差啥的+4个字节的slotValue

如果有hash冲突,slotValue存的就是上一个hash冲突的index的indexCount(因为当前位置的hash位置已经存了当前index的indexCount了),否则就是0。

这样就形成了链表结构,解决了hash冲突。code为QUERY_MESSAGE(12)的请求,会调用本方法,所以我们实现的DefaultMQPushConsumer等consumer是有queryMessage()方法的。注意收到的消息列表,

key可能是其他hash冲突的key,要过滤,这是因为indexFile只存hash值不存key值,没办法帮我们过滤

ps:consumer在queryMessage的时候,是遍历indexFile的list,这时候需要传入开始和结束时间,缩小查找indexFile的范围,在缩小范围后的indexFile再用hash+链表的办法查找。还有就是要遍历所有的brokerAddrs。