【lucene】ByteBufferGuard
`ByteBufferGuard` 是 Lucene 用来**保护 `ByteBuffer` 不被非法访问或提前释放**的一个 **安全/防御性机制**。
---
### ✅ 一句话解释:
> `ByteBufferGuard` 是一个“守门员”,确保你在使用 `ByteBuffer` 的时候:
> - 不会越界访问(读/写非法区域)
> - 不会读到已经释放(unmap)的内存
> - 不会并发读写冲突(线程安全)
---
### ✅ 为什么需要它?
Lucene 的底层实现中,很多 `IndexInput`(比如 `MMapDirectory` 的 `ByteBufferIndexInput`)是基于 **内存映射文件(mmap)** 的 `ByteBuffer`。
但 `ByteBuffer` 有一个致命问题:
- 如果底层文件被关闭(`unmap`),你再访问这个 `ByteBuffer`,**JVM 会直接崩溃(segmentation fault)**。
- 多线程访问同一个 `ByteBuffer` 也不安全。
---
### ✅ `ByteBufferGuard` 做了什么?
| 功能 | 说明 |
|------|------|
| **防止越界** | 检查 `position + length` 是否在合法范围内 |
| **防止 use-after-free** | 检查底层 buffer 是否已经被 unmap |
| **线程安全** | 提供 `read()` 和 `write()` 的同步包装 |
| **调试/诊断** | 在非法访问时抛出清晰的异常(而不是 JVM 崩溃) |
---
### ✅ 举个例子(伪代码)
```java
ByteBuffer buffer = ...; // mmap 的文件
ByteBufferGuard guard = new ByteBufferGuard("myfile.cfs");
// 安全读取
guard.read(buffer, position, length, (buf, off, len) -> {
// 真正的读取逻辑
});
```
---
### ✅ 总结一句话:
> `ByteBufferGuard` 是 Lucene 用来**防止 ByteBuffer 被越界、并发或已释放内存访问**的“安全守卫”,尤其在 `MMapDirectory` 等底层实现中非常关键。
是 **Lucene 专门为 `ByteBufferIndexInput`(特别是 MMapDirectory 的内存映射实现)设计的一个“安全锁”**,用于防止:
- **访问已 unmap 的内存**(会导致 JVM 崩溃)
- **并发读写冲突**
- **越界访问**
---
### ✅ 一句话总结
> `ByteBufferGuard` 是一个“**内存访问看门狗**”:
> 一旦底层 `ByteBuffer` 被释放(unmap),它就**拒绝所有后续访问**,抛出异常而不是让 JVM 崩溃。
---
### ✅ 关键机制解析
#### 🔒 1. **防止访问已释放的内存**
- 使用一个布尔标志 `invalidated`(非 volatile,出于性能考虑)
- 一旦被标记为 `invalidated`,所有 `getXxx()` 方法都会抛出 `NullPointerException`,
最终由 `ByteBufferIndexInput` 包装成 `AlreadyClosedException`
#### 🧹 2. **unmap 支持**
- 通过 `BufferCleaner` 接口(函数式接口)实现真正的 unmap 操作
- 这是 MMapDirectory 实现的,用私有 API 解除内存映射
#### ⚙️ 3. **线程可见性 & 缓存一致性**
- 使用 `AtomicInteger.lazySet(0)` 作为**轻量级内存屏障**(store-store barrier)
- 调用 `Thread.yield()` 让其他线程有机会完成当前读取,避免 race condition
---
### ✅ 工作流程图
```
ByteBufferIndexInput.readInt()
↓
ByteBufferGuard.getInt(buffer)
↓
ensureValid() 检查 invalidated
↓
如果 invalidated == true → NullPointerException → AlreadyClosedException
↓
否则正常读取
```
---
### ✅ 举个例子
```java
IndexInput in = MMapDirectory.open("index").openInput("segments_N", IOContext.DEFAULT);
in.readInt(); // ✅ 正常读取
in.close(); // 触发 ByteBufferGuard.invalidateAndUnmap(...)
in.readInt(); // ❌ 抛出 AlreadyClosedException
```
---
### ✅ 总结一句话
> `ByteBufferGuard` 是 Lucene 在内存映射文件(mmap)场景下的“最后一道防线”,防止访问已释放内存导致 JVM 崩溃,同时兼顾性能与线程安全。