Sqlite源码解读(三)

2021SC@SDUSC

接着上次的winVfsAppData结构体继续往下看。

#ifdef SQLITE_WIN32_MALLOC

malloc()是Sqlite在缺省情况下调用C标准库例程来分配内存的。

如果这不是零,则本机Win 32分配器子系统将创建一个孤立的堆;否则,将使用默认的进程堆。此设置在为WinRT编译时没有任何影响。默认情况下,这是启用的,并且将创建一个独立的堆来存储所有分配的数据

此处出现了一个warning:当设置为非零并且调用了winMemShu倒计时函数时,使用隔离堆分配的所有数据都将立即被释放,而任何试图访问已释放的数据会立即导致访问冲突。

#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE

#  define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)

#endif

Win32特定堆的最大初始大小

#ifndef SQLITE_WIN32_CACHE_SIZE

#  if SQLITE_DEFAULT_CACHE_SIZE>=0

#    define SQLITE_WIN32_CACHE_SIZE     (SQLITE_DEFAULT_CACHE_SIZE)

#  else

#    define SQLITE_WIN32_CACHE_SIZE     (-(SQLITE_DEFAULT_CACHE_SIZE))

#  endif

#endif

计算Win32特定堆的初始大小时所用的缓存大小

#ifndef SQLITE_WIN32_MAX_CACHE_SIZE

#  define SQLITE_WIN32_MAX_CACHE_SIZE   (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \

                                          (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \

                                         (SQLITE_DEFAULT_PAGE_SIZE))

#endif

根据可能最大的初始堆大小和默认页大小,计算最大合法缓存大小(以页为单位),并预留所需的额外空间。

typedef struct winMemData winMemData;
struct winMemData {
    
    
#ifndef NDEBUG
  u32 magic1;   
#endif
  HANDLE hHeap; 
  BOOL bOwned;  
#ifndef NDEBUG
  u32 magic2;   
#endif
};
 
 
#ifndef NDEBUG
#define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 )
#define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 )
#define winMemAssertMagic()  winMemAssertMagic1(); winMemAssertMagic2();
#else
#define winMemAssertMagic()
#endif
 
 
WinmemData结构存储sqlite3_mem_method实现所需的信息。包含了上面提到的分配方法malloc(),free(),remalloc()
如果定义了NDEBUG,编译器会认为是非DEBUG的模式(虽然编译出来的程序还是很大,而且还可以进行调试),此时trace(),assert()就没有用了,相当于点击了’release’
 
 
static struct win_syscall {
    
    
  const char *zName;            /* Name of the system call */
  sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
  sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
    
    
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
  { "AreFileApisANSI",         (SYSCALL)AreFileApisANSI,         0 },
#else
  { "AreFileApisANSI",         (SYSCALL)0,                       0 },
#endif
(省略接下来长达数数数...百行的可重写系统调用)
许多系统调用是通过指针到函数访问的,这样它们在运行阶段可被重写,以便于在测试中进行错误注入。而上面的数组用来保存所有可重写系统调用的名称和指针。

#if defined(InterlockedCompareExchange)
  { "InterlockedCompareExchange", (SYSCALL)0,                    0 },
 
 
#define osInterlockedCompareExchange InterlockedCompareExchange
#else
  { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
 
 
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
        SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif 

注意!InterlockedCompareExchange实际上只是一个使用编译器内部的宏。所以不要试图将它变成一个可重新定义的接口。

接来下是很重要的一个方法:sqlite3_VFS的xSetSystemCall()方法,用于所有的WIN32 VFSes.

如果成功地更新系统调用指针,则返回SQLITE_OK;如果没有可配置的系统调用zName,则返回SQLITE_NotFound. 
static int winSetSystemCall(
  sqlite3_vfs *pNotUsed,        
  const char *zName,            
  sqlite3_syscall_ptr pNewFunc  
){
    
    
  unsigned int i;
  int rc = SQLITE_NOTFOUND;
 
 
  UNUSED_PARAMETER(pNotUsed);
  if( zName==0 ){
    
    
    /*如果没有指定zName,则将所有系统调用还原到其默认设置并返回NULL*/
    rc = SQLITE_OK;
    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
    
    
      if( aSyscall[i].pDefault ){
    
    
        aSyscall[i].pCurrent = aSyscall[i].pDefault;
      }
    }
  }
else{
    
    

   /*如果指定了zName,则只对指定的一个系统调用进行操作。*/

    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
    
    
      if( strcmp(zName, aSyscall[i].zName)==0 ){
    
    
        if( aSyscall[i].pDefault==0 ){
    
    
          aSyscall[i].pDefault = aSyscall[i].pCurrent;
        }
        rc = SQLITE_OK;
        if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
        aSyscall[i].pCurrent = pNewFunc;
        break;
      }
    }
  }
  return rc;
}

返回系统调用的值。如果zName不是一个可识别的系统调用名或者系统调用当前未定义,则返回NULL。

static sqlite3_syscall_ptr winGetSystemCall(
  sqlite3_vfs *pNotUsed,
  const char *zName
){
    
    
  unsigned int i;
 
 
  UNUSED_PARAMETER(pNotUsed);
  for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
    
    
    if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
  }
  return 0;
}

在zName之后返回第一个系统调用的名称。

如果zName==NULL,则返回第一个系统调用的名称。如果zName是最后一次系统调用,或者如果zName不是有效系统调用的名称,则返回NULL。

static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
    
    
  int i = -1;
  UNUSED_PARAMETER(p);
  if( zName ){
    
    
    for(i=0; i<ArraySize(aSyscall)-1; i++){
    
    
      if( strcmp(zName, aSyscall[i].zName)==0 ) break;
    }
  }
  for(i++; i<ArraySize(aSyscall); i++){
    
    
    if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
  }
  return 0;
}

下面这个函数将尝试压缩Win32本机堆。如果成功,则返回SQLITE_OK;如果失败,将返回SQLITE_NOMEM、SQLITE_ERROR或SQLITE_NotFound的一个。“pnLargest”参数(如果不是零)将用于返回堆中最大的提交空闲块的大小
#ifdef SQLITE_WIN32_MALLOC
int sqlite3_win32_compact_heap(LPUINT pnLargest){
    
    
  int rc = SQLITE_OK;
  UINT nLargest = 0;
  HANDLE hHeap;
 
 
  winMemAssertMagic();
  hHeap = winMemGetHeap();
  assert( hHeap!=0 );
  assert( hHeap!=INVALID_HANDLE_VALUE );
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
  assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
  if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){
    
    
    DWORD lastErrno = osGetLastError();
    if( lastErrno==NO_ERROR ){
    
    
      sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
                  (void*)hHeap);
      rc = SQLITE_NOMEM_BKPT;
    }else{
    
    
      sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
                  osGetLastError(), (void*)hHeap);
      rc = SQLITE_ERROR;
    }
  }
#else
  sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p",
              (void*)hHeap);
  rc = SQLITE_NOTFOUND;
#endif
  if( pnLargest ) *pnLargest = nLargest;
  return rc;
}
如果配置了Win 32本机堆,此函数将尝试销毁并重新创建它。如果Win 32本机堆未被隔离,并且/或sqlite3_Memory_use()函数不返回零,则将返回SQLITE_SARY,并且不会对Win 32本机堆进行任何更改。
此时,堆上不应该有未完成的内存分配。此外,由于主锁和memsys锁目前都由我们持有,因此没有其他函数能够访问堆。现在尝试销毁和重新创建我们的孤立的Win 32本机堆。

猜你喜欢

转载自blog.csdn.net/qq_53825872/article/details/120835516