Sqlite源码解读(十一)

2021SC@SDUSC

接着winShmNode继续讲。

PShmNode上的引用计数已经在winShmEnterMutex()互斥体的覆盖下递增,并且指向pShmNode的新对象的指针已经设置。剩下要做的就是将新对象链接到从pShmNode->pFirst开始的链接列表中,这必须在持有pShmNode->mutex互斥时完成。

  sqlite3_mutex_enter(pShmNode->mutex);

  p->pNext = pShmNode->pFirst;

  pShmNode->pFirst = p;

  sqlite3_mutex_leave(pShmNode->mutex);

  return rc;

跳到任何错误上

shm_open_err:

  winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);

  winShmPurge(pDbFd->pVfs, 0);      /* 如果需要的话,此调用将释放pShmNode */

  sqlite3_free(p);

  sqlite3_free(pNew);

  winShmLeaveMutex();

  return rc;

}

关闭到共享内存的连接。如果删除标志为true,则删除底层存储。

static int winShmUnmap(

  sqlite3_file *fd,             /*持有共享内存的数据库 */

  int deleteFlag              /* 如果true则在关闭后删除 */

){

  winFile *pDbFd;            /* 持有共享内存的数据库*/

  winShm *p;               /*将要关闭的连接*/

  winShmNode *pShmNode;  /* 底层的共享内存文件 */

  winShm **pp;             /* 在兄弟连接上循环 */

  pDbFd = (winFile*)fd;

  p = pDbFd->pShm;

  if( p==0 ) return SQLITE_OK;

  pShmNode = p->pShmNode;

从与pShmNode关联的一组连接中删除连接p

sqlite3_mutex_enter(pShmNode->mutex);

  for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}

  *pp = p->pNext;

释放连接P

sqlite3_free(p);

  pDbFd->pShm = 0;

  sqlite3_mutex_leave(pShmNode->mutex);

如果pShmNode->nREF达到0,则关闭底层共享内存文件

winShmEnterMutex();

  assert( pShmNode->nRef>0 );

  pShmNode->nRef--;

  if( pShmNode->nRef==0 ){

    winShmPurge(pDbFd->pVfs, deleteFlag);

  }

  winShmLeaveMutex();

  return SQLITE_OK;

}

在共享内存上实现内存屏障或内存隔离。在屏障之前开始的所有装载和储存必须在任何于屏障之后开始的装载或储存之前完成。

static void winShmBarrier(

  sqlite3_file *fd            /* 持有共享内存的数据库 */

){

  UNUSED_PARAMETER(fd);

  sqlite3MemoryBarrier();     /* 编译器-定义内存屏障 */

  winShmEnterMutex();       /* 同样互斥,用于冗余*/

  winShmLeaveMutex();

}

清除指定文件的映射区域(如果有的话)

#if SQLITE_MAX_MMAP_SIZE>0

static int winUnmapfile(winFile *pFile){

  assert( pFile!=0 );

  OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "

           "mmapSize=%lld, mmapSizeMax=%lld\n",

           osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,

           pFile->mmapSize, pFile->mmapSizeMax));

  if( pFile->pMapRegion ){

    if( !osUnmapViewOfFile(pFile->pMapRegion) ){

      pFile->lastErrno = osGetLastError();

      OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "

               "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,

               pFile->pMapRegion));

      return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,

                         "winUnmapfile1", pFile->zPath);

    }

    pFile->pMapRegion = 0;

    pFile->mmapSize = 0;

OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",

           osGetCurrentProcessId(), pFile));

  return SQLITE_OK;

}

内存映射或重新映射由文件描述符pfd打开的文件(如果文件已经映射,则现有的映射将被新的映射所取代)。或者,如果已经存在该文件的映射,并且仍然存在对它的未执行的xFetch()引用,则该函数是不操作。如果参数nByte是非负的,那么它就是要创建的映射的请求大小。否则,如果nByte小于零,那么请求的大小就是磁盘上文件的大小。创建的映射的实际大小要么是请求的大小,要么是使用SQLITE_FCNTL_MMAP_Size配置的值,以较小的值为准。SQLITE_OK如果不发生错误(即使映射没有由于未完成的引用而重新创建)或SQLite错误代码,则返回SQLITE_OK。

