| |
|
开发:
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本机堆。
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |