我们正在尝试更改嵌入式数据库系统SQLite,使用mmap()而不是通常的read()和write()调用来访问磁盘上的数据库文件.对整个文件使用单个大映射.假设文件足够小,我们可以毫不费力地在虚拟内存中找到空间.
到现在为止还挺好.在许多情况下,使用mmap()似乎比read()和write()快一点.而且在某些情况下要快得多.
调整映射大小以提交扩展数据库文件的写事务似乎是个问题.为了扩展数据库文件,代码可以执行以下操作:
ftruncate(); // extend the database file on disk
munmap(); // unmap the current mapping (it's now too small)
mmap(); // create a new, larger, mapping
Run Code Online (Sandbox Code Playgroud)
然后将新数据复制到新内存映射的末尾.但是,munmap/mmap是不合需要的,因为这意味着下次访问数据库文件的每一页时都会发生次要页面错误,并且系统必须在OS页面缓存中搜索与虚拟内存地址关联的正确帧.换句话说,它会减慢后续数据库读取速度.
在Linux上,我们可以使用非标准的mremap()系统调用而不是munmap()/ mmap()来调整映射的大小.这似乎可以避免次要页面错误.
问题:如何在没有mremap()的其他系统(如OSX)上处理这个问题?
我们目前有两个想法.关于每个问题:
1)创建大于数据库文件的映射.然后,在扩展数据库文件时,只需调用ftruncate()以扩展磁盘上的文件并继续使用相同的映射.
这将是理想的,似乎在实践中起作用.但是,我们在手册页中担心这个警告:
"未指定更改与文件的添加或删除区域对应的页面上的映射的基础文件的大小的效果."
问题:这是我们应该担心的吗?或者在这一点上不合时宜?
2)扩展数据库文件时,使用mmap()的第一个参数来请求与虚拟内存中当前映射之后的数据库文件的新页面对应的映射.有效地扩展初始映射.如果系统无法遵守在第一个之后立即放置新映射的请求,则回退到munmap/mmap.
在实践中,我们发现OSX非常适合以这种方式定位映射,所以这个技巧在那里工作.
问题:如果系统确实在第一个虚拟内存之后立即分配第二个映射,那么使用对munmap()的单个大调用最终是否可以安全地取消映射它们?
对于发送到 Amazon S3 Blob 存储的 PUT 请求,是否存在与“If-Match”(Azure) 或“x-goog-if- Generation-match”(Google Storage) 等效的等效项?
这两个标头都执行相同的操作 - 它们允许您指定覆盖对象的 PUT 请求仅在覆盖对象的特定先前版本时才应成功。细节:
https://cloud.google.com/storage/docs/xml-api/reference-headers#xgoogif Generationmatch
谢谢!
例如,如果我这样做:
char *pMap1; /* First mapping */
char *pReq; /* Address we would like the second mapping at */
char *pMap2; /* Second mapping */
/* Map the first 1 MB of the file. */
pMap1 = (char *)mmap(0, 1024*1024, PROT_READ, MAP_SHARED, fd, 0);
assert( pMap1!=MAP_FAILED );
/* Now map the second MB of the file. Request that the OS positions the
** second mapping immediately after the first in virtual memory. */
pReq = pMap1 + 1024*1024;
pMap2 = …Run Code Online (Sandbox Code Playgroud)