mmap

mmap

数据库存储引擎要解决的主要问题之一是如何处理磁盘中大于可用内存的数据。从更高的层面来说,面向磁盘的存储引擎的主要目的是操作磁盘中的数据文件。但如果我们假设磁盘中的数据最终会大于可用内存,我们就不能简单地将整个数据文件加载到内存中,进行更改,然后再写回磁盘。这在计算机科学中并不是一个新问题。在 20 世纪 60 年代初开发操作系统时,就面临着类似的问题:如何运行存储在磁盘中的程序,而这些程序又大于可用的内存?1961 年,曼彻斯特的一个小组提出了解决这个问题的方法,并在 Atlas 计算机上实现。它被称为虚拟内存。虚拟内存给正在运行的程序一种错觉,认为它有足够大的内存,尽管事实上计算机没有足够的内存。

当一个程序在访问内存时,就是在访问虚拟内存。而也许程序要访问的数据其实并不在内存中,但这并不重要。操作系统会通过到磁盘上,把它假装成在磁盘上,然后放在那里,并替换掉一块旧的、不会被使用的内存。所以,数据库存储引擎解决大于内存问题的方法之一就是利用虚拟内存和内存映射文件的概念。在 Linux 中,我们可以通过使用系统调用 mmap 来实现这一用途,它可以让你直接将一个文件(无论多大的文件)映射到内存中。如果你的程序需要操作文件,只需要操作内存就可以了。操作系统会为你处理写入磁盘的事情。

mmap 简单示例

package main

import (
	"os"
	"fmt"
	"github.com/edsrzf/mmap-go"
)

func main() {
	f, _ := os.OpenFile("./file", os.O_RDWR, 0644)
	defer f.Close()

	mmap, _ := mmap.Map(f, mmap.RDWR, 0 )
	defer mmap.Unmap()
	fmt.Println(string(mmap))

	mmap[0] = 'X'
	mmap.Flush()
}

美中不足的是,我们可以有一个更大的文件,而这个解决方案仍然有效。我们不必担心为了避免内存被填满而管理内存。