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();