Sqlite源码解读(十)

2021SC@SDUSC

接着LockFile继续讲解关于锁的内容。

如果*pArg最初是负的,那么这就是一个查询。将*pArg设置为1或0,这取决于是否设置了pfile->ctrlFlags的位掩码。如果*pArg为0或1,则清除或设置pfile->ctrlFlags的掩码位。

static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){

  if( *pArg<0 ){

    *pArg = (pFile->ctrlFlags & mask)!=0;

  }else if( (*pArg)==0 ){

    pFile->ctrlFlags &= ~mask;

  }else{

    pFile->ctrlFlags |= mask;

  }

}

转发对用于临时文件的VFS助手方法的引用

static int winGetTempname(sqlite3_vfs *, char **);

static int winIsDir(const void *);

static BOOL winIsLongPathPrefix(const char *);

static BOOL winIsDriveLetterAndColon(const char *);

返回指定文件的基础块设备的扇区大小(以字节为单位)。SQLite代码假定此函数不会失败。它还假设如果在同一个文件系统目录中创建了两个文件,则这两个文件的扇区大小相同。

static int winSectorSize(sqlite3_file *id){

  (void)id;

  return SQLITE_DEFAULT_SECTOR_SIZE;

}

返回设备的特征向量

static int winDeviceCharacteristics(sqlite3_file *id){

  winFile *p = (winFile*)id;

  return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |

         ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);

}

帮助函数获得并放弃全局互斥。全局互斥被用来保护文件所使用的winLockInfo对象,所有这些都可以由多个线程共享。

static sqlite3_mutex *winBigLock = 0;

static void winShmEnterMutex(void){

  sqlite3_mutex_enter(winBigLock);

}

static void winShmLeaveMutex(void){

  sqlite3_mutex_leave(winBigLock);

}

#ifndef NDEBUG

static int winShmMutexHeld(void) {

  return sqlite3_mutex_held(winBigLock);

}

#endif

所有winShmNode对象的全局数组。在读取或写入此列表时,winShmMutexHeld()必须为true。

struct winShm {

  winShmNode *pShmNode;      /* 底层 winShmNode 对象 */

  winShm *pNext;             /* 使用相同的winShmNode的下一个winshm */

  u8 hasMutex;               /* 如果持有winShmNode互斥体,则为true */

  u16 sharedMask;            /* 共享锁的掩码 */

  u16 exclMask;              /* 独占锁的掩码 */

#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)

  u8 id;                     /* 使用winShmNode 的连接的ID*/

#endif

};

对以ofst开始的所有n个字节应用咨询锁。

#define WINSHM_UNLCK  1

#define WINSHM_RDLCK  2

#define WINSHM_WRLCK  3

static int winShmSystemLock(

  winShmNode *pFile,  /* 将锁应用到这个打开的共享内存段*/

  int lockType,        /* WINSHM_UNLCK、WINSHM_RDLCK 或 WINSHM_WRLCK类型*/

  int ofst,            /*偏移量到要锁定或解锁的第一个字节 */

  int nByte           /* 要锁定或解锁的字节数 */

){

  int rc = 0;          /* Lock/UnlockFileEx()的结果代码 */

  /*调用方序列化对winShmNode对象的访问*/

  assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );

  OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",

           pFile->hFile.h, lockType, ofst, nByte));

  /* 释放或获取系统级锁*/

  if( lockType==WINSHM_UNLCK ){

    rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);

  }else{

    /* Initialize the locking parameters */

    DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;

    if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;

    rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);

  }

  if( rc!= 0 ){

    rc = SQLITE_OK;

  }else{

    pFile->lastErrno =  osGetLastError();

    rc = SQLITE_BUSY;

  }

  OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",

           pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :

           "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));

  return rc;

}

清除winShmNode.nRef==0的所有条目的winShmNodeList列表。

这不是一个VFS共享内存方法;它是一个由VFS共享内存方法调用的实用函数。