static int winMapfile(winFile *pFd, sqlite3_int64 nByte){

  sqlite3_int64 nMap = nByte;

  int rc;

  assert( nMap>=0 || pFd->nFetchOut==0 );

  OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",

           osGetCurrentProcessId(), pFd, nByte));

  if( pFd->nFetchOut>0 ) return SQLITE_OK;

  if( nMap<0 ){

    rc = winFileSize((sqlite3_file*)pFd, &nMap);

    if( rc ){

      OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",

               osGetCurrentProcessId(), pFd));

      return SQLITE_IOERR_FSTAT;

    }

  }

  if( nMap>pFd->mmapSizeMax ){

    nMap = pFd->mmapSizeMax;

  }

  nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);

  if( nMap==0 && pFd->mmapSize>0 ){

    winUnmapfile(pFd);

  }

  if( nMap!=pFd->mmapSize ){

    void *pNew = 0;

    DWORD protect = PAGE_READONLY;

    DWORD flags = FILE_MAP_READ;

    winUnmapfile(pFd);

#ifdef SQLITE_MMAP_READWRITE

    if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){

      protect = PAGE_READWRITE;

      flags |= FILE_MAP_WRITE;

    }

#endif

如果可能,返回一个指向文件fd映射的指针,从偏移量iOff开始。映射必须至少对nAmt字节有效。如果可以获得这样的指针,将其存储在*pp中并返回SQLITE_OK。或者,如果没有出现错误,则将*pp设置为0并返回SQLITE_OK。最后,如果发生错误,则返回SQLite错误代码。

static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){

#if SQLITE_MAX_MMAP_SIZE>0

  winFile *pFd = (winFile*)fd;   /* The underlying database file */

#endif

  *pp = 0;

  OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",

           osGetCurrentProcessId(), fd, iOff, nAmt, pp));

#if SQLITE_MAX_MMAP_SIZE>0

  if( pFd->mmapSizeMax>0 ){

    if( pFd->pMapRegion==0 ){

      int rc = winMapfile(pFd, -1);

      if( rc!=SQLITE_OK ){

        OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",

                 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));

        return rc;

      }

    }

    if( pFd->mmapSize >= iOff+nAmt ){

      assert( pFd->pMapRegion!=0 );

      *pp = &((u8 *)pFd->pMapRegion)[iOff];

      pFd->nFetchOut++;

    }

  }

#endif

  OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",

           osGetCurrentProcessId(), fd, pp, *pp));

  return SQLITE_OK;

}

如果第三个参数为非空参数,则此函数将释放先前调用winFetch()获得的引用。传递给此函数的第二个参数必须与传递给winFetch()调用的相应参数相同。或者,如果第三个参数为NULL,则调用该函数通知VFS层,根据POSIX,任何现有映射现在都可能无效,应该取消映射。

static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){

#if SQLITE_MAX_MMAP_SIZE>0

  winFile *pFd = (winFile*)fd;     /* 底层数据库文件 */

  assert( (p==0)==(pFd->nFetchOut==0) );

  /* 如果P不等于,它必须与iOff值匹配. */

  assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );

  OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",

           osGetCurrentProcessId(), pFd, iOff, p));

  if( p ){

    pFd->nFetchOut--;

  }else{

    winUnmapfile(pFd);

  }

  assert( pFd->nFetchOut>=0 );

#endif

  OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",

           osGetCurrentProcessId(), fd));

  return SQLITE_OK;

}

至此,所有sqlite3_file方法的实现结束。

Guess you like

Origin blog.csdn.net/qq_53825872/article/details/121520603