当前位置: 首页 > news >正文

【lucene】MMapDirectory 在FSDirectory基础上干了啥?

一句话:  
**MMapDirectory 只是把 “读写文件” 从普通的 FileChannel I/O 换成了 mmap(内存映射),其余所有逻辑(文件创建、删除、锁、pending_segments 处理等)都和 FSDirectory 共用同一套代码**。

---

### 1. FSDirectory 已经做了什么  
FSDirectory 提供了:  
- 创建/打开/删除文件的统一实现(createOutput / openInput / deleteFile)  
- 对 pendingDeletes、文件锁、临时文件的处理  
- 可插拔的 `FSIndexOutput`/`FSIndexInput` 实现(用 `FileChannel.read/write` 做真正的 I/O)  

---

### 2. MMapDirectory 只改了 I/O 实现  
```java
public final class MMapDirectory extends FSDirectory {
...
@Override
public IndexInput openInput(String name, IOContext context) throws IOException {
ensureOpen();
Path path = directory.resolve(name);
// 用 mmap 而不是 FileChannel.read
return new MMapIndexInput(name, path, chunkSizePower, preload, useUnmapHack);
}

    /* IndexOutput 仍然是 FSIndexOutput(FileChannel.write),
因为 mmap 写文件需要 RandomAccessFile + rw,且性能不一定更好,
Lucene 只在“读”路径用 mmap,“写”路径保留 FileChannel。 */
}
```

- **读文件** → `MMapIndexInput`:把文件映射到 `MappedByteBuffer`,后续读操作就是内存访问。  
- **写文件** → 仍用 `FSIndexOutput`(FileChannel.write),因为:  
- mmap 写需要 `RandomAccessFile` + `MapMode.READ_WRITE`,且每次扩展文件长度要重新映射,成本高;  
- 写通常是顺序大块写入,FileChannel 反而更快。  

---

### 3. 额外提供的调优参数  
MMapDirectory 额外暴露:  
- `setPreload(true)`:在 map 后立即 `madvise(MADV_WILLNEED)`,减少首次访问缺页。  
- `setUseUnmapHack(true)`:用 Cleaner 或 Unsafe 手动 `unmap`,避免 64-bit JVM 下映射残留导致 “无法删除文件” 的问题(Windows 上尤其重要)。  

---

### 总结对比

| 维度            | FSDirectory 默认实现 | MMapDirectory                      |
|-----------------|----------------------|------------------------------------|
| Directory 框架  | ✅ 同一套             | ✅ 继承 FSDirectory                |
| 读文件          | FileChannel.read     | mmap(MappedByteBuffer)          |
| 写文件          | FileChannel.write    | 同 FSDirectory(未用 mmap)       |
| 额外调优        | 无                   | preload、unmapHack、chunkSizePower |
| 适用场景        | 通用                 | 读多写少,64-bit、大索引、随机查  |

因此:**MMapDirectory = FSDirectory + 读路径换成 mmap,其余完全复用**。

对,**在 open reader 的环节差异最大**:

1. 当你调用  
`DirectoryReader.open(directory)` 或 `IndexReader.open(...)`  
最终都会走到 `SegmentCoreReaders` → `openInput(name, IOContext.READONCE / RANDOM / MERGE)` 去为每个段文件(`.cfs`, `.fdx`, `.tim`, `.doc`, …)创建 `IndexInput`。

2. 如果目录是:
- **FSDirectory** → 返回 `FSIndexInput`,底层是 `FileChannel.read`  
- **MMapDirectory** → 返回 `MMapIndexInput`,底层是 `MappedByteBuffer`(mmap)

3. **差异只在读阶段**  
- 写文件时两者都走 `FSIndexOutput`(FileChannel.write),没有 mmap。  
- 因此只有 **reader 打开后** 的随机访问、倒排表遍历、跳表查询等读操作,才会体验到 mmap 带来的:
- 地址空间直接映射,减少一次内核→用户空间拷贝  
- 大文件分段映射,降低 GC 压力  
- 预读/缓存效果由 OS 页缓存自动完成

4. **对上层 API 没区别**  
上层代码(`IndexSearcher.search`, `TermsEnum`, `StoredFields`…)感知不到,只是底层 `IndexInput` 实现不同。

一句话:**writer 阶段无差异;reader 阶段因 mmap 而提速,尤其随机读多的查询**。

http://www.dtcms.com/a/301029.html

相关文章:

  • 链表算法综合——重排链表
  • KNN 算法中的各种距离:从原理到应用
  • D3.js的力导向图使用入门笔记
  • AI行业热点抓取和排序系统实现案例
  • [Linux入门] Linux 远程访问及控制全解析:从入门到实战
  • Jmeter的元件使用介绍:(七)后置处理器详解
  • 10.迭代器模式
  • 设计模式(二)创建型:工厂方法模式详解
  • 设计模式(十一)结构型:外观模式详解
  • rename系统调用及示例
  • docker-desktop引擎启动失败报wsl --update
  • 推荐系统学习
  • QML视图组件:ListView、GridView、TableView、PathView
  • MyBatis Plus 乐观锁与悲观锁
  • 《C++ list 完全指南:list的模拟实现》
  • NodeJs接入腾讯云存储COS
  • MySQL 用户管理
  • 第六章 JavaScript 互操(3)JS调用.NET
  • Django5.1(131)—— 表单 API二(API参考)
  • 电科金仓 KingbaseES 深度解码:技术突破・行业实践・沙龙邀约 -- 融合数据库的变革之力
  • Java面试宝典:MySQL索引
  • 2-4、Dify案例实践—基于工作流构建商城用户评价智能分析系统
  • PyTorch武侠演义 第一卷:初入江湖 第7章:矿洞中的计算禁制
  • 基于mnn架构在本地 c++运行llm与mllm模型
  • 数据结构基本内容(第四篇:队列)
  • 2025.7.27
  • Java面试题及详细答案120道之(061-080)
  • C++算法竞赛篇(六)一维数组题型讲解
  • 【工具】python汇总发票(含源码)
  • Java排序算法之<希尔排序>