static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){

  winShmNode **pp;

  winShmNode *p;

  assert( winShmMutexHeld() );

  OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",

           osGetCurrentProcessId(), deleteFlag));

  pp = &winShmNodeList;

  while( (p = *pp)!=0 ){

    if( p->nRef==0 ){

      int i;

      if( p->mutex ){ sqlite3_mutex_free(p->mutex); }

      for(i=0; i<p->nRegion; i++){

        BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);

        OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",

                 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));

        UNUSED_VARIABLE_VALUE(bRc);

        bRc = osCloseHandle(p->aRegion[i].hMap);

        OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",

                 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));

        UNUSED_VARIABLE_VALUE(bRc);

      }

      if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){

        SimulateIOErrorBenign(1);

        winClose((sqlite3_file *)&p->hFile);

        SimulateIOErrorBenign(0);

      }

      if( deleteFlag ){

        SimulateIOErrorBenign(1);

        sqlite3BeginBenignMalloc();

        winDelete(pVfs, p->zFilename, 0);

        sqlite3EndBenignMalloc();

        SimulateIOErrorBenign(0);

      }

      *pp = p->pNext;

      sqlite3_free(p->aRegion);

      sqlite3_free(p);

    }else{

      pp = &p->pNext;

    }

  }

}

尚未对SHM文件pShmNode执行DMS锁。现在就试着把它拿走。如果成功,返回SQLITE_OK,否则返回SQLite错误代码。如果DMS由于这是readonly_shm=1连接而无法锁定,并且没有其他进程已经持有锁,则返回SQLITE_READONLY_CANTINIT并设置pShmNode->isUnlock=1。

static int winLockSharedMemory(winShmNode *pShmNode){

  int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);

  if( rc==SQLITE_OK ){

    if( pShmNode->isReadonly ){

      pShmNode->isUnlocked = 1;

      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);

      return SQLITE_READONLY_CANTINIT;

    }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){

      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);

      return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),

                         "winLockSharedMemory", pShmNode->zFilename);

    }

  }

  if( rc==SQLITE_OK ){

    winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);

  }

  return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);

}

打开与数据库文件pDbFd关联的共享内存区域。当打开一个新的共享内存文件时,如果当前没有打开该文件的其他实例,则该文件必须被截断为零长度或清除其标头。

static int winOpenSharedMemory(winFile *pDbFd){

  struct winShm *p;                   /* 要打开的连接*/

  winShmNode *pShmNode = 0;         /*底层mmapped文件*/

  int rc = SQLITE_OK;                 /* 结果代码*/

  winShmNode *pNew;                  /*新分配的winShmNode */

  int nName;                        /*zName的大小(以字节为单位)*/

  assert( pDbFd->pShm==0 );         /*以前没有打开 */

/*为新sqlite3_SHM对象分配空间。此外,还为新的winShmNode和文件名分配空间。*/

p = sqlite3MallocZero( sizeof(*p) );

  if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;

  nName = sqlite3Strlen30(pDbFd->zPath);

  pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );

  if( pNew==0 ){

    sqlite3_free(p);

    return SQLITE_IOERR_NOMEM_BKPT;

  }

  pNew->zFilename = (char*)&pNew[1];

  sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);

  sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);

查看是否存在可以使用的现有winShmNode。如果当前不存在匹配的winShmNode,则创建一个新的。

winShmEnterMutex();

  for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){

    /*TBD需要在这里找到更好的匹配。也许使用file_id_ANY_DIR_INFO结构。*/  if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;

  }

  if( pShmNode ){

    sqlite3_free(pNew);

  }else{

    int inFlags = SQLITE_OPEN_WAL;

int outFlags = 0;

/*使新连接成为winShmNode的子节点*/

p->pShmNode = pShmNode;

#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)

  p->id = pShmNode->nextShmId++;

#endif

  pShmNode->nRef++;

  pDbFd->pShm = p;

  winShmLeaveMutex();

上一篇:C# sqlite执行sql


下一篇:Unity3D:动态加载资源(Resources.Load与AssetBundle.LoadAsset)