IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Sqlite源码解读(三) -> 正文阅读

[大数据]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本机堆。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-10-19 11:57:30  更:2021-10-19 11:58:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:24:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码