Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
7248dc68
TDengine
项目概览
taosdata
/
TDengine
大约 2 年 前同步成功
通知
1192
Star
22018
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
7248dc68
编写于
2月 21, 2022
作者:
H
Hongze Cheng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
more
上级
f2096385
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
378 addition
and
382 deletion
+378
-382
source/libs/tdb/src/sqlite/pcache.c
source/libs/tdb/src/sqlite/pcache.c
+283
-316
source/libs/tdb/src/sqlite/pcache1.c
source/libs/tdb/src/sqlite/pcache1.c
+18
-9
source/libs/tdb/src/sqliteinc/pcache.h
source/libs/tdb/src/sqliteinc/pcache.h
+77
-57
未找到文件。
source/libs/tdb/src/sqlite/pcache.c
浏览文件 @
7248dc68
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
**
**
** The PCache.pSynced variable is used to optimize searching for a dirty
** The PCache.pSynced variable is used to optimize searching for a dirty
** page to eject from the cache mid-transaction. It is better to eject
** page to eject from the cache mid-transaction. It is better to eject
** a page that does not require a journal sync than one that does.
** a page that does not require a journal sync than one that does.
** Therefore, pSynced is maintained so that it *almost* always points
** Therefore, pSynced is maintained so that it *almost* always points
** to either the oldest page in the pDirty/pDirtyTail list that has a
** to either the oldest page in the pDirty/pDirtyTail list that has a
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
...
@@ -39,18 +39,18 @@
...
@@ -39,18 +39,18 @@
** pointers).
** pointers).
*/
*/
struct
PCache
{
struct
PCache
{
PgHdr
*
pDirty
,
*
pDirtyTail
;
/* List of dirty pages in LRU order */
PgHdr
*
pDirty
,
*
pDirtyTail
;
/* List of dirty pages in LRU order */
PgHdr
*
pSynced
;
/* Last synced page in dirty page list */
PgHdr
*
pSynced
;
/* Last synced page in dirty page list */
int
nRefSum
;
/* Sum of ref counts over all pages */
int
nRefSum
;
/* Sum of ref counts over all pages */
int
szCache
;
/* Configured cache size */
int
szCache
;
/* Configured cache size */
int
szSpill
;
/* Size before spilling occurs */
int
szSpill
;
/* Size before spilling occurs */
int
szPage
;
/* Size of every page in this cache */
int
szPage
;
/* Size of every page in this cache */
int
szExtra
;
/* Size of extra space for each page */
int
szExtra
;
/* Size of extra space for each page */
u8
bPurgeable
;
/* True if pages are on backing store */
u8
bPurgeable
;
/* True if pages are on backing store */
u8
eCreate
;
/* eCreate value for for xFetch() */
u8
eCreate
;
/* eCreate value for for xFetch() */
int
(
*
xStress
)(
void
*
,
PgHdr
*
);
/* Call to try make a page clean */
int
(
*
xStress
)(
void
*
,
PgHdr
*
);
/* Call to try make a page clean */
void
*
pStress
;
/* Argument to xStress */
void
*
pStress
;
/* Argument to xStress */
sqlite3_pcache
*
pCache
;
/* Pluggable cache module */
sqlite3_pcache
*
pCache
;
/* Pluggable cache module */
};
};
/********************************** Test and Debug Logic **********************/
/********************************** Test and Debug Logic **********************/
...
@@ -63,36 +63,39 @@ struct PCache {
...
@@ -63,36 +63,39 @@ struct PCache {
** is displayed for many operations, resulting in a lot of output.
** is displayed for many operations, resulting in a lot of output.
*/
*/
#if defined(SQLITE_DEBUG) && 0
#if defined(SQLITE_DEBUG) && 0
int
sqlite3PcacheTrace
=
2
;
/* 0: off 1: simple 2: cache dumps */
int
sqlite3PcacheTrace
=
2
;
/* 0: off 1: simple 2: cache dumps */
int
sqlite3PcacheMxDump
=
9999
;
/* Max cache entries for pcacheDump() */
int
sqlite3PcacheMxDump
=
9999
;
/* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
#define pcacheTrace(X) \
void
pcacheDump
(
PCache
*
pCache
){
if (sqlite3PcacheTrace) { \
int
N
;
sqlite3DebugPrintf X; \
int
i
,
j
;
}
sqlite3_pcache_page
*
pLower
;
void
pcacheDump
(
PCache
*
pCache
)
{
PgHdr
*
pPg
;
int
N
;
unsigned
char
*
a
;
int
i
,
j
;
sqlite3_pcache_page
*
pLower
;
if
(
sqlite3PcacheTrace
<
2
)
return
;
PgHdr
*
pPg
;
if
(
pCache
->
pCache
==
0
)
return
;
unsigned
char
*
a
;
N
=
sqlite3PcachePagecount
(
pCache
);
if
(
N
>
sqlite3PcacheMxDump
)
N
=
sqlite3PcacheMxDump
;
if
(
sqlite3PcacheTrace
<
2
)
return
;
for
(
i
=
1
;
i
<=
N
;
i
++
){
if
(
pCache
->
pCache
==
0
)
return
;
pLower
=
sqlite3GlobalConfig
.
pcache2
.
xFetch
(
pCache
->
pCache
,
i
,
0
);
N
=
sqlite3PcachePagecount
(
pCache
);
if
(
pLower
==
0
)
continue
;
if
(
N
>
sqlite3PcacheMxDump
)
N
=
sqlite3PcacheMxDump
;
pPg
=
(
PgHdr
*
)
pLower
->
pExtra
;
for
(
i
=
1
;
i
<=
N
;
i
++
)
{
printf
(
"%3d: nRef %2d flgs %02x data "
,
i
,
pPg
->
nRef
,
pPg
->
flags
);
pLower
=
pcache2
.
xFetch
(
pCache
->
pCache
,
i
,
0
);
a
=
(
unsigned
char
*
)
pLower
->
pBuf
;
if
(
pLower
==
0
)
continue
;
for
(
j
=
0
;
j
<
12
;
j
++
)
printf
(
"%02x"
,
a
[
j
]);
pPg
=
(
PgHdr
*
)
pLower
->
pExtra
;
printf
(
"
\n
"
);
printf
(
"%3d: nRef %2d flgs %02x data "
,
i
,
pPg
->
nRef
,
pPg
->
flags
);
if
(
pPg
->
pPage
==
0
){
a
=
(
unsigned
char
*
)
pLower
->
pBuf
;
sqlite3GlobalConfig
.
pcache2
.
xUnpin
(
pCache
->
pCache
,
pLower
,
0
);
for
(
j
=
0
;
j
<
12
;
j
++
)
printf
(
"%02x"
,
a
[
j
]);
}
printf
(
"
\n
"
);
if
(
pPg
->
pPage
==
0
)
{
pcache2
.
xUnpin
(
pCache
->
pCache
,
pLower
,
0
);
}
}
}
}
#else
}
# define pcacheTrace(X)
#else
# define pcacheDump(X)
#define pcacheTrace(X)
#define pcacheDump(X)
#endif
#endif
/*
/*
...
@@ -105,20 +108,20 @@ struct PCache {
...
@@ -105,20 +108,20 @@ struct PCache {
** assert( sqlite3PcachePageSanity(pPg) );
** assert( sqlite3PcachePageSanity(pPg) );
*/
*/
#ifdef SQLITE_DEBUG
#ifdef SQLITE_DEBUG
int
sqlite3PcachePageSanity
(
PgHdr
*
pPg
){
int
sqlite3PcachePageSanity
(
PgHdr
*
pPg
)
{
PCache
*
pCache
;
PCache
*
pCache
;
assert
(
pPg
!=
0
);
assert
(
pPg
!=
0
);
assert
(
pPg
->
pgno
>
0
||
pPg
->
pPager
==
0
);
/* Page number is 1 or more */
assert
(
pPg
->
pgno
>
0
||
pPg
->
pPager
==
0
);
/* Page number is 1 or more */
pCache
=
pPg
->
pCache
;
pCache
=
pPg
->
pCache
;
assert
(
pCache
!=
0
);
/* Every page has an associated PCache */
assert
(
pCache
!=
0
);
/* Every page has an associated PCache */
if
(
pPg
->
flags
&
PGHDR_CLEAN
)
{
if
(
pPg
->
flags
&
PGHDR_CLEAN
)
{
assert
(
(
pPg
->
flags
&
PGHDR_DIRTY
)
==
0
);
/* Cannot be both CLEAN and DIRTY */
assert
(
(
pPg
->
flags
&
PGHDR_DIRTY
)
==
0
);
/* Cannot be both CLEAN and DIRTY */
assert
(
pCache
->
pDirty
!=
pPg
);
/* CLEAN pages not on dirty list */
assert
(
pCache
->
pDirty
!=
pPg
);
/* CLEAN pages not on dirty list */
assert
(
pCache
->
pDirtyTail
!=
pPg
);
assert
(
pCache
->
pDirtyTail
!=
pPg
);
}
}
/* WRITEABLE pages must also be DIRTY */
/* WRITEABLE pages must also be DIRTY */
if
(
pPg
->
flags
&
PGHDR_WRITEABLE
)
{
if
(
pPg
->
flags
&
PGHDR_WRITEABLE
)
{
assert
(
pPg
->
flags
&
PGHDR_DIRTY
);
/* WRITEABLE implies DIRTY */
assert
(
pPg
->
flags
&
PGHDR_DIRTY
);
/* WRITEABLE implies DIRTY */
}
}
/* NEED_SYNC can be set independently of WRITEABLE. This can happen,
/* NEED_SYNC can be set independently of WRITEABLE. This can happen,
** for example, when using the sqlite3PagerDontWrite() optimization:
** for example, when using the sqlite3PagerDontWrite() optimization:
...
@@ -141,13 +144,12 @@ int sqlite3PcachePageSanity(PgHdr *pPg){
...
@@ -141,13 +144,12 @@ int sqlite3PcachePageSanity(PgHdr *pPg){
}
}
#endif
/* SQLITE_DEBUG */
#endif
/* SQLITE_DEBUG */
/********************************** Linked List Management ********************/
/********************************** Linked List Management ********************/
/* Allowed values for second argument to pcacheManageDirtyList() */
/* Allowed values for second argument to pcacheManageDirtyList() */
#define PCACHE_DIRTYLIST_REMOVE
1
/* Remove pPage from dirty list */
#define PCACHE_DIRTYLIST_REMOVE
1
/* Remove pPage from dirty list */
#define PCACHE_DIRTYLIST_ADD
2
/* Add pPage to the dirty list */
#define PCACHE_DIRTYLIST_ADD
2
/* Add pPage to the dirty list */
#define PCACHE_DIRTYLIST_FRONT
3
/* Move pPage to the front of the list */
#define PCACHE_DIRTYLIST_FRONT
3
/* Move pPage to the front of the list */
/*
/*
** Manage pPage's participation on the dirty list. Bits of the addRemove
** Manage pPage's participation on the dirty list. Bits of the addRemove
...
@@ -155,66 +157,63 @@ int sqlite3PcachePageSanity(PgHdr *pPg){
...
@@ -155,66 +157,63 @@ int sqlite3PcachePageSanity(PgHdr *pPg){
** remove pPage from the dirty list. The 0x02 means add pPage back to
** remove pPage from the dirty list. The 0x02 means add pPage back to
** the dirty list. Doing both moves pPage to the front of the dirty list.
** the dirty list. Doing both moves pPage to the front of the dirty list.
*/
*/
static
void
pcacheManageDirtyList
(
PgHdr
*
pPage
,
u8
addRemove
){
static
void
pcacheManageDirtyList
(
PgHdr
*
pPage
,
u8
addRemove
)
{
PCache
*
p
=
pPage
->
pCache
;
PCache
*
p
=
pPage
->
pCache
;
pcacheTrace
((
"%p.DIRTYLIST.%s %d
\n
"
,
p
,
pcacheTrace
((
"%p.DIRTYLIST.%s %d
\n
"
,
p
,
addRemove
==
1
?
"REMOVE"
:
addRemove
==
2
?
"ADD"
:
"FRONT"
,
pPage
->
pgno
));
addRemove
==
1
?
"REMOVE"
:
addRemove
==
2
?
"ADD"
:
"FRONT"
,
if
(
addRemove
&
PCACHE_DIRTYLIST_REMOVE
)
{
pPage
->
pgno
));
assert
(
pPage
->
pDirtyNext
||
pPage
==
p
->
pDirtyTail
);
if
(
addRemove
&
PCACHE_DIRTYLIST_REMOVE
){
assert
(
pPage
->
pDirtyPrev
||
pPage
==
p
->
pDirty
);
assert
(
pPage
->
pDirtyNext
||
pPage
==
p
->
pDirtyTail
);
assert
(
pPage
->
pDirtyPrev
||
pPage
==
p
->
pDirty
);
/* Update the PCache1.pSynced variable if necessary. */
/* Update the PCache1.pSynced variable if necessary. */
if
(
p
->
pSynced
==
pPage
)
{
if
(
p
->
pSynced
==
pPage
)
{
p
->
pSynced
=
pPage
->
pDirtyPrev
;
p
->
pSynced
=
pPage
->
pDirtyPrev
;
}
}
if
(
pPage
->
pDirtyNext
)
{
if
(
pPage
->
pDirtyNext
)
{
pPage
->
pDirtyNext
->
pDirtyPrev
=
pPage
->
pDirtyPrev
;
pPage
->
pDirtyNext
->
pDirtyPrev
=
pPage
->
pDirtyPrev
;
}
else
{
}
else
{
assert
(
pPage
==
p
->
pDirtyTail
);
assert
(
pPage
==
p
->
pDirtyTail
);
p
->
pDirtyTail
=
pPage
->
pDirtyPrev
;
p
->
pDirtyTail
=
pPage
->
pDirtyPrev
;
}
}
if
(
pPage
->
pDirtyPrev
)
{
if
(
pPage
->
pDirtyPrev
)
{
pPage
->
pDirtyPrev
->
pDirtyNext
=
pPage
->
pDirtyNext
;
pPage
->
pDirtyPrev
->
pDirtyNext
=
pPage
->
pDirtyNext
;
}
else
{
}
else
{
/* If there are now no dirty pages in the cache, set eCreate to 2.
/* If there are now no dirty pages in the cache, set eCreate to 2.
** This is an optimization that allows sqlite3PcacheFetch() to skip
** This is an optimization that allows sqlite3PcacheFetch() to skip
** searching for a dirty page to eject from the cache when it might
** searching for a dirty page to eject from the cache when it might
** otherwise have to. */
** otherwise have to. */
assert
(
pPage
==
p
->
pDirty
);
assert
(
pPage
==
p
->
pDirty
);
p
->
pDirty
=
pPage
->
pDirtyNext
;
p
->
pDirty
=
pPage
->
pDirtyNext
;
assert
(
p
->
bPurgeable
||
p
->
eCreate
==
2
);
assert
(
p
->
bPurgeable
||
p
->
eCreate
==
2
);
if
(
p
->
pDirty
==
0
){
/*OPTIMIZATION-IF-TRUE*/
if
(
p
->
pDirty
==
0
)
{
/*OPTIMIZATION-IF-TRUE*/
assert
(
p
->
bPurgeable
==
0
||
p
->
eCreate
==
1
);
assert
(
p
->
bPurgeable
==
0
||
p
->
eCreate
==
1
);
p
->
eCreate
=
2
;
p
->
eCreate
=
2
;
}
}
}
}
}
}
if
(
addRemove
&
PCACHE_DIRTYLIST_ADD
)
{
if
(
addRemove
&
PCACHE_DIRTYLIST_ADD
)
{
pPage
->
pDirtyPrev
=
0
;
pPage
->
pDirtyPrev
=
0
;
pPage
->
pDirtyNext
=
p
->
pDirty
;
pPage
->
pDirtyNext
=
p
->
pDirty
;
if
(
pPage
->
pDirtyNext
)
{
if
(
pPage
->
pDirtyNext
)
{
assert
(
pPage
->
pDirtyNext
->
pDirtyPrev
==
0
);
assert
(
pPage
->
pDirtyNext
->
pDirtyPrev
==
0
);
pPage
->
pDirtyNext
->
pDirtyPrev
=
pPage
;
pPage
->
pDirtyNext
->
pDirtyPrev
=
pPage
;
}
else
{
}
else
{
p
->
pDirtyTail
=
pPage
;
p
->
pDirtyTail
=
pPage
;
if
(
p
->
bPurgeable
)
{
if
(
p
->
bPurgeable
)
{
assert
(
p
->
eCreate
==
2
);
assert
(
p
->
eCreate
==
2
);
p
->
eCreate
=
1
;
p
->
eCreate
=
1
;
}
}
}
}
p
->
pDirty
=
pPage
;
p
->
pDirty
=
pPage
;
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
** pSynced to point to it. Checking the NEED_SYNC flag is an
** pSynced to point to it. Checking the NEED_SYNC flag is an
** optimization, as if pSynced points to a page with the NEED_SYNC
** optimization, as if pSynced points to a page with the NEED_SYNC
** flag set sqlite3PcacheFetchStress() searches through all newer
** flag set sqlite3PcacheFetchStress() searches through all newer
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
if
(
!
p
->
pSynced
if
(
!
p
->
pSynced
&&
0
==
(
pPage
->
flags
&
PGHDR_NEED_SYNC
)
/*OPTIMIZATION-IF-FALSE*/
&&
0
==
(
pPage
->
flags
&
PGHDR_NEED_SYNC
)
/*OPTIMIZATION-IF-FALSE*/
)
{
){
p
->
pSynced
=
pPage
;
p
->
pSynced
=
pPage
;
}
}
}
}
...
@@ -225,10 +224,10 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
...
@@ -225,10 +224,10 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
** Wrapper around the pluggable caches xUnpin method. If the cache is
** Wrapper around the pluggable caches xUnpin method. If the cache is
** being used for an in-memory database, this function is a no-op.
** being used for an in-memory database, this function is a no-op.
*/
*/
static
void
pcacheUnpin
(
PgHdr
*
p
){
static
void
pcacheUnpin
(
PgHdr
*
p
)
{
if
(
p
->
pCache
->
bPurgeable
)
{
if
(
p
->
pCache
->
bPurgeable
)
{
pcacheTrace
((
"%p.UNPIN %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
pcacheTrace
((
"%p.UNPIN %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
sqlite3GlobalConfig
.
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
0
);
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
0
);
pcacheDump
(
p
->
pCache
);
pcacheDump
(
p
->
pCache
);
}
}
}
}
...
@@ -237,54 +236,45 @@ static void pcacheUnpin(PgHdr *p){
...
@@ -237,54 +236,45 @@ static void pcacheUnpin(PgHdr *p){
** Compute the number of pages of cache requested. p->szCache is the
** Compute the number of pages of cache requested. p->szCache is the
** cache size requested by the "PRAGMA cache_size" statement.
** cache size requested by the "PRAGMA cache_size" statement.
*/
*/
static
int
numberOfCachePages
(
PCache
*
p
){
static
int
numberOfCachePages
(
PCache
*
p
)
{
if
(
p
->
szCache
>=
0
)
{
if
(
p
->
szCache
>=
0
)
{
/* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
/* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
** suggested cache size is set to N. */
** suggested cache size is set to N. */
return
p
->
szCache
;
return
p
->
szCache
;
}
else
{
}
else
{
i64
n
;
i64
n
;
/* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
/* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would
** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current
** use approximately abs(N*1024) bytes of memory based on the current
** page size. */
** page size. */
n
=
((
-
1024
*
(
i64
)
p
->
szCache
)
/
(
p
->
szPage
+
p
->
szExtra
));
n
=
((
-
1024
*
(
i64
)
p
->
szCache
)
/
(
p
->
szPage
+
p
->
szExtra
));
if
(
n
>
1000000000
)
n
=
1000000000
;
if
(
n
>
1000000000
)
n
=
1000000000
;
return
(
int
)
n
;
return
(
int
)
n
;
}
}
}
}
/*************************************************** General Interfaces ******
/*************************************************** General Interfaces ******
**
**
** Initialize and shutdown the page cache subsystem. Neither of these
** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.
** functions are threadsafe.
*/
*/
int
sqlite3PcacheInitialize
(
void
){
int
sqlite3PcacheInitialize
(
void
)
{
return
pcache2
.
xInit
(
pcache2
.
pArg
);
}
if
(
sqlite3GlobalConfig
.
pcache2
.
xInit
==
0
){
void
sqlite3PcacheShutdown
(
void
)
{
/* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
if
(
pcache2
.
xShutdown
)
{
** built-in default page cache is used instead of the application defined
** page cache. */
sqlite3PCacheSetDefault
();
assert
(
sqlite3GlobalConfig
.
pcache2
.
xInit
!=
0
);
}
return
sqlite3GlobalConfig
.
pcache2
.
xInit
(
sqlite3GlobalConfig
.
pcache2
.
pArg
);
}
void
sqlite3PcacheShutdown
(
void
){
if
(
sqlite3GlobalConfig
.
pcache2
.
xShutdown
){
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
sqlite3GlobalConfig
.
pcache2
.
xShutdown
(
sqlite3GlobalConfig
.
pcache2
.
pArg
);
pcache2
.
xShutdown
(
pcache2
.
pArg
);
}
}
}
}
/*
/*
** Return the size in bytes of a PCache object.
** Return the size in bytes of a PCache object.
*/
*/
int
sqlite3PcacheSize
(
void
){
return
sizeof
(
PCache
);
}
int
sqlite3PcacheSize
(
void
)
{
return
sizeof
(
PCache
);
}
/*
/*
** Create a new PCache object. Storage space to hold the object
** Create a new PCache object. Storage space to hold the object
** has already been allocated and is passed in as the p pointer.
** has already been allocated and is passed in as the p pointer.
** The caller discovers how much space needs to be allocated by
** The caller discovers how much space needs to be allocated by
** calling sqlite3PcacheSize().
** calling sqlite3PcacheSize().
**
**
** szExtra is some extra space allocated for each page. The first
** szExtra is some extra space allocated for each page. The first
...
@@ -293,25 +283,24 @@ int sqlite3PcacheSize(void){ return sizeof(PCache); }
...
@@ -293,25 +283,24 @@ int sqlite3PcacheSize(void){ return sizeof(PCache); }
** to this module, the extra space really ends up being the MemPage
** to this module, the extra space really ends up being the MemPage
** structure in the pager.
** structure in the pager.
*/
*/
int
sqlite3PcacheOpen
(
int
sqlite3PcacheOpen
(
int
szPage
,
/* Size of every page */
int
szPage
,
/* Size of every page */
int
szExtra
,
/* Extra space associated with each page */
int
szExtra
,
/* Extra space associated with each page */
int
bPurgeable
,
/* True if pages are on backing store */
int
bPurgeable
,
/* True if pages are on backing store */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
void
*
pStress
,
/* Argument to xStress */
void
*
pStress
,
/* Argument to xStress */
PCache
*
p
/* Preallocated space for the PCache */
PCache
*
p
/* Preallocated space for the PCache */
)
{
){
memset
(
p
,
0
,
sizeof
(
PCache
));
memset
(
p
,
0
,
sizeof
(
PCache
));
p
->
szPage
=
1
;
p
->
szPage
=
1
;
p
->
szExtra
=
szExtra
;
p
->
szExtra
=
szExtra
;
assert
(
szExtra
>=
8
);
/* First 8 bytes will be zeroed */
assert
(
szExtra
>=
8
);
/* First 8 bytes will be zeroed */
p
->
bPurgeable
=
bPurgeable
;
p
->
bPurgeable
=
bPurgeable
;
p
->
eCreate
=
2
;
p
->
eCreate
=
2
;
p
->
xStress
=
xStress
;
p
->
xStress
=
xStress
;
p
->
pStress
=
pStress
;
p
->
pStress
=
pStress
;
p
->
szCache
=
100
;
p
->
szCache
=
100
;
p
->
szSpill
=
1
;
p
->
szSpill
=
1
;
pcacheTrace
((
"%p.OPEN szPage %d bPurgeable %d
\n
"
,
p
,
szPage
,
bPurgeable
));
pcacheTrace
((
"%p.OPEN szPage %d bPurgeable %d
\n
"
,
p
,
szPage
,
bPurgeable
));
return
sqlite3PcacheSetPageSize
(
p
,
szPage
);
return
sqlite3PcacheSetPageSize
(
p
,
szPage
);
}
}
...
@@ -319,22 +308,19 @@ int sqlite3PcacheOpen(
...
@@ -319,22 +308,19 @@ int sqlite3PcacheOpen(
** Change the page size for PCache object. The caller must ensure that there
** Change the page size for PCache object. The caller must ensure that there
** are no outstanding page references when this function is called.
** are no outstanding page references when this function is called.
*/
*/
int
sqlite3PcacheSetPageSize
(
PCache
*
pCache
,
int
szPage
){
int
sqlite3PcacheSetPageSize
(
PCache
*
pCache
,
int
szPage
)
{
assert
(
pCache
->
nRefSum
==
0
&&
pCache
->
pDirty
==
0
);
assert
(
pCache
->
nRefSum
==
0
&&
pCache
->
pDirty
==
0
);
if
(
pCache
->
szPage
)
{
if
(
pCache
->
szPage
)
{
sqlite3_pcache
*
pNew
;
sqlite3_pcache
*
pNew
;
pNew
=
sqlite3GlobalConfig
.
pcache2
.
xCreate
(
pNew
=
pcache2
.
xCreate
(
szPage
,
pCache
->
szExtra
+
ROUND8
(
sizeof
(
PgHdr
)),
pCache
->
bPurgeable
);
szPage
,
pCache
->
szExtra
+
ROUND8
(
sizeof
(
PgHdr
)),
if
(
pNew
==
0
)
return
SQLITE_NOMEM_BKPT
;
pCache
->
bPurgeable
pcache2
.
xCachesize
(
pNew
,
numberOfCachePages
(
pCache
));
);
if
(
pCache
->
pCache
)
{
if
(
pNew
==
0
)
return
SQLITE_NOMEM_BKPT
;
pcache2
.
xDestroy
(
pCache
->
pCache
);
sqlite3GlobalConfig
.
pcache2
.
xCachesize
(
pNew
,
numberOfCachePages
(
pCache
));
if
(
pCache
->
pCache
){
sqlite3GlobalConfig
.
pcache2
.
xDestroy
(
pCache
->
pCache
);
}
}
pCache
->
pCache
=
pNew
;
pCache
->
pCache
=
pNew
;
pCache
->
szPage
=
szPage
;
pCache
->
szPage
=
szPage
;
pcacheTrace
((
"%p.PAGESIZE %d
\n
"
,
pCache
,
szPage
));
pcacheTrace
((
"%p.PAGESIZE %d
\n
"
,
pCache
,
szPage
));
}
}
return
SQLITE_OK
;
return
SQLITE_OK
;
}
}
...
@@ -363,18 +349,17 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
...
@@ -363,18 +349,17 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
** the stack on entry and pop them back off on exit, which saves a
** the stack on entry and pop them back off on exit, which saves a
** lot of pushing and popping.
** lot of pushing and popping.
*/
*/
sqlite3_pcache_page
*
sqlite3PcacheFetch
(
sqlite3_pcache_page
*
sqlite3PcacheFetch
(
PCache
*
pCache
,
/* Obtain the page from this cache */
PCache
*
pCache
,
/* Obtain the page from this cache */
Pgno
pgno
,
/* Page number to obtain */
Pgno
pgno
,
/* Page number to obtain */
int
createFlag
/* If true, create page if it does not exist already */
int
createFlag
/* If true, create page if it does not exist already */
)
{
){
int
eCreate
;
int
eCreate
;
sqlite3_pcache_page
*
pRes
;
sqlite3_pcache_page
*
pRes
;
assert
(
pCache
!=
0
);
assert
(
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
assert
(
createFlag
==
3
||
createFlag
==
0
);
assert
(
createFlag
==
3
||
createFlag
==
0
);
assert
(
pCache
->
eCreate
==
((
pCache
->
bPurgeable
&&
pCache
->
pDirty
)
?
1
:
2
)
);
assert
(
pCache
->
eCreate
==
((
pCache
->
bPurgeable
&&
pCache
->
pDirty
)
?
1
:
2
)
);
/* eCreate defines what to do if the page does not exist.
/* eCreate defines what to do if the page does not exist.
** 0 Do not allocate a new page. (createFlag==0)
** 0 Do not allocate a new page. (createFlag==0)
...
@@ -384,19 +369,18 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
...
@@ -384,19 +369,18 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
** (createFlag==1 AND !(bPurgeable AND pDirty)
** (createFlag==1 AND !(bPurgeable AND pDirty)
*/
*/
eCreate
=
createFlag
&
pCache
->
eCreate
;
eCreate
=
createFlag
&
pCache
->
eCreate
;
assert
(
eCreate
==
0
||
eCreate
==
1
||
eCreate
==
2
);
assert
(
eCreate
==
0
||
eCreate
==
1
||
eCreate
==
2
);
assert
(
createFlag
==
0
||
pCache
->
eCreate
==
eCreate
);
assert
(
createFlag
==
0
||
pCache
->
eCreate
==
eCreate
);
assert
(
createFlag
==
0
||
eCreate
==
1
+
(
!
pCache
->
bPurgeable
||!
pCache
->
pDirty
)
);
assert
(
createFlag
==
0
||
eCreate
==
1
+
(
!
pCache
->
bPurgeable
||
!
pCache
->
pDirty
));
pRes
=
sqlite3GlobalConfig
.
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
eCreate
);
pRes
=
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
eCreate
);
pcacheTrace
((
"%p.FETCH %d%s (result: %p)
\n
"
,
pCache
,
pgno
,
pcacheTrace
((
"%p.FETCH %d%s (result: %p)
\n
"
,
pCache
,
pgno
,
createFlag
?
" create"
:
""
,
pRes
));
createFlag
?
" create"
:
""
,
pRes
));
return
pRes
;
return
pRes
;
}
}
/*
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** page because no clean pages are available for reuse and the cache
** page because no clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
** size limit has been reached, then this routine can be invoked to
** try harder to allocate a page. This routine might invoke the stress
** try harder to allocate a page. This routine might invoke the stress
** callback to spill dirty pages to the journal. It will then try to
** callback to spill dirty pages to the journal. It will then try to
** allocate the new page and will only fail to allocate a new page on
** allocate the new page and will only fail to allocate a new page on
...
@@ -404,51 +388,46 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
...
@@ -404,51 +388,46 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
**
**
** This routine should be invoked only after sqlite3PcacheFetch() fails.
** This routine should be invoked only after sqlite3PcacheFetch() fails.
*/
*/
int
sqlite3PcacheFetchStress
(
int
sqlite3PcacheFetchStress
(
PCache
*
pCache
,
/* Obtain the page from this cache */
PCache
*
pCache
,
/* Obtain the page from this cache */
Pgno
pgno
,
/* Page number to obtain */
Pgno
pgno
,
/* Page number to obtain */
sqlite3_pcache_page
**
ppPage
/* Write result here */
sqlite3_pcache_page
**
ppPage
/* Write result here */
)
{
){
PgHdr
*
pPg
;
PgHdr
*
pPg
;
if
(
pCache
->
eCreate
==
2
)
return
0
;
if
(
pCache
->
eCreate
==
2
)
return
0
;
if
(
sqlite3PcachePagecount
(
pCache
)
>
pCache
->
szSpill
)
{
if
(
sqlite3PcachePagecount
(
pCache
)
>
pCache
->
szSpill
)
{
/* Find a dirty page to write-out and recycle. First try to find a
/* Find a dirty page to write-out and recycle. First try to find a
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
** cleared), but if that is not possible settle for any other
** cleared), but if that is not possible settle for any other
** unreferenced dirty page.
** unreferenced dirty page.
**
**
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
** flag is currently referenced, then the following may leave pSynced
** flag is currently referenced, then the following may leave pSynced
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
** cleared). This is Ok, as pSynced is just an optimization. */
** cleared). This is Ok, as pSynced is just an optimization. */
for
(
pPg
=
pCache
->
pSynced
;
for
(
pPg
=
pCache
->
pSynced
;
pPg
&&
(
pPg
->
nRef
||
(
pPg
->
flags
&
PGHDR_NEED_SYNC
));
pPg
=
pPg
->
pDirtyPrev
)
pPg
&&
(
pPg
->
nRef
||
(
pPg
->
flags
&
PGHDR_NEED_SYNC
));
;
pPg
=
pPg
->
pDirtyPrev
);
pCache
->
pSynced
=
pPg
;
pCache
->
pSynced
=
pPg
;
if
(
!
pPg
){
if
(
!
pPg
)
{
for
(
pPg
=
pCache
->
pDirtyTail
;
pPg
&&
pPg
->
nRef
;
pPg
=
pPg
->
pDirtyPrev
);
for
(
pPg
=
pCache
->
pDirtyTail
;
pPg
&&
pPg
->
nRef
;
pPg
=
pPg
->
pDirtyPrev
)
;
}
}
if
(
pPg
)
{
if
(
pPg
)
{
int
rc
;
int
rc
;
#ifdef SQLITE_LOG_CACHE_SPILL
#ifdef SQLITE_LOG_CACHE_SPILL
sqlite3_log
(
SQLITE_FULL
,
sqlite3_log
(
SQLITE_FULL
,
"spill page %d making room for %d - cache used: %d/%d"
,
pPg
->
pgno
,
pgno
,
"spill page %d making room for %d - cache used: %d/%d"
,
pcache2
.
xPagecount
(
pCache
->
pCache
),
numberOfCachePages
(
pCache
));
pPg
->
pgno
,
pgno
,
sqlite3GlobalConfig
.
pcache2
.
xPagecount
(
pCache
->
pCache
),
numberOfCachePages
(
pCache
));
#endif
#endif
pcacheTrace
((
"%p.SPILL %d
\n
"
,
pCache
,
pPg
->
pgno
));
pcacheTrace
((
"%p.SPILL %d
\n
"
,
pCache
,
pPg
->
pgno
));
rc
=
pCache
->
xStress
(
pCache
->
pStress
,
pPg
);
rc
=
pCache
->
xStress
(
pCache
->
pStress
,
pPg
);
pcacheDump
(
pCache
);
pcacheDump
(
pCache
);
if
(
rc
!=
SQLITE_OK
&&
rc
!=
SQLITE_BUSY
)
{
if
(
rc
!=
SQLITE_OK
&&
rc
!=
SQLITE_BUSY
)
{
return
rc
;
return
rc
;
}
}
}
}
}
}
*
ppPage
=
sqlite3GlobalConfig
.
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
2
);
*
ppPage
=
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
2
);
return
*
ppPage
==
0
?
SQLITE_NOMEM_BKPT
:
SQLITE_OK
;
return
*
ppPage
==
0
?
SQLITE_NOMEM_BKPT
:
SQLITE_OK
;
}
}
/*
/*
...
@@ -461,15 +440,15 @@ int sqlite3PcacheFetchStress(
...
@@ -461,15 +440,15 @@ int sqlite3PcacheFetchStress(
** case.
** case.
*/
*/
static
SQLITE_NOINLINE
PgHdr
*
pcacheFetchFinishWithInit
(
static
SQLITE_NOINLINE
PgHdr
*
pcacheFetchFinishWithInit
(
PCache
*
pCache
,
/* Obtain the page from this cache */
PCache
*
pCache
,
/* Obtain the page from this cache */
Pgno
pgno
,
/* Page number obtained */
Pgno
pgno
,
/* Page number obtained */
sqlite3_pcache_page
*
pPage
/* Page obtained by prior PcacheFetch() call */
sqlite3_pcache_page
*
pPage
/* Page obtained by prior PcacheFetch() call */
){
)
{
PgHdr
*
pPgHdr
;
PgHdr
*
pPgHdr
;
assert
(
pPage
!=
0
);
assert
(
pPage
!=
0
);
pPgHdr
=
(
PgHdr
*
)
pPage
->
pExtra
;
pPgHdr
=
(
PgHdr
*
)
pPage
->
pExtra
;
assert
(
pPgHdr
->
pPage
==
0
);
assert
(
pPgHdr
->
pPage
==
0
);
memset
(
&
pPgHdr
->
pDirty
,
0
,
sizeof
(
PgHdr
)
-
offsetof
(
PgHdr
,
pDirty
));
memset
(
&
pPgHdr
->
pDirty
,
0
,
sizeof
(
PgHdr
)
-
offsetof
(
PgHdr
,
pDirty
));
pPgHdr
->
pPage
=
pPage
;
pPgHdr
->
pPage
=
pPage
;
pPgHdr
->
pData
=
pPage
->
pBuf
;
pPgHdr
->
pData
=
pPage
->
pBuf
;
pPgHdr
->
pExtra
=
(
void
*
)
&
pPgHdr
[
1
];
pPgHdr
->
pExtra
=
(
void
*
)
&
pPgHdr
[
1
];
...
@@ -477,7 +456,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
...
@@ -477,7 +456,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
pPgHdr
->
pCache
=
pCache
;
pPgHdr
->
pCache
=
pCache
;
pPgHdr
->
pgno
=
pgno
;
pPgHdr
->
pgno
=
pgno
;
pPgHdr
->
flags
=
PGHDR_CLEAN
;
pPgHdr
->
flags
=
PGHDR_CLEAN
;
return
sqlite3PcacheFetchFinish
(
pCache
,
pgno
,
pPage
);
return
sqlite3PcacheFetchFinish
(
pCache
,
pgno
,
pPage
);
}
}
/*
/*
...
@@ -486,22 +465,21 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
...
@@ -486,22 +465,21 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
** must be called after sqlite3PcacheFetch() in order to get a usable
** must be called after sqlite3PcacheFetch() in order to get a usable
** result.
** result.
*/
*/
PgHdr
*
sqlite3PcacheFetchFinish
(
PgHdr
*
sqlite3PcacheFetchFinish
(
PCache
*
pCache
,
/* Obtain the page from this cache */
PCache
*
pCache
,
/* Obtain the page from this cache */
Pgno
pgno
,
/* Page number obtained */
Pgno
pgno
,
/* Page number obtained */
sqlite3_pcache_page
*
pPage
/* Page obtained by prior PcacheFetch() call */
sqlite3_pcache_page
*
pPage
/* Page obtained by prior PcacheFetch() call */
)
{
){
PgHdr
*
pPgHdr
;
PgHdr
*
pPgHdr
;
assert
(
pPage
!=
0
);
assert
(
pPage
!=
0
);
pPgHdr
=
(
PgHdr
*
)
pPage
->
pExtra
;
pPgHdr
=
(
PgHdr
*
)
pPage
->
pExtra
;
if
(
!
pPgHdr
->
pPage
)
{
if
(
!
pPgHdr
->
pPage
)
{
return
pcacheFetchFinishWithInit
(
pCache
,
pgno
,
pPage
);
return
pcacheFetchFinishWithInit
(
pCache
,
pgno
,
pPage
);
}
}
pCache
->
nRefSum
++
;
pCache
->
nRefSum
++
;
pPgHdr
->
nRef
++
;
pPgHdr
->
nRef
++
;
assert
(
sqlite3PcachePageSanity
(
pPgHdr
)
);
assert
(
sqlite3PcachePageSanity
(
pPgHdr
)
);
return
pPgHdr
;
return
pPgHdr
;
}
}
...
@@ -509,13 +487,13 @@ PgHdr *sqlite3PcacheFetchFinish(
...
@@ -509,13 +487,13 @@ PgHdr *sqlite3PcacheFetchFinish(
** Decrement the reference count on a page. If the page is clean and the
** Decrement the reference count on a page. If the page is clean and the
** reference count drops to 0, then it is made eligible for recycling.
** reference count drops to 0, then it is made eligible for recycling.
*/
*/
void
SQLITE_NOINLINE
sqlite3PcacheRelease
(
PgHdr
*
p
){
void
SQLITE_NOINLINE
sqlite3PcacheRelease
(
PgHdr
*
p
)
{
assert
(
p
->
nRef
>
0
);
assert
(
p
->
nRef
>
0
);
p
->
pCache
->
nRefSum
--
;
p
->
pCache
->
nRefSum
--
;
if
(
(
--
p
->
nRef
)
==
0
)
{
if
((
--
p
->
nRef
)
==
0
)
{
if
(
p
->
flags
&
PGHDR_CLEAN
)
{
if
(
p
->
flags
&
PGHDR_CLEAN
)
{
pcacheUnpin
(
p
);
pcacheUnpin
(
p
);
}
else
{
}
else
{
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_FRONT
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_FRONT
);
}
}
}
}
...
@@ -524,9 +502,9 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
...
@@ -524,9 +502,9 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
/*
/*
** Increase the reference count of a supplied page by 1.
** Increase the reference count of a supplied page by 1.
*/
*/
void
sqlite3PcacheRef
(
PgHdr
*
p
){
void
sqlite3PcacheRef
(
PgHdr
*
p
)
{
assert
(
p
->
nRef
>
0
);
assert
(
p
->
nRef
>
0
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
p
->
nRef
++
;
p
->
nRef
++
;
p
->
pCache
->
nRefSum
++
;
p
->
pCache
->
nRefSum
++
;
}
}
...
@@ -536,32 +514,32 @@ void sqlite3PcacheRef(PgHdr *p){
...
@@ -536,32 +514,32 @@ void sqlite3PcacheRef(PgHdr *p){
** page. This function deletes that reference, so after it returns the
** page. This function deletes that reference, so after it returns the
** page pointed to by p is invalid.
** page pointed to by p is invalid.
*/
*/
void
sqlite3PcacheDrop
(
PgHdr
*
p
){
void
sqlite3PcacheDrop
(
PgHdr
*
p
)
{
assert
(
p
->
nRef
==
1
);
assert
(
p
->
nRef
==
1
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
if
(
p
->
flags
&
PGHDR_DIRTY
)
{
if
(
p
->
flags
&
PGHDR_DIRTY
)
{
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_REMOVE
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_REMOVE
);
}
}
p
->
pCache
->
nRefSum
--
;
p
->
pCache
->
nRefSum
--
;
sqlite3GlobalConfig
.
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
1
);
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
1
);
}
}
/*
/*
** Make sure the page is marked as dirty. If it isn't dirty already,
** Make sure the page is marked as dirty. If it isn't dirty already,
** make it so.
** make it so.
*/
*/
void
sqlite3PcacheMakeDirty
(
PgHdr
*
p
){
void
sqlite3PcacheMakeDirty
(
PgHdr
*
p
)
{
assert
(
p
->
nRef
>
0
);
assert
(
p
->
nRef
>
0
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
if
(
p
->
flags
&
(
PGHDR_CLEAN
|
PGHDR_DONT_WRITE
)
){
/*OPTIMIZATION-IF-FALSE*/
if
(
p
->
flags
&
(
PGHDR_CLEAN
|
PGHDR_DONT_WRITE
))
{
/*OPTIMIZATION-IF-FALSE*/
p
->
flags
&=
~
PGHDR_DONT_WRITE
;
p
->
flags
&=
~
PGHDR_DONT_WRITE
;
if
(
p
->
flags
&
PGHDR_CLEAN
)
{
if
(
p
->
flags
&
PGHDR_CLEAN
)
{
p
->
flags
^=
(
PGHDR_DIRTY
|
PGHDR_CLEAN
);
p
->
flags
^=
(
PGHDR_DIRTY
|
PGHDR_CLEAN
);
pcacheTrace
((
"%p.DIRTY %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
pcacheTrace
((
"%p.DIRTY %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
assert
(
(
p
->
flags
&
(
PGHDR_DIRTY
|
PGHDR_CLEAN
))
==
PGHDR_DIRTY
);
assert
(
(
p
->
flags
&
(
PGHDR_DIRTY
|
PGHDR_CLEAN
))
==
PGHDR_DIRTY
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_ADD
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_ADD
);
}
}
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
}
}
}
}
...
@@ -569,16 +547,16 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
...
@@ -569,16 +547,16 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
** Make sure the page is marked as clean. If it isn't clean already,
** Make sure the page is marked as clean. If it isn't clean already,
** make it so.
** make it so.
*/
*/
void
sqlite3PcacheMakeClean
(
PgHdr
*
p
){
void
sqlite3PcacheMakeClean
(
PgHdr
*
p
)
{
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
(
p
->
flags
&
PGHDR_DIRTY
)
!=
0
);
assert
(
(
p
->
flags
&
PGHDR_DIRTY
)
!=
0
);
assert
(
(
p
->
flags
&
PGHDR_CLEAN
)
==
0
);
assert
(
(
p
->
flags
&
PGHDR_CLEAN
)
==
0
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_REMOVE
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_REMOVE
);
p
->
flags
&=
~
(
PGHDR_DIRTY
|
PGHDR_NEED_SYNC
|
PGHDR_WRITEABLE
);
p
->
flags
&=
~
(
PGHDR_DIRTY
|
PGHDR_NEED_SYNC
|
PGHDR_WRITEABLE
);
p
->
flags
|=
PGHDR_CLEAN
;
p
->
flags
|=
PGHDR_CLEAN
;
pcacheTrace
((
"%p.CLEAN %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
pcacheTrace
((
"%p.CLEAN %d
\n
"
,
p
->
pCache
,
p
->
pgno
));
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
if
(
p
->
nRef
==
0
)
{
if
(
p
->
nRef
==
0
)
{
pcacheUnpin
(
p
);
pcacheUnpin
(
p
);
}
}
}
}
...
@@ -586,10 +564,10 @@ void sqlite3PcacheMakeClean(PgHdr *p){
...
@@ -586,10 +564,10 @@ void sqlite3PcacheMakeClean(PgHdr *p){
/*
/*
** Make every page in the cache clean.
** Make every page in the cache clean.
*/
*/
void
sqlite3PcacheCleanAll
(
PCache
*
pCache
){
void
sqlite3PcacheCleanAll
(
PCache
*
pCache
)
{
PgHdr
*
p
;
PgHdr
*
p
;
pcacheTrace
((
"%p.CLEAN-ALL
\n
"
,
pCache
));
pcacheTrace
((
"%p.CLEAN-ALL
\n
"
,
pCache
));
while
(
(
p
=
pCache
->
pDirty
)
!=
0
)
{
while
((
p
=
pCache
->
pDirty
)
!=
0
)
{
sqlite3PcacheMakeClean
(
p
);
sqlite3PcacheMakeClean
(
p
);
}
}
}
}
...
@@ -597,11 +575,11 @@ void sqlite3PcacheCleanAll(PCache *pCache){
...
@@ -597,11 +575,11 @@ void sqlite3PcacheCleanAll(PCache *pCache){
/*
/*
** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
*/
*/
void
sqlite3PcacheClearWritable
(
PCache
*
pCache
){
void
sqlite3PcacheClearWritable
(
PCache
*
pCache
)
{
PgHdr
*
p
;
PgHdr
*
p
;
pcacheTrace
((
"%p.CLEAR-WRITEABLE
\n
"
,
pCache
));
pcacheTrace
((
"%p.CLEAR-WRITEABLE
\n
"
,
pCache
));
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
p
->
flags
&=
~
(
PGHDR_NEED_SYNC
|
PGHDR_WRITEABLE
);
p
->
flags
&=
~
(
PGHDR_NEED_SYNC
|
PGHDR_WRITEABLE
);
}
}
pCache
->
pSynced
=
pCache
->
pDirtyTail
;
pCache
->
pSynced
=
pCache
->
pDirtyTail
;
}
}
...
@@ -609,26 +587,26 @@ void sqlite3PcacheClearWritable(PCache *pCache){
...
@@ -609,26 +587,26 @@ void sqlite3PcacheClearWritable(PCache *pCache){
/*
/*
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
*/
*/
void
sqlite3PcacheClearSyncFlags
(
PCache
*
pCache
){
void
sqlite3PcacheClearSyncFlags
(
PCache
*
pCache
)
{
PgHdr
*
p
;
PgHdr
*
p
;
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
p
->
flags
&=
~
PGHDR_NEED_SYNC
;
p
->
flags
&=
~
PGHDR_NEED_SYNC
;
}
}
pCache
->
pSynced
=
pCache
->
pDirtyTail
;
pCache
->
pSynced
=
pCache
->
pDirtyTail
;
}
}
/*
/*
** Change the page number of page p to newPgno.
** Change the page number of page p to newPgno.
*/
*/
void
sqlite3PcacheMove
(
PgHdr
*
p
,
Pgno
newPgno
){
void
sqlite3PcacheMove
(
PgHdr
*
p
,
Pgno
newPgno
)
{
PCache
*
pCache
=
p
->
pCache
;
PCache
*
pCache
=
p
->
pCache
;
assert
(
p
->
nRef
>
0
);
assert
(
p
->
nRef
>
0
);
assert
(
newPgno
>
0
);
assert
(
newPgno
>
0
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
assert
(
sqlite3PcachePageSanity
(
p
)
);
pcacheTrace
((
"%p.MOVE %d -> %d
\n
"
,
pCache
,
p
->
pgno
,
newPgno
));
pcacheTrace
((
"%p.MOVE %d -> %d
\n
"
,
pCache
,
p
->
pgno
,
newPgno
));
sqlite3GlobalConfig
.
pcache2
.
xRekey
(
pCache
->
pCache
,
p
->
pPage
,
p
->
pgno
,
newPgno
);
pcache2
.
xRekey
(
pCache
->
pCache
,
p
->
pPage
,
p
->
pgno
,
newPgno
);
p
->
pgno
=
newPgno
;
p
->
pgno
=
newPgno
;
if
(
(
p
->
flags
&
PGHDR_DIRTY
)
&&
(
p
->
flags
&
PGHDR_NEED_SYNC
)
)
{
if
((
p
->
flags
&
PGHDR_DIRTY
)
&&
(
p
->
flags
&
PGHDR_NEED_SYNC
))
{
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_FRONT
);
pcacheManageDirtyList
(
p
,
PCACHE_DIRTYLIST_FRONT
);
}
}
}
}
...
@@ -642,74 +620,72 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
...
@@ -642,74 +620,72 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
** function is 0, then the data area associated with page 1 is zeroed, but
** function is 0, then the data area associated with page 1 is zeroed, but
** the page object is not dropped.
** the page object is not dropped.
*/
*/
void
sqlite3PcacheTruncate
(
PCache
*
pCache
,
Pgno
pgno
){
void
sqlite3PcacheTruncate
(
PCache
*
pCache
,
Pgno
pgno
)
{
if
(
pCache
->
pCache
)
{
if
(
pCache
->
pCache
)
{
PgHdr
*
p
;
PgHdr
*
p
;
PgHdr
*
pNext
;
PgHdr
*
pNext
;
pcacheTrace
((
"%p.TRUNCATE %d
\n
"
,
pCache
,
pgno
));
pcacheTrace
((
"%p.TRUNCATE %d
\n
"
,
pCache
,
pgno
));
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
pNext
)
{
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
pNext
)
{
pNext
=
p
->
pDirtyNext
;
pNext
=
p
->
pDirtyNext
;
/* This routine never gets call with a positive pgno except right
/* This routine never gets call with a positive pgno except right
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
** it must be that pgno==0.
** it must be that pgno==0.
*/
*/
assert
(
p
->
pgno
>
0
);
assert
(
p
->
pgno
>
0
);
if
(
p
->
pgno
>
pgno
)
{
if
(
p
->
pgno
>
pgno
)
{
assert
(
p
->
flags
&
PGHDR_DIRTY
);
assert
(
p
->
flags
&
PGHDR_DIRTY
);
sqlite3PcacheMakeClean
(
p
);
sqlite3PcacheMakeClean
(
p
);
}
}
}
}
if
(
pgno
==
0
&&
pCache
->
nRefSum
)
{
if
(
pgno
==
0
&&
pCache
->
nRefSum
)
{
sqlite3_pcache_page
*
pPage1
;
sqlite3_pcache_page
*
pPage1
;
pPage1
=
sqlite3GlobalConfig
.
pcache2
.
xFetch
(
pCache
->
pCache
,
1
,
0
);
pPage1
=
pcache2
.
xFetch
(
pCache
->
pCache
,
1
,
0
);
if
(
ALWAYS
(
pPage1
)
){
/* Page 1 is always available in cache, because
if
(
ALWAYS
(
pPage1
))
{
/* Page 1 is always available in cache, because
** pCache->nRefSum>0 */
** pCache->nRefSum>0 */
memset
(
pPage1
->
pBuf
,
0
,
pCache
->
szPage
);
memset
(
pPage1
->
pBuf
,
0
,
pCache
->
szPage
);
pgno
=
1
;
pgno
=
1
;
}
}
}
}
sqlite3GlobalConfig
.
pcache2
.
xTruncate
(
pCache
->
pCache
,
pgno
+
1
);
pcache2
.
xTruncate
(
pCache
->
pCache
,
pgno
+
1
);
}
}
}
}
/*
/*
** Close a cache.
** Close a cache.
*/
*/
void
sqlite3PcacheClose
(
PCache
*
pCache
){
void
sqlite3PcacheClose
(
PCache
*
pCache
)
{
assert
(
pCache
->
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
pcacheTrace
((
"%p.CLOSE
\n
"
,
pCache
));
pcacheTrace
((
"%p.CLOSE
\n
"
,
pCache
));
sqlite3GlobalConfig
.
pcache2
.
xDestroy
(
pCache
->
pCache
);
pcache2
.
xDestroy
(
pCache
->
pCache
);
}
}
/*
/*
** Discard the contents of the cache.
** Discard the contents of the cache.
*/
*/
void
sqlite3PcacheClear
(
PCache
*
pCache
){
void
sqlite3PcacheClear
(
PCache
*
pCache
)
{
sqlite3PcacheTruncate
(
pCache
,
0
);
}
sqlite3PcacheTruncate
(
pCache
,
0
);
}
/*
/*
** Merge two lists of pages connected by pDirty and in pgno order.
** Merge two lists of pages connected by pDirty and in pgno order.
** Do not bother fixing the pDirtyPrev pointers.
** Do not bother fixing the pDirtyPrev pointers.
*/
*/
static
PgHdr
*
pcacheMergeDirtyList
(
PgHdr
*
pA
,
PgHdr
*
pB
){
static
PgHdr
*
pcacheMergeDirtyList
(
PgHdr
*
pA
,
PgHdr
*
pB
)
{
PgHdr
result
,
*
pTail
;
PgHdr
result
,
*
pTail
;
pTail
=
&
result
;
pTail
=
&
result
;
assert
(
pA
!=
0
&&
pB
!=
0
);
assert
(
pA
!=
0
&&
pB
!=
0
);
for
(;;)
{
for
(;;)
{
if
(
pA
->
pgno
<
pB
->
pgno
)
{
if
(
pA
->
pgno
<
pB
->
pgno
)
{
pTail
->
pDirty
=
pA
;
pTail
->
pDirty
=
pA
;
pTail
=
pA
;
pTail
=
pA
;
pA
=
pA
->
pDirty
;
pA
=
pA
->
pDirty
;
if
(
pA
==
0
)
{
if
(
pA
==
0
)
{
pTail
->
pDirty
=
pB
;
pTail
->
pDirty
=
pB
;
break
;
break
;
}
}
}
else
{
}
else
{
pTail
->
pDirty
=
pB
;
pTail
->
pDirty
=
pB
;
pTail
=
pB
;
pTail
=
pB
;
pB
=
pB
->
pDirty
;
pB
=
pB
->
pDirty
;
if
(
pB
==
0
)
{
if
(
pB
==
0
)
{
pTail
->
pDirty
=
pA
;
pTail
->
pDirty
=
pA
;
break
;
break
;
}
}
...
@@ -728,25 +704,25 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
...
@@ -728,25 +704,25 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
** One extra bucket is added to catch overflow in case something
** One extra bucket is added to catch overflow in case something
** ever changes to make the previous sentence incorrect.
** ever changes to make the previous sentence incorrect.
*/
*/
#define N_SORT_BUCKET
32
#define N_SORT_BUCKET 32
static
PgHdr
*
pcacheSortDirtyList
(
PgHdr
*
pIn
){
static
PgHdr
*
pcacheSortDirtyList
(
PgHdr
*
pIn
)
{
PgHdr
*
a
[
N_SORT_BUCKET
],
*
p
;
PgHdr
*
a
[
N_SORT_BUCKET
],
*
p
;
int
i
;
int
i
;
memset
(
a
,
0
,
sizeof
(
a
));
memset
(
a
,
0
,
sizeof
(
a
));
while
(
pIn
)
{
while
(
pIn
)
{
p
=
pIn
;
p
=
pIn
;
pIn
=
p
->
pDirty
;
pIn
=
p
->
pDirty
;
p
->
pDirty
=
0
;
p
->
pDirty
=
0
;
for
(
i
=
0
;
ALWAYS
(
i
<
N_SORT_BUCKET
-
1
);
i
++
)
{
for
(
i
=
0
;
ALWAYS
(
i
<
N_SORT_BUCKET
-
1
);
i
++
)
{
if
(
a
[
i
]
==
0
)
{
if
(
a
[
i
]
==
0
)
{
a
[
i
]
=
p
;
a
[
i
]
=
p
;
break
;
break
;
}
else
{
}
else
{
p
=
pcacheMergeDirtyList
(
a
[
i
],
p
);
p
=
pcacheMergeDirtyList
(
a
[
i
],
p
);
a
[
i
]
=
0
;
a
[
i
]
=
0
;
}
}
}
}
if
(
NEVER
(
i
==
N_SORT_BUCKET
-
1
)
)
{
if
(
NEVER
(
i
==
N_SORT_BUCKET
-
1
))
{
/* To get here, there need to be 2^(N_SORT_BUCKET) elements in
/* To get here, there need to be 2^(N_SORT_BUCKET) elements in
** the input list. But that is impossible.
** the input list. But that is impossible.
*/
*/
...
@@ -754,8 +730,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
...
@@ -754,8 +730,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
}
}
}
}
p
=
a
[
0
];
p
=
a
[
0
];
for
(
i
=
1
;
i
<
N_SORT_BUCKET
;
i
++
)
{
for
(
i
=
1
;
i
<
N_SORT_BUCKET
;
i
++
)
{
if
(
a
[
i
]
==
0
)
continue
;
if
(
a
[
i
]
==
0
)
continue
;
p
=
p
?
pcacheMergeDirtyList
(
p
,
a
[
i
])
:
a
[
i
];
p
=
p
?
pcacheMergeDirtyList
(
p
,
a
[
i
])
:
a
[
i
];
}
}
return
p
;
return
p
;
...
@@ -764,56 +740,49 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
...
@@ -764,56 +740,49 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
/*
/*
** Return a list of all dirty pages in the cache, sorted by page number.
** Return a list of all dirty pages in the cache, sorted by page number.
*/
*/
PgHdr
*
sqlite3PcacheDirtyList
(
PCache
*
pCache
){
PgHdr
*
sqlite3PcacheDirtyList
(
PCache
*
pCache
)
{
PgHdr
*
p
;
PgHdr
*
p
;
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
for
(
p
=
pCache
->
pDirty
;
p
;
p
=
p
->
pDirtyNext
)
{
p
->
pDirty
=
p
->
pDirtyNext
;
p
->
pDirty
=
p
->
pDirtyNext
;
}
}
return
pcacheSortDirtyList
(
pCache
->
pDirty
);
return
pcacheSortDirtyList
(
pCache
->
pDirty
);
}
}
/*
/*
** Return the total number of references to all pages held by the cache.
** Return the total number of references to all pages held by the cache.
**
**
** This is not the total number of pages referenced, but the sum of the
** This is not the total number of pages referenced, but the sum of the
** reference count for all pages.
** reference count for all pages.
*/
*/
int
sqlite3PcacheRefCount
(
PCache
*
pCache
){
int
sqlite3PcacheRefCount
(
PCache
*
pCache
)
{
return
pCache
->
nRefSum
;
}
return
pCache
->
nRefSum
;
}
/*
/*
** Return the number of references to the page supplied as an argument.
** Return the number of references to the page supplied as an argument.
*/
*/
int
sqlite3PcachePageRefcount
(
PgHdr
*
p
){
int
sqlite3PcachePageRefcount
(
PgHdr
*
p
)
{
return
p
->
nRef
;
}
return
p
->
nRef
;
}
/*
/*
** Return the total number of pages in the cache.
** Return the total number of pages in the cache.
*/
*/
int
sqlite3PcachePagecount
(
PCache
*
pCache
){
int
sqlite3PcachePagecount
(
PCache
*
pCache
)
{
assert
(
pCache
->
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
return
sqlite3GlobalConfig
.
pcache2
.
xPagecount
(
pCache
->
pCache
);
return
pcache2
.
xPagecount
(
pCache
->
pCache
);
}
}
#ifdef SQLITE_TEST
#ifdef SQLITE_TEST
/*
/*
** Get the suggested cache-size value.
** Get the suggested cache-size value.
*/
*/
int
sqlite3PcacheGetCachesize
(
PCache
*
pCache
){
int
sqlite3PcacheGetCachesize
(
PCache
*
pCache
)
{
return
numberOfCachePages
(
pCache
);
}
return
numberOfCachePages
(
pCache
);
}
#endif
#endif
/*
/*
** Set the suggested cache-size value.
** Set the suggested cache-size value.
*/
*/
void
sqlite3PcacheSetCachesize
(
PCache
*
pCache
,
int
mxPage
){
void
sqlite3PcacheSetCachesize
(
PCache
*
pCache
,
int
mxPage
)
{
assert
(
pCache
->
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
pCache
->
szCache
=
mxPage
;
pCache
->
szCache
=
mxPage
;
sqlite3GlobalConfig
.
pcache2
.
xCachesize
(
pCache
->
pCache
,
pcache2
.
xCachesize
(
pCache
->
pCache
,
numberOfCachePages
(
pCache
));
numberOfCachePages
(
pCache
));
}
}
/*
/*
...
@@ -821,53 +790,51 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
...
@@ -821,53 +790,51 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
** argument is zero. Return the effective cache-spill size, which will
** argument is zero. Return the effective cache-spill size, which will
** be the larger of the szSpill and szCache.
** be the larger of the szSpill and szCache.
*/
*/
int
sqlite3PcacheSetSpillsize
(
PCache
*
p
,
int
mxPage
){
int
sqlite3PcacheSetSpillsize
(
PCache
*
p
,
int
mxPage
)
{
int
res
;
int
res
;
assert
(
p
->
pCache
!=
0
);
assert
(
p
->
pCache
!=
0
);
if
(
mxPage
)
{
if
(
mxPage
)
{
if
(
mxPage
<
0
)
{
if
(
mxPage
<
0
)
{
mxPage
=
(
int
)((
-
1024
*
(
i64
)
mxPage
)
/
(
p
->
szPage
+
p
->
szExtra
));
mxPage
=
(
int
)((
-
1024
*
(
i64
)
mxPage
)
/
(
p
->
szPage
+
p
->
szExtra
));
}
}
p
->
szSpill
=
mxPage
;
p
->
szSpill
=
mxPage
;
}
}
res
=
numberOfCachePages
(
p
);
res
=
numberOfCachePages
(
p
);
if
(
res
<
p
->
szSpill
)
res
=
p
->
szSpill
;
if
(
res
<
p
->
szSpill
)
res
=
p
->
szSpill
;
return
res
;
return
res
;
}
}
/*
/*
** Free up as much memory as possible from the page cache.
** Free up as much memory as possible from the page cache.
*/
*/
void
sqlite3PcacheShrink
(
PCache
*
pCache
){
void
sqlite3PcacheShrink
(
PCache
*
pCache
)
{
assert
(
pCache
->
pCache
!=
0
);
assert
(
pCache
->
pCache
!=
0
);
sqlite3GlobalConfig
.
pcache2
.
xShrink
(
pCache
->
pCache
);
pcache2
.
xShrink
(
pCache
->
pCache
);
}
}
/*
/*
** Return the size of the header added by this middleware layer
** Return the size of the header added by this middleware layer
** in the page-cache hierarchy.
** in the page-cache hierarchy.
*/
*/
int
sqlite3HeaderSizePcache
(
void
){
return
ROUND8
(
sizeof
(
PgHdr
));
}
int
sqlite3HeaderSizePcache
(
void
)
{
return
ROUND8
(
sizeof
(
PgHdr
));
}
/*
/*
** Return the number of dirty pages currently in the cache, as a percentage
** Return the number of dirty pages currently in the cache, as a percentage
** of the configured cache size.
** of the configured cache size.
*/
*/
int
sqlite3PCachePercentDirty
(
PCache
*
pCache
){
int
sqlite3PCachePercentDirty
(
PCache
*
pCache
)
{
PgHdr
*
pDirty
;
PgHdr
*
pDirty
;
int
nDirty
=
0
;
int
nDirty
=
0
;
int
nCache
=
numberOfCachePages
(
pCache
);
int
nCache
=
numberOfCachePages
(
pCache
);
for
(
pDirty
=
pCache
->
pDirty
;
pDirty
;
pDirty
=
pDirty
->
pDirtyNext
)
nDirty
++
;
for
(
pDirty
=
pCache
->
pDirty
;
pDirty
;
pDirty
=
pDirty
->
pDirtyNext
)
nDirty
++
;
return
nCache
?
(
int
)(((
i64
)
nDirty
*
100
)
/
nCache
)
:
0
;
return
nCache
?
(
int
)(((
i64
)
nDirty
*
100
)
/
nCache
)
:
0
;
}
}
#ifdef SQLITE_DIRECT_OVERFLOW_READ
#ifdef SQLITE_DIRECT_OVERFLOW_READ
/*
/*
** Return true if there are one or more dirty pages in the cache. Else false.
** Return true if there are one or more dirty pages in the cache. Else false.
*/
*/
int
sqlite3PCacheIsDirty
(
PCache
*
pCache
){
int
sqlite3PCacheIsDirty
(
PCache
*
pCache
)
{
return
(
pCache
->
pDirty
!=
0
);
}
return
(
pCache
->
pDirty
!=
0
);
}
#endif
#endif
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
...
@@ -876,9 +843,9 @@ int sqlite3PCacheIsDirty(PCache *pCache){
...
@@ -876,9 +843,9 @@ int sqlite3PCacheIsDirty(PCache *pCache){
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
** defined.
** defined.
*/
*/
void
sqlite3PcacheIterateDirty
(
PCache
*
pCache
,
void
(
*
xIter
)(
PgHdr
*
)){
void
sqlite3PcacheIterateDirty
(
PCache
*
pCache
,
void
(
*
xIter
)(
PgHdr
*
))
{
PgHdr
*
pDirty
;
PgHdr
*
pDirty
;
for
(
pDirty
=
pCache
->
pDirty
;
pDirty
;
pDirty
=
pDirty
->
pDirtyNext
)
{
for
(
pDirty
=
pCache
->
pDirty
;
pDirty
;
pDirty
=
pDirty
->
pDirtyNext
)
{
xIter
(
pDirty
);
xIter
(
pDirty
);
}
}
}
}
...
...
source/libs/tdb/src/sqlite/pcache1.c
浏览文件 @
7248dc68
...
@@ -199,10 +199,26 @@ struct PgFreeslot {
...
@@ -199,10 +199,26 @@ struct PgFreeslot {
PgFreeslot
*
pNext
;
/* Next free slot */
PgFreeslot
*
pNext
;
/* Next free slot */
};
};
sqlite3_pcache_methods2
pcache2
=
{
1
,
/* iVersion */
0
,
/* pArg */
pcache1Init
,
/* xInit */
pcache1Shutdown
,
/* xShutdown */
pcache1Create
,
/* xCreate */
pcache1Cachesize
,
/* xCachesize */
pcache1Pagecount
,
/* xPagecount */
pcache1Fetch
,
/* xFetch */
pcache1Unpin
,
/* xUnpin */
pcache1Rekey
,
/* xRekey */
pcache1Truncate
,
/* xTruncate */
pcache1Destroy
,
/* xDestroy */
pcache1Shrink
/* xShrink */
};
/*
/*
** Global data used by this cache.
** Global data used by this cache.
*/
*/
static
SQLITE_WSD
struct
PCacheGlobal
{
static
struct
PCacheGlobal
{
PGroup
grp
;
/* The global PGroup for mode (2) */
PGroup
grp
;
/* The global PGroup for mode (2) */
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
/* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
...
@@ -226,14 +242,7 @@ static SQLITE_WSD struct PCacheGlobal {
...
@@ -226,14 +242,7 @@ static SQLITE_WSD struct PCacheGlobal {
** (2) even if an incorrect value is read, no great harm is done since this
** (2) even if an incorrect value is read, no great harm is done since this
** is really just an optimization. */
** is really just an optimization. */
int
bUnderPressure
;
/* True if low on PAGECACHE memory */
int
bUnderPressure
;
/* True if low on PAGECACHE memory */
}
pcache1_g
;
}
pcache1
;
/*
** All code in this file should access the global structure above via the
** alias "pcache1". This ensures that the WSD emulation is used when
** compiling for systems that do not support real WSD.
*/
#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
/*
/*
** Macros to enter and leave the PCache LRU mutex.
** Macros to enter and leave the PCache LRU mutex.
...
...
source/libs/tdb/src/sqliteinc/pcache.h
浏览文件 @
7248dc68
...
@@ -10,12 +10,12 @@
...
@@ -10,12 +10,12 @@
**
**
*************************************************************************
*************************************************************************
** This header file defines the interface that the sqlite page cache
** This header file defines the interface that the sqlite page cache
** subsystem.
** subsystem.
*/
*/
#ifndef _PCACHE_H_
#ifndef _PCACHE_H_
typedef
struct
PgHdr
PgHdr
;
typedef
struct
PgHdr
PgHdr
;
typedef
struct
PCache
PCache
;
typedef
struct
PCache
PCache
;
/*
/*
...
@@ -23,43 +23,44 @@ typedef struct PCache PCache;
...
@@ -23,43 +23,44 @@ typedef struct PCache PCache;
** structure.
** structure.
*/
*/
struct
PgHdr
{
struct
PgHdr
{
sqlite3_pcache_page
*
pPage
;
/* Pcache object page handle */
sqlite3_pcache_page
*
pPage
;
/* Pcache object page handle */
void
*
pData
;
/* Page data */
void
*
pData
;
/* Page data */
void
*
pExtra
;
/* Extra content */
void
*
pExtra
;
/* Extra content */
PCache
*
pCache
;
/* PRIVATE: Cache that owns this page */
PCache
*
pCache
;
/* PRIVATE: Cache that owns this page */
PgHdr
*
pDirty
;
/* Transient list of dirty sorted by pgno */
PgHdr
*
pDirty
;
/* Transient list of dirty sorted by pgno */
Pager
*
pPager
;
/* The pager this page is part of */
Pager
*
pPager
;
/* The pager this page is part of */
Pgno
pgno
;
/* Page number for this page */
Pgno
pgno
;
/* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
#ifdef SQLITE_CHECK_PAGES
u32
pageHash
;
/* Hash of page content */
u32
pageHash
;
/* Hash of page content */
#endif
#endif
u16
flags
;
/* PGHDR flags defined below */
u16
flags
;
/* PGHDR flags defined below */
/**********************************************************************
/**********************************************************************
** Elements above, except pCache, are public. All that follow are
** Elements above, except pCache, are public. All that follow are
** private to pcache.c and should not be accessed by other modules.
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
** pCache is grouped with the public elements for efficiency.
*/
*/
i16
nRef
;
/* Number of users of this page */
i16
nRef
;
/* Number of users of this page */
PgHdr
*
pDirtyNext
;
/* Next element in list of dirty pages */
PgHdr
*
pDirtyNext
;
/* Next element in list of dirty pages */
PgHdr
*
pDirtyPrev
;
/* Previous element in list of dirty pages */
PgHdr
*
pDirtyPrev
;
/* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
/* NB: pDirtyNext and pDirtyPrev are undefined if the
** PgHdr object is not dirty */
** PgHdr object is not dirty */
};
};
/* Bit values for PgHdr.flags */
/* Bit values for PgHdr.flags */
#define PGHDR_CLEAN 0x001
/* Page not on the PCache.pDirty list */
#define PGHDR_CLEAN 0x001
/* Page not on the PCache.pDirty list */
#define PGHDR_DIRTY 0x002
/* Page is on the PCache.pDirty list */
#define PGHDR_DIRTY 0x002
/* Page is on the PCache.pDirty list */
#define PGHDR_WRITEABLE 0x004
/* Journaled and ready to modify */
#define PGHDR_WRITEABLE 0x004
/* Journaled and ready to modify */
#define PGHDR_NEED_SYNC 0x008
/* Fsync the rollback journal before
#define PGHDR_NEED_SYNC \
** writing this page to the database */
0x008
/* Fsync the rollback journal before \
#define PGHDR_DONT_WRITE 0x010
/* Do not write content to disk */
** writing this page to the database */
#define PGHDR_MMAP 0x020
/* This is an mmap page object */
#define PGHDR_DONT_WRITE 0x010
/* Do not write content to disk */
#define PGHDR_MMAP 0x020
/* This is an mmap page object */
#define PGHDR_WAL_APPEND
0x040
/* Appended to wal file */
#define PGHDR_WAL_APPEND
0x040
/* Appended to wal file */
/* Initialize and shutdown the page cache subsystem */
/* Initialize and shutdown the page cache subsystem */
int
sqlite3PcacheInitialize
(
void
);
int
sqlite3PcacheInitialize
(
void
);
void
sqlite3PcacheShutdown
(
void
);
void
sqlite3PcacheShutdown
(
void
);
/* Page cache buffer management:
/* Page cache buffer management:
...
@@ -71,13 +72,12 @@ void sqlite3PCacheBufferSetup(void *, int sz, int n);
...
@@ -71,13 +72,12 @@ void sqlite3PCacheBufferSetup(void *, int sz, int n);
** Under memory stress, invoke xStress to try to make pages clean.
** Under memory stress, invoke xStress to try to make pages clean.
** Only clean and unpinned pages can be reclaimed.
** Only clean and unpinned pages can be reclaimed.
*/
*/
int
sqlite3PcacheOpen
(
int
sqlite3PcacheOpen
(
int
szPage
,
/* Size of every page */
int
szPage
,
/* Size of every page */
int
szExtra
,
/* Extra space associated with each page */
int
szExtra
,
/* Extra space associated with each page */
int
bPurgeable
,
/* True if pages are on backing store */
int
bPurgeable
,
/* True if pages are on backing store */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
void
*
pStress
,
/* Argument to xStress */
void
*
pStress
,
/* Argument to xStress */
PCache
*
pToInit
/* Preallocated space for the PCache */
PCache
*
pToInit
/* Preallocated space for the PCache */
);
);
/* Modify the page-size after the cache has been created. */
/* Modify the page-size after the cache has been created. */
...
@@ -89,51 +89,51 @@ int sqlite3PcacheSetPageSize(PCache *, int);
...
@@ -89,51 +89,51 @@ int sqlite3PcacheSetPageSize(PCache *, int);
int
sqlite3PcacheSize
(
void
);
int
sqlite3PcacheSize
(
void
);
/* One release per successful fetch. Page is pinned until released.
/* One release per successful fetch. Page is pinned until released.
** Reference counted.
** Reference counted.
*/
*/
sqlite3_pcache_page
*
sqlite3PcacheFetch
(
PCache
*
,
Pgno
,
int
createFlag
);
sqlite3_pcache_page
*
sqlite3PcacheFetch
(
PCache
*
,
Pgno
,
int
createFlag
);
int
sqlite3PcacheFetchStress
(
PCache
*
,
Pgno
,
sqlite3_pcache_page
**
);
int
sqlite3PcacheFetchStress
(
PCache
*
,
Pgno
,
sqlite3_pcache_page
**
);
PgHdr
*
sqlite3PcacheFetchFinish
(
PCache
*
,
Pgno
,
sqlite3_pcache_page
*
pPage
);
PgHdr
*
sqlite3PcacheFetchFinish
(
PCache
*
,
Pgno
,
sqlite3_pcache_page
*
pPage
);
void
sqlite3PcacheRelease
(
PgHdr
*
);
void
sqlite3PcacheRelease
(
PgHdr
*
);
void
sqlite3PcacheDrop
(
PgHdr
*
);
/* Remove page from cache */
void
sqlite3PcacheDrop
(
PgHdr
*
);
/* Remove page from cache */
void
sqlite3PcacheMakeDirty
(
PgHdr
*
);
/* Make sure page is marked dirty */
void
sqlite3PcacheMakeDirty
(
PgHdr
*
);
/* Make sure page is marked dirty */
void
sqlite3PcacheMakeClean
(
PgHdr
*
);
/* Mark a single page as clean */
void
sqlite3PcacheMakeClean
(
PgHdr
*
);
/* Mark a single page as clean */
void
sqlite3PcacheCleanAll
(
PCache
*
);
/* Mark all dirty list pages as clean */
void
sqlite3PcacheCleanAll
(
PCache
*
);
/* Mark all dirty list pages as clean */
void
sqlite3PcacheClearWritable
(
PCache
*
);
void
sqlite3PcacheClearWritable
(
PCache
*
);
/* Change a page number. Used by incr-vacuum. */
/* Change a page number. Used by incr-vacuum. */
void
sqlite3PcacheMove
(
PgHdr
*
,
Pgno
);
void
sqlite3PcacheMove
(
PgHdr
*
,
Pgno
);
/* Remove all pages with pgno>x. Reset the cache if x==0 */
/* Remove all pages with pgno>x. Reset the cache if x==0 */
void
sqlite3PcacheTruncate
(
PCache
*
,
Pgno
x
);
void
sqlite3PcacheTruncate
(
PCache
*
,
Pgno
x
);
/* Get a list of all dirty pages in the cache, sorted by page number */
/* Get a list of all dirty pages in the cache, sorted by page number */
PgHdr
*
sqlite3PcacheDirtyList
(
PCache
*
);
PgHdr
*
sqlite3PcacheDirtyList
(
PCache
*
);
/* Reset and close the cache object */
/* Reset and close the cache object */
void
sqlite3PcacheClose
(
PCache
*
);
void
sqlite3PcacheClose
(
PCache
*
);
/* Clear flags from pages of the page cache */
/* Clear flags from pages of the page cache */
void
sqlite3PcacheClearSyncFlags
(
PCache
*
);
void
sqlite3PcacheClearSyncFlags
(
PCache
*
);
/* Discard the contents of the cache */
/* Discard the contents of the cache */
void
sqlite3PcacheClear
(
PCache
*
);
void
sqlite3PcacheClear
(
PCache
*
);
/* Return the total number of outstanding page references */
/* Return the total number of outstanding page references */
int
sqlite3PcacheRefCount
(
PCache
*
);
int
sqlite3PcacheRefCount
(
PCache
*
);
/* Increment the reference count of an existing page */
/* Increment the reference count of an existing page */
void
sqlite3PcacheRef
(
PgHdr
*
);
void
sqlite3PcacheRef
(
PgHdr
*
);
int
sqlite3PcachePageRefcount
(
PgHdr
*
);
int
sqlite3PcachePageRefcount
(
PgHdr
*
);
/* Return the total number of pages stored in the cache */
/* Return the total number of pages stored in the cache */
int
sqlite3PcachePagecount
(
PCache
*
);
int
sqlite3PcachePagecount
(
PCache
*
);
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/* Iterate through all dirty pages currently stored in the cache. This
/* Iterate through all dirty pages currently stored in the cache. This
** interface is only available if SQLITE_CHECK_PAGES is defined when the
** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
** library is built.
*/
*/
void
sqlite3PcacheIterateDirty
(
PCache
*
pCache
,
void
(
*
xIter
)(
PgHdr
*
));
void
sqlite3PcacheIterateDirty
(
PCache
*
pCache
,
void
(
*
xIter
)(
PgHdr
*
));
...
@@ -141,7 +141,7 @@ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
...
@@ -141,7 +141,7 @@ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#if defined(SQLITE_DEBUG)
#if defined(SQLITE_DEBUG)
/* Check invariants on a PgHdr object */
/* Check invariants on a PgHdr object */
int
sqlite3PcachePageSanity
(
PgHdr
*
);
int
sqlite3PcachePageSanity
(
PgHdr
*
);
#endif
#endif
/* Set and get the suggested cache-size for the specified pager-cache.
/* Set and get the suggested cache-size for the specified pager-cache.
...
@@ -163,7 +163,7 @@ int sqlite3PcacheGetCachesize(PCache *);
...
@@ -163,7 +163,7 @@ int sqlite3PcacheGetCachesize(PCache *);
int
sqlite3PcacheSetSpillsize
(
PCache
*
,
int
);
int
sqlite3PcacheSetSpillsize
(
PCache
*
,
int
);
/* Free up as much memory as possible from the page cache */
/* Free up as much memory as possible from the page cache */
void
sqlite3PcacheShrink
(
PCache
*
);
void
sqlite3PcacheShrink
(
PCache
*
);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* Try to return memory used by the pcache module to the main memory heap */
/* Try to return memory used by the pcache module to the main memory heap */
...
@@ -171,7 +171,7 @@ int sqlite3PcacheReleaseMemory(int);
...
@@ -171,7 +171,7 @@ int sqlite3PcacheReleaseMemory(int);
#endif
#endif
#ifdef SQLITE_TEST
#ifdef SQLITE_TEST
void
sqlite3PcacheStats
(
int
*
,
int
*
,
int
*
,
int
*
);
void
sqlite3PcacheStats
(
int
*
,
int
*
,
int
*
,
int
*
);
#endif
#endif
void
sqlite3PCacheSetDefault
(
void
);
void
sqlite3PCacheSetDefault
(
void
);
...
@@ -181,10 +181,30 @@ int sqlite3HeaderSizePcache(void);
...
@@ -181,10 +181,30 @@ int sqlite3HeaderSizePcache(void);
int
sqlite3HeaderSizePcache1
(
void
);
int
sqlite3HeaderSizePcache1
(
void
);
/* Number of dirty pages as a percentage of the configured cache size */
/* Number of dirty pages as a percentage of the configured cache size */
int
sqlite3PCachePercentDirty
(
PCache
*
);
int
sqlite3PCachePercentDirty
(
PCache
*
);
#ifdef SQLITE_DIRECT_OVERFLOW_READ
#ifdef SQLITE_DIRECT_OVERFLOW_READ
int
sqlite3PCacheIsDirty
(
PCache
*
pCache
);
int
sqlite3PCacheIsDirty
(
PCache
*
pCache
);
#endif
#endif
// For real implementation of sqlite3_pcache ========================================
typedef
struct
sqlite3_pcache
sqlite3_pcache
;
typedef
struct
sqlite3_pcache_methods2
{
int
iVersion
;
void
*
pArg
;
int
(
*
xInit
)(
void
*
);
void
(
*
xShutdown
)(
void
*
);
sqlite3_pcache
*
(
*
xCreate
)(
int
szPage
,
int
szExtra
,
int
bPurgeable
);
void
(
*
xCachesize
)(
sqlite3_pcache
*
,
int
nCachesize
);
int
(
*
xPagecount
)(
sqlite3_pcache
*
);
sqlite3_pcache_page
*
(
*
xFetch
)(
sqlite3_pcache
*
,
unsigned
key
,
int
createFlag
);
void
(
*
xUnpin
)(
sqlite3_pcache
*
,
sqlite3_pcache_page
*
,
int
discard
);
void
(
*
xRekey
)(
sqlite3_pcache
*
,
sqlite3_pcache_page
*
,
unsigned
oldKey
,
unsigned
newKey
);
void
(
*
xTruncate
)(
sqlite3_pcache
*
,
unsigned
iLimit
);
void
(
*
xDestroy
)(
sqlite3_pcache
*
);
void
(
*
xShrink
)(
sqlite3_pcache
*
);
}
sqlite3_pcache_methods2
;
extern
sqlite3_pcache_methods2
pcache2
;
#endif
/* _PCACHE_H_ */
#endif
/* _PCACHE_H_ */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录