|
在Mongodb中,其使用了操作系统底层提供的内存映射机制,即MMAP。MMAP可以把磁盘文件的一部分或全部内容直接映射到内存,这样文件中的信息位置就会在内存中有对应的地址空间,这时对文件的读写可以直接用指针来做,而不需要read/write函数了。同时操作系统会将数据刷新保存到磁盘上。如下图:
鉴于linux,window系统为mmap所提供的API大同小异(见下图)。这里仅以mongodb对window系统的mmap调用机制为例,来说明一下其具体的实现方式,以及在mongodb启动时,客户端提交查询和插入操作请求时mongodb的mmap执行流程。

上面类图中:
MongoFile:定义了mongo文件对象常用操作,包括创建,关闭,设置名称,flushAll,获取MongoFile文件总尺寸等。
MMF: 一个类型定义,其声明:typedef MemoryMappedFile MMF;
MongoMMF:为了便于journaling/durability操作,对MemoryMappedFile进行了一些封装(特别是对private views )
下面着重看一下windows提供的mmap的常用API:
MapViewOfFile(): 把文件数据映射到进程的地址空间
CreateFileMapping() : 创建一个新的文件映射内核对象
FlushViewOfFile(): 强制系统将内存中修改过的数据重新写入磁盘映像,从而可以确保所有的数据更新能及时保存到磁盘
CloseHandle(): 关闭文件映射对象和文件对象
MapViewOfFileEx(): 将文件映射到指定的进程地址空间
参数说明:
MapViewOfFile(
__in HANDLE hFileMappingObject, /*hFileMappingObject是共享文件对象*/
__in DWORD dwDesiredAccess, /*dwDesiredAccess是文件共享属性*/
__in DWORD dwFileOffsetHigh, /*dwFileOffsetHigh是文件共享区的偏移地址*/
__in DWORD dwFileOffsetLow, /*dwFileOffsetLow是文件共享区的偏移地址*/
__in SIZE_T dwNumberOfBytesToMap /*dwNumberOfBytesToMap是共享数据长度*/
);
//winbase.h
CreateFileMappingW(
__in HANDLE hFile, /*hFile是创建共享文件的句柄*/
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes, /*lpFileMappingAttributes是文件共享的属性*/
__in DWORD flProtect, /*flProtect是当文件映射时读写文件的属性*/
__in DWORD dwMaximumSizeHigh, /*是文件共享的大小高位字节*/
__in DWORD dwMaximumSizeLow, /*是文件共享的大小低位字节*/
__in_opt LPCWSTR lpName /*lpName是共享文件对象名称*/
);
#ifdef UNICODE
#define CreateFileMapping CreateFileMappingW
#else
#define CreateFileMapping CreateFileMappingA
#endif // !UNICODE
FlushViewOfFile(
__in LPCVOID lpBaseAddress, /*内存映射文件中的视图的一个字节的地址*/
__in SIZE_T dwNumberOfBytesToFlush /*想要刷新的字节数*/
);
MapViewOfFileEx(
__in HANDLE hFileMappingObject, /*共享文件对象*/
__in DWORD dwDesiredAccess, /*文件共享属性*/
__in DWORD dwFileOffsetHigh, /*文件共享区的偏移地址*/
__in DWORD dwFileOffsetLow, /*文件共享区的偏移地址*/
__in SIZE_T dwNumberOfBytesToMap /*共享数据长度*/
__in_opt LPVOID lpBaseAddress /*指定映射文件映射对象的地址。如这个地址处没有足够的内存空间,
那么对MapViewOfFileEx的调用会失效*/
);
下面我们看一下mongodb如何使用上述API,来实现windows环境下对mongofile进行mmap操作的.
//mmap_win.cpp
mutex mapViewMutex("mapView");//声明mapView的互斥体(mutex)对象
ourbitset writable;
/** unmapping 通知,以便清空 writable bits */
void MemoryMappedFile::clearWritableBits(void *p) {
for( unsigned i = ((size_t)p)/ChunkSize; i createExtent(ns, approxSize, newCapped, loops+1);
.....
}
最后在addAFile方法中,我们会看下如下代码段:
//database.cpp
MongoDataFile* Database::addAFile( int sizeNeeded, bool preallocateNextFile ) {
int n = (int) files.size();
MongoDataFile *ret = getFile( n, sizeNeeded );//调用下面的getFile方法
.....
}
//database.cpp
MongoDataFile* Database::getFile( int n, int sizeNeeded , bool preallocateOnly) {
......
namespaceIndex.init();
.....
}
//namespace.cpp
void NamespaceIndex::init() {
......
unsigned long long len = 0;
boost::filesystem::path nsPath = path();
string pathString = nsPath.string();
void *p = 0;
if( MMF::exists(nsPath) ) {//使用本文前面提到的MMF类,判断数据库文件是否存在
if( f.open(pathString, true) ) {//打开指定的文件并执行mmap操作
len = f.length();
if ( len % (1024*1024) != 0 ) {
log() |
|
|