Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
7184778c
T
TDengine
项目概览
taosdata
/
TDengine
大约 2 年 前同步成功
通知
1192
Star
22018
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
7184778c
编写于
2月 21, 2022
作者:
H
Hongze Cheng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
more page cache
上级
7248dc68
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
698 addition
and
732 deletion
+698
-732
source/libs/tdb/src/sqlite/pcache.c
source/libs/tdb/src/sqlite/pcache.c
+300
-274
source/libs/tdb/src/sqlite/pcache1.c
source/libs/tdb/src/sqlite/pcache1.c
+391
-458
source/libs/tdb/src/sqliteinc/sqliteInt.h
source/libs/tdb/src/sqliteinc/sqliteInt.h
+7
-0
未找到文件。
source/libs/tdb/src/sqlite/pcache.c
浏览文件 @
7184778c
...
@@ -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,39 +63,36 @@ struct PCache {
...
@@ -63,39 +63,36 @@ 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) \
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
if (sqlite3PcacheTrace) { \
void
pcacheDump
(
PCache
*
pCache
){
sqlite3DebugPrintf X; \
int
N
;
}
int
i
,
j
;
void
pcacheDump
(
PCache
*
pCache
)
{
sqlite3_pcache_page
*
pLower
;
int
N
;
PgHdr
*
pPg
;
int
i
,
j
;
unsigned
char
*
a
;
sqlite3_pcache_page
*
pLower
;
PgHdr
*
pPg
;
if
(
sqlite3PcacheTrace
<
2
)
return
;
unsigned
char
*
a
;
if
(
pCache
->
pCache
==
0
)
return
;
N
=
sqlite3PcachePagecount
(
pCache
);
if
(
sqlite3PcacheTrace
<
2
)
return
;
if
(
N
>
sqlite3PcacheMxDump
)
N
=
sqlite3PcacheMxDump
;
if
(
pCache
->
pCache
==
0
)
return
;
for
(
i
=
1
;
i
<=
N
;
i
++
){
N
=
sqlite3PcachePagecount
(
pCache
);
pLower
=
pcache2
.
xFetch
(
pCache
->
pCache
,
i
,
0
);
if
(
N
>
sqlite3PcacheMxDump
)
N
=
sqlite3PcacheMxDump
;
if
(
pLower
==
0
)
continue
;
for
(
i
=
1
;
i
<=
N
;
i
++
)
{
pPg
=
(
PgHdr
*
)
pLower
->
pExtra
;
pLower
=
pcache2
.
xFetch
(
pCache
->
pCache
,
i
,
0
);
printf
(
"%3d: nRef %2d flgs %02x data "
,
i
,
pPg
->
nRef
,
pPg
->
flags
);
if
(
pLower
==
0
)
continue
;
a
=
(
unsigned
char
*
)
pLower
->
pBuf
;
pPg
=
(
PgHdr
*
)
pLower
->
pExtra
;
for
(
j
=
0
;
j
<
12
;
j
++
)
printf
(
"%02x"
,
a
[
j
]);
printf
(
"%3d: nRef %2d flgs %02x data "
,
i
,
pPg
->
nRef
,
pPg
->
flags
);
printf
(
"
\n
"
);
a
=
(
unsigned
char
*
)
pLower
->
pBuf
;
if
(
pPg
->
pPage
==
0
){
for
(
j
=
0
;
j
<
12
;
j
++
)
printf
(
"%02x"
,
a
[
j
]);
pcache2
.
xUnpin
(
pCache
->
pCache
,
pLower
,
0
);
printf
(
"
\n
"
);
}
if
(
pPg
->
pPage
==
0
)
{
pcache2
.
xUnpin
(
pCache
->
pCache
,
pLower
,
0
);
}
}
}
}
}
#else
#else
# define pcacheTrace(X)
#define pcacheTrace(X)
# define pcacheDump(X)
#define pcacheDump(X)
#endif
#endif
/*
/*
...
@@ -108,20 +105,20 @@ void pcacheDump(PCache *pCache) {
...
@@ -108,20 +105,20 @@ void pcacheDump(PCache *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:
...
@@ -144,12 +141,13 @@ int sqlite3PcachePageSanity(PgHdr *pPg) {
...
@@ -144,12 +141,13 @@ 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
...
@@ -157,63 +155,66 @@ int sqlite3PcachePageSanity(PgHdr *pPg) {
...
@@ -157,63 +155,66 @@ 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
,
addRemove
==
1
?
"REMOVE"
:
addRemove
==
2
?
"ADD"
:
"FRONT"
,
pPage
->
pgno
));
pcacheTrace
((
"%p.DIRTYLIST.%s %d
\n
"
,
p
,
if
(
addRemove
&
PCACHE_DIRTYLIST_REMOVE
)
{
addRemove
==
1
?
"REMOVE"
:
addRemove
==
2
?
"ADD"
:
"FRONT"
,
assert
(
pPage
->
pDirtyNext
||
pPage
==
p
->
pDirtyTail
);
pPage
->
pgno
));
assert
(
pPage
->
pDirtyPrev
||
pPage
==
p
->
pDirty
);
if
(
addRemove
&
PCACHE_DIRTYLIST_REMOVE
){
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
&&
0
==
(
pPage
->
flags
&
PGHDR_NEED_SYNC
)
/*OPTIMIZATION-IF-FALSE*/
if
(
!
p
->
pSynced
)
{
&&
0
==
(
pPage
->
flags
&
PGHDR_NEED_SYNC
)
/*OPTIMIZATION-IF-FALSE*/
){
p
->
pSynced
=
pPage
;
p
->
pSynced
=
pPage
;
}
}
}
}
...
@@ -224,8 +225,8 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove) {
...
@@ -224,8 +225,8 @@ 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
));
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
0
);
pcache2
.
xUnpin
(
p
->
pCache
->
pCache
,
p
->
pPage
,
0
);
pcacheDump
(
p
->
pCache
);
pcacheDump
(
p
->
pCache
);
...
@@ -236,31 +237,33 @@ static void pcacheUnpin(PgHdr *p) {
...
@@ -236,31 +237,33 @@ 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
)
{
return
pcache2
.
xInit
(
pcache2
.
pArg
);
}
int
sqlite3PcacheInitialize
(
void
){
void
sqlite3PcacheShutdown
(
void
)
{
return
pcache2
.
xInit
(
pcache2
.
pArg
);
if
(
pcache2
.
xShutdown
)
{
}
void
sqlite3PcacheShutdown
(
void
){
if
(
pcache2
.
xShutdown
){
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
pcache2
.
xShutdown
(
pcache2
.
pArg
);
pcache2
.
xShutdown
(
pcache2
.
pArg
);
}
}
...
@@ -269,12 +272,12 @@ void sqlite3PcacheShutdown(void) {
...
@@ -269,12 +272,12 @@ void sqlite3PcacheShutdown(void) {
/*
/*
** 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
...
@@ -283,24 +286,25 @@ int sqlite3PcacheSize(void) { return sizeof(PCache); }
...
@@ -283,24 +286,25 @@ 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
szPage
,
/* Size of every page */
int
sqlite3PcacheOpen
(
int
szExtra
,
/* Extra space associated with each page */
int
szPage
,
/* Size of every page */
int
bPurgeable
,
/* True if pages are on backing store */
int
szExtra
,
/* Extra space associated with each page */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
int
bPurgeable
,
/* True if pages are on backing store */
void
*
pStress
,
/* Argument to xStress */
int
(
*
xStress
)(
void
*
,
PgHdr
*
),
/* Call to try to make pages clean */
PCache
*
p
/* Preallocated space for the PCache */
void
*
pStress
,
/* Argument to xStress */
)
{
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
);
}
}
...
@@ -308,21 +312,24 @@ int sqlite3PcacheOpen(int szPage, /* Size of every page */
...
@@ -308,21 +312,24 @@ int sqlite3PcacheOpen(int szPage, /* Size of every page */
** 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
=
pcache2
.
xCreate
(
szPage
,
pCache
->
szExtra
+
ROUND8
(
sizeof
(
PgHdr
)),
pCache
->
bPurgeable
);
pNew
=
pcache2
.
xCreate
(
if
(
pNew
==
0
)
return
SQLITE_NOMEM_BKPT
;
szPage
,
pCache
->
szExtra
+
ROUND8
(
sizeof
(
PgHdr
)),
pCache
->
bPurgeable
);
if
(
pNew
==
0
)
return
SQLITE_NOMEM_BKPT
;
pcache2
.
xCachesize
(
pNew
,
numberOfCachePages
(
pCache
));
pcache2
.
xCachesize
(
pNew
,
numberOfCachePages
(
pCache
));
if
(
pCache
->
pCache
)
{
if
(
pCache
->
pCache
)
{
pcache2
.
xDestroy
(
pCache
->
pCache
);
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
0
;
}
}
/*
/*
...
@@ -349,17 +356,18 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage) {
...
@@ -349,17 +356,18 @@ 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
(
PCache
*
pCache
,
/* Obtain the page from this cache */
sqlite3_pcache_page
*
sqlite3PcacheFetch
(
Pgno
pgno
,
/* Page number to obtain */
PCache
*
pCache
,
/* Obtain the page from this cache */
int
createFlag
/* If true, create page if it does not exist already */
Pgno
pgno
,
/* Page number to obtain */
)
{
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)
...
@@ -369,18 +377,19 @@ sqlite3_pcache_page *sqlite3PcacheFetch(PCache *pCache, /* Obtain the page fr
...
@@ -369,18 +377,19 @@ sqlite3_pcache_page *sqlite3PcacheFetch(PCache *pCache, /* Obtain the page fr
** (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
=
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
eCreate
);
pRes
=
pcache2
.
xFetch
(
pCache
->
pCache
,
pgno
,
eCreate
);
pcacheTrace
((
"%p.FETCH %d%s (result: %p)
\n
"
,
pCache
,
pgno
,
createFlag
?
" create"
:
""
,
pRes
));
pcacheTrace
((
"%p.FETCH %d%s (result: %p)
\n
"
,
pCache
,
pgno
,
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
...
@@ -388,46 +397,51 @@ sqlite3_pcache_page *sqlite3PcacheFetch(PCache *pCache, /* Obtain the page fr
...
@@ -388,46 +397,51 @@ sqlite3_pcache_page *sqlite3PcacheFetch(PCache *pCache, /* Obtain the page fr
**
**
** This routine should be invoked only after sqlite3PcacheFetch() fails.
** This routine should be invoked only after sqlite3PcacheFetch() fails.
*/
*/
int
sqlite3PcacheFetchStress
(
PCache
*
pCache
,
/* Obtain the page from this cache */
int
sqlite3PcacheFetchStress
(
Pgno
pgno
,
/* Page number to obtain */
PCache
*
pCache
,
/* Obtain the page from this cache */
sqlite3_pcache_page
**
ppPage
/* Write result here */
Pgno
pgno
,
/* Page number to obtain */
)
{
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
;
pPg
&&
(
pPg
->
nRef
||
(
pPg
->
flags
&
PGHDR_NEED_SYNC
));
pPg
=
pPg
->
pDirtyPrev
)
for
(
pPg
=
pCache
->
pSynced
;
;
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
,
"spill page %d making room for %d - cache used: %d/%d"
,
pPg
->
pgno
,
pgno
,
sqlite3_log
(
SQLITE_FULL
,
pcache2
.
xPagecount
(
pCache
->
pCache
),
numberOfCachePages
(
pCache
));
"spill page %d making room for %d - cache used: %d/%d"
,
pPg
->
pgno
,
pgno
,
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
!=
0
&&
rc
!=
SQLITE_BUSY
)
{
return
rc
;
return
rc
;
}
}
}
}
}
}
*
ppPage
=
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
:
0
;
}
}
/*
/*
...
@@ -440,15 +454,15 @@ int sqlite3PcacheFetchStress(PCache * pCache, /* Obtain the page fr
...
@@ -440,15 +454,15 @@ int sqlite3PcacheFetchStress(PCache * pCache, /* Obtain the page fr
** 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
];
...
@@ -456,7 +470,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
...
@@ -456,7 +470,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
);
}
}
/*
/*
...
@@ -465,21 +479,22 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
...
@@ -465,21 +479,22 @@ 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
(
PCache
*
pCache
,
/* Obtain the page from this cache */
PgHdr
*
sqlite3PcacheFetchFinish
(
Pgno
pgno
,
/* Page number obtained */
PCache
*
pCache
,
/* Obtain the page from this cache */
sqlite3_pcache_page
*
pPage
/* Page obtained by prior PcacheFetch() call */
Pgno
pgno
,
/* Page number obtained */
)
{
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
;
}
}
...
@@ -487,13 +502,13 @@ PgHdr *sqlite3PcacheFetchFinish(PCache * pCache, /* Obtain the page
...
@@ -487,13 +502,13 @@ PgHdr *sqlite3PcacheFetchFinish(PCache * pCache, /* Obtain the page
** 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
);
}
}
}
}
...
@@ -502,9 +517,9 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p) {
...
@@ -502,9 +517,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
++
;
}
}
...
@@ -514,10 +529,10 @@ void sqlite3PcacheRef(PgHdr *p) {
...
@@ -514,10 +529,10 @@ 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
--
;
...
@@ -528,18 +543,18 @@ void sqlite3PcacheDrop(PgHdr *p) {
...
@@ -528,18 +543,18 @@ void sqlite3PcacheDrop(PgHdr *p) {
** 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
)
);
}
}
}
}
...
@@ -547,16 +562,16 @@ void sqlite3PcacheMakeDirty(PgHdr *p) {
...
@@ -547,16 +562,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
);
}
}
}
}
...
@@ -564,10 +579,10 @@ void sqlite3PcacheMakeClean(PgHdr *p) {
...
@@ -564,10 +579,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
);
}
}
}
}
...
@@ -575,11 +590,11 @@ void sqlite3PcacheCleanAll(PCache *pCache) {
...
@@ -575,11 +590,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
;
}
}
...
@@ -587,26 +602,26 @@ void sqlite3PcacheClearWritable(PCache *pCache) {
...
@@ -587,26 +602,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
));
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
);
}
}
}
}
...
@@ -620,72 +635,74 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno) {
...
@@ -620,72 +635,74 @@ 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
=
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
;
}
}
}
}
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
));
pcache2
.
xDestroy
(
pCache
->
pCache
);
pcache2
.
xDestroy
(
pCache
->
pCache
);
}
}
/*
/*
** Discard the contents of the cache.
** Discard the contents of the cache.
*/
*/
void
sqlite3PcacheClear
(
PCache
*
pCache
)
{
sqlite3PcacheTruncate
(
pCache
,
0
);
}
void
sqlite3PcacheClear
(
PCache
*
pCache
){
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
;
}
}
...
@@ -704,25 +721,25 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB) {
...
@@ -704,25 +721,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.
*/
*/
...
@@ -730,8 +747,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn) {
...
@@ -730,8 +747,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
;
...
@@ -740,32 +757,36 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn) {
...
@@ -740,32 +757,36 @@ 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
)
{
return
pCache
->
nRefSum
;
}
int
sqlite3PcacheRefCount
(
PCache
*
pCache
){
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
)
{
return
p
->
nRef
;
}
int
sqlite3PcachePageRefcount
(
PgHdr
*
p
){
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
pcache2
.
xPagecount
(
pCache
->
pCache
);
return
pcache2
.
xPagecount
(
pCache
->
pCache
);
}
}
...
@@ -773,16 +794,19 @@ int sqlite3PcachePagecount(PCache *pCache) {
...
@@ -773,16 +794,19 @@ int sqlite3PcachePagecount(PCache *pCache) {
/*
/*
** Get the suggested cache-size value.
** Get the suggested cache-size value.
*/
*/
int
sqlite3PcacheGetCachesize
(
PCache
*
pCache
)
{
return
numberOfCachePages
(
pCache
);
}
int
sqlite3PcacheGetCachesize
(
PCache
*
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
;
pcache2
.
xCachesize
(
pCache
->
pCache
,
numberOfCachePages
(
pCache
));
pcache2
.
xCachesize
(
pCache
->
pCache
,
numberOfCachePages
(
pCache
));
}
}
/*
/*
...
@@ -790,25 +814,25 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage) {
...
@@ -790,25 +814,25 @@ 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
);
pcache2
.
xShrink
(
pCache
->
pCache
);
pcache2
.
xShrink
(
pCache
->
pCache
);
}
}
...
@@ -816,25 +840,27 @@ void sqlite3PcacheShrink(PCache *pCache) {
...
@@ -816,25 +840,27 @@ void sqlite3PcacheShrink(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
)
{
return
(
pCache
->
pDirty
!=
0
);
}
int
sqlite3PCacheIsDirty
(
PCache
*
pCache
){
return
(
pCache
->
pDirty
!=
0
);
}
#endif
#endif
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
...
@@ -843,9 +869,9 @@ int sqlite3PCacheIsDirty(PCache *pCache) { return (pCache->pDirty != 0); }
...
@@ -843,9 +869,9 @@ int sqlite3PCacheIsDirty(PCache *pCache) { return (pCache->pDirty != 0); }
** 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
浏览文件 @
7184778c
...
@@ -63,7 +63,7 @@
...
@@ -63,7 +63,7 @@
**
**
** The third case is a chunk of heap memory (defaulting to 100 pages worth)
** The third case is a chunk of heap memory (defaulting to 100 pages worth)
** that is allocated when the page cache is created. The size of the local
** that is allocated when the page cache is created. The size of the local
** bulk allocation can be adjusted using
** bulk allocation can be adjusted using
**
**
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
**
**
...
@@ -82,47 +82,47 @@
...
@@ -82,47 +82,47 @@
*/
*/
#include "sqliteInt.h"
#include "sqliteInt.h"
typedef
struct
PCache1
PCache1
;
typedef
struct
PCache1
PCache1
;
typedef
struct
PgHdr1
PgHdr1
;
typedef
struct
PgHdr1
PgHdr1
;
typedef
struct
PgFreeslot
PgFreeslot
;
typedef
struct
PgFreeslot
PgFreeslot
;
typedef
struct
PGroup
PGroup
;
typedef
struct
PGroup
PGroup
;
/*
/*
** Each cache entry is represented by an instance of the following
** Each cache entry is represented by an instance of the following
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
** PgHdr1.pCache->szPage bytes is allocated directly before this structure
** PgHdr1.pCache->szPage bytes is allocated directly before this structure
** in memory.
** in memory.
**
**
** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since
** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located
** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
** read part of this structure before the corruption is detected. This
** can cause a valgrind error if the unitialized gap is accessed. Using u16
** can cause a valgrind error if the unitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of unitialized memory
** ensures there is no such gap, and therefore no bytes of unitialized memory
** in the structure.
** in the structure.
*/
*/
struct
PgHdr1
{
struct
PgHdr1
{
sqlite3_pcache_page
page
;
/* Base class. Must be first. pBuf & pExtra */
sqlite3_pcache_page
page
;
/* Base class. Must be first. pBuf & pExtra */
unsigned
int
iKey
;
/* Key value (page number) */
unsigned
int
iKey
;
/* Key value (page number) */
u16
isBulkLocal
;
/* This page from bulk local storage */
u16
isBulkLocal
;
/* This page from bulk local storage */
u16
isAnchor
;
/* This is the PGroup.lru element */
u16
isAnchor
;
/* This is the PGroup.lru element */
PgHdr1
*
pNext
;
/* Next in hash table chain */
PgHdr1
*
pNext
;
/* Next in hash table chain */
PCache1
*
pCache
;
/* Cache that currently owns this page */
PCache1
*
pCache
;
/* Cache that currently owns this page */
PgHdr1
*
pLruNext
;
/* Next in LRU list of unpinned pages */
PgHdr1
*
pLruNext
;
/* Next in LRU list of unpinned pages */
PgHdr1
*
pLruPrev
;
/* Previous in LRU list of unpinned pages */
PgHdr1
*
pLruPrev
;
/* Previous in LRU list of unpinned pages */
/* NB: pLruPrev is only valid if pLruNext!=0 */
/* NB: pLruPrev is only valid if pLruNext!=0 */
};
};
/*
/*
** A page is pinned if it is not on the LRU list. To be "pinned" means
** A page is pinned if it is not on the LRU list. To be "pinned" means
** that the page is in active use and must not be deallocated.
** that the page is in active use and must not be deallocated.
*/
*/
#define PAGE_IS_PINNED(p)
((p)->pLruNext==
0)
#define PAGE_IS_PINNED(p)
((p)->pLruNext ==
0)
#define PAGE_IS_UNPINNED(p)
((p)->pLruNext!=
0)
#define PAGE_IS_UNPINNED(p)
((p)->pLruNext !=
0)
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
** of one or more PCaches that are able to recycle each other's unpinned
** of one or more PCaches that are able to recycle each other's unpinned
** pages when they are under memory pressure. A PGroup is an instance of
** pages when they are under memory pressure. A PGroup is an instance of
** the following object.
** the following object.
...
@@ -145,12 +145,12 @@ struct PgHdr1 {
...
@@ -145,12 +145,12 @@ struct PgHdr1 {
** SQLITE_MUTEX_STATIC_LRU.
** SQLITE_MUTEX_STATIC_LRU.
*/
*/
struct
PGroup
{
struct
PGroup
{
sqlite3_mutex
*
mutex
;
/* MUTEX_STATIC_LRU or NULL */
pthread_mutex_t
mutex
;
/* MUTEX_STATIC_LRU or NULL */
unsigned
int
nMaxPage
;
/* Sum of nMax for purgeable caches */
unsigned
int
nMaxPage
;
/* Sum of nMax for purgeable caches */
unsigned
int
nMinPage
;
/* Sum of nMin for purgeable caches */
unsigned
int
nMinPage
;
/* Sum of nMin for purgeable caches */
unsigned
int
mxPinned
;
/* nMaxpage + 10 - nMinPage */
unsigned
int
mxPinned
;
/* nMaxpage + 10 - nMinPage */
unsigned
int
nPurgeable
;
/* Number of purgeable pages allocated */
unsigned
int
nPurgeable
;
/* Number of purgeable pages allocated */
PgHdr1
lru
;
/* The beginning and end of the LRU list */
PgHdr1
lru
;
/* The beginning and end of the LRU list */
};
};
/* Each page cache is an instance of the following object. Every
/* Each page cache is an instance of the following object. Every
...
@@ -158,37 +158,37 @@ struct PGroup {
...
@@ -158,37 +158,37 @@ struct PGroup {
** temporary or transient database) has a single page cache which
** temporary or transient database) has a single page cache which
** is an instance of this object.
** is an instance of this object.
**
**
** Pointers to structures of this type are cast and returned as
** Pointers to structures of this type are cast and returned as
** opaque sqlite3_pcache* handles.
** opaque sqlite3_pcache* handles.
*/
*/
struct
PCache1
{
struct
PCache1
{
/* Cache configuration parameters. Page size (szPage) and the purgeable
/* Cache configuration parameters. Page size (szPage) and the purgeable
** flag (bPurgeable) and the pnPurgeable pointer are all set when the
** flag (bPurgeable) and the pnPurgeable pointer are all set when the
** cache is created and are never changed thereafter. nMax may be
** cache is created and are never changed thereafter. nMax may be
** modified at any time by a call to the pcache1Cachesize() method.
** modified at any time by a call to the pcache1Cachesize() method.
** The PGroup mutex must be held when accessing nMax.
** The PGroup mutex must be held when accessing nMax.
*/
*/
PGroup
*
pGroup
;
/* PGroup this cache belongs to */
PGroup
*
pGroup
;
/* PGroup this cache belongs to */
unsigned
int
*
pnPurgeable
;
/* Pointer to pGroup->nPurgeable */
unsigned
int
*
pnPurgeable
;
/* Pointer to pGroup->nPurgeable */
int
szPage
;
/* Size of database content section */
int
szPage
;
/* Size of database content section */
int
szExtra
;
/* sizeof(MemPage)+sizeof(PgHdr) */
int
szExtra
;
/* sizeof(MemPage)+sizeof(PgHdr) */
int
szAlloc
;
/* Total size of one pcache line */
int
szAlloc
;
/* Total size of one pcache line */
int
bPurgeable
;
/* True if cache is purgeable */
int
bPurgeable
;
/* True if cache is purgeable */
unsigned
int
nMin
;
/* Minimum number of pages reserved */
unsigned
int
nMin
;
/* Minimum number of pages reserved */
unsigned
int
nMax
;
/* Configured "cache_size" value */
unsigned
int
nMax
;
/* Configured "cache_size" value */
unsigned
int
n90pct
;
/* nMax*9/10 */
unsigned
int
n90pct
;
/* nMax*9/10 */
unsigned
int
iMaxKey
;
/* Largest key seen since xTruncate() */
unsigned
int
iMaxKey
;
/* Largest key seen since xTruncate() */
unsigned
int
nPurgeableDummy
;
/* pnPurgeable points here when not used*/
unsigned
int
nPurgeableDummy
;
/* pnPurgeable points here when not used*/
/* Hash table of all pages. The following variables may only be accessed
/* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the PGroup mutex.
** when the accessor is holding the PGroup mutex.
*/
*/
unsigned
int
nRecyclable
;
/* Number of pages in the LRU list */
unsigned
int
nRecyclable
;
/* Number of pages in the LRU list */
unsigned
int
nPage
;
/* Total number of pages in apHash */
unsigned
int
nPage
;
/* Total number of pages in apHash */
unsigned
int
nHash
;
/* Number of slots in apHash[] */
unsigned
int
nHash
;
/* Number of slots in apHash[] */
PgHdr1
**
apHash
;
/* Hash table for fast lookup by key */
PgHdr1
**
apHash
;
/* Hash table for fast lookup by key */
PgHdr1
*
pFree
;
/* List of unused pcache-local pages */
PgHdr1
*
pFree
;
/* List of unused pcache-local pages */
void
*
pBulk
;
/* Bulk memory used by pcache-local */
void
*
pBulk
;
/* Bulk memory used by pcache-local */
};
};
/*
/*
...
@@ -196,73 +196,56 @@ struct PCache1 {
...
@@ -196,73 +196,56 @@ struct PCache1 {
** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
*/
*/
struct
PgFreeslot
{
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
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
** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
** fixed at sqlite3_initialize() time and do not require mutex protection.
** fixed at sqlite3_initialize() time and do not require mutex protection.
** The nFreeSlot and pFree values do require mutex protection.
** The nFreeSlot and pFree values do require mutex protection.
*/
*/
int
isInit
;
/* True if initialized */
int
isInit
;
/* True if initialized */
int
separateCache
;
/* Use a new PGroup for each PCache */
int
separateCache
;
/* Use a new PGroup for each PCache */
int
nInitPage
;
/* Initial bulk allocation size */
int
nInitPage
;
/* Initial bulk allocation size */
int
szSlot
;
/* Size of each free slot */
int
szSlot
;
/* Size of each free slot */
int
nSlot
;
/* The number of pcache slots */
int
nSlot
;
/* The number of pcache slots */
int
nReserve
;
/* Try to keep nFreeSlot above this */
int
nReserve
;
/* Try to keep nFreeSlot above this */
void
*
pStart
,
*
pEnd
;
/* Bounds of global page cache memory */
void
*
pStart
,
*
pEnd
;
/* Bounds of global page cache memory */
/* Above requires no mutex. Use mutex below for variable that follow. */
/* Above requires no mutex. Use mutex below for variable that follow. */
sqlite3_mutex
*
mutex
;
/* Mutex for accessing the following: */
pthread_mutex_t
mutex
;
/* Mutex for accessing the following: */
PgFreeslot
*
pFree
;
/* Free page blocks */
PgFreeslot
*
pFree
;
/* Free page blocks */
int
nFreeSlot
;
/* Number of unused pcache slots */
int
nFreeSlot
;
/* Number of unused pcache slots */
/* The following value requires a mutex to change. We skip the mutex on
/* The following value requires a mutex to change. We skip the mutex on
** reading because (1) most platforms read a 32-bit integer atomically and
** reading because (1) most platforms read a 32-bit integer atomically and
** (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
;
}
pcache1
;
/*
/*
** Macros to enter and leave the PCache LRU mutex.
** Macros to enter and leave the PCache LRU mutex.
*/
*/
#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE
==
0
#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE
==
0
#
define pcache1EnterMutex(X) assert((X)->mutex==
0)
#
define pcache1EnterMutex(X) assert((X)->mutex ==
0)
#
define pcache1LeaveMutex(X) assert((X)->mutex==
0)
#
define pcache1LeaveMutex(X) assert((X)->mutex ==
0)
#
define PCACHE1_MIGHT_USE_GROUP_MUTEX 0
#define PCACHE1_MIGHT_USE_GROUP_MUTEX 0
#else
#else
#
define pcache1EnterMutex(X)
sqlite3_mutex_enter((X)->mutex)
#
define pcache1EnterMutex(X)
sqlite3_mutex_enter((X)->mutex)
#
define pcache1LeaveMutex(X)
sqlite3_mutex_leave((X)->mutex)
#
define pcache1LeaveMutex(X)
sqlite3_mutex_leave((X)->mutex)
#
define PCACHE1_MIGHT_USE_GROUP_MUTEX 1
#define PCACHE1_MIGHT_USE_GROUP_MUTEX 1
#endif
#endif
/******************************************************************************/
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
/*
/*
** This function is called during initialization if a static buffer is
** This function is called during initialization if a static buffer is
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
** enough to contain 'n' buffers of 'sz' bytes each.
** enough to contain 'n' buffers of 'sz' bytes each.
...
@@ -270,23 +253,23 @@ static struct PCacheGlobal {
...
@@ -270,23 +253,23 @@ static struct PCacheGlobal {
** This routine is called from sqlite3_initialize() and so it is guaranteed
** This routine is called from sqlite3_initialize() and so it is guaranteed
** to be serialized already. There is no need for further mutexing.
** to be serialized already. There is no need for further mutexing.
*/
*/
void
sqlite3PCacheBufferSetup
(
void
*
pBuf
,
int
sz
,
int
n
){
void
sqlite3PCacheBufferSetup
(
void
*
pBuf
,
int
sz
,
int
n
)
{
if
(
pcache1
.
isInit
)
{
if
(
pcache1
.
isInit
)
{
PgFreeslot
*
p
;
PgFreeslot
*
p
;
if
(
pBuf
==
0
)
sz
=
n
=
0
;
if
(
pBuf
==
0
)
sz
=
n
=
0
;
if
(
n
==
0
)
sz
=
0
;
if
(
n
==
0
)
sz
=
0
;
sz
=
ROUNDDOWN8
(
sz
);
sz
=
ROUNDDOWN8
(
sz
);
pcache1
.
szSlot
=
sz
;
pcache1
.
szSlot
=
sz
;
pcache1
.
nSlot
=
pcache1
.
nFreeSlot
=
n
;
pcache1
.
nSlot
=
pcache1
.
nFreeSlot
=
n
;
pcache1
.
nReserve
=
n
>
90
?
10
:
(
n
/
10
+
1
);
pcache1
.
nReserve
=
n
>
90
?
10
:
(
n
/
10
+
1
);
pcache1
.
pStart
=
pBuf
;
pcache1
.
pStart
=
pBuf
;
pcache1
.
pFree
=
0
;
pcache1
.
pFree
=
0
;
pcache1
.
bUnderPressure
=
0
;
pcache1
.
bUnderPressure
=
0
;
while
(
n
--
)
{
while
(
n
--
)
{
p
=
(
PgFreeslot
*
)
pBuf
;
p
=
(
PgFreeslot
*
)
pBuf
;
p
->
pNext
=
pcache1
.
pFree
;
p
->
pNext
=
pcache1
.
pFree
;
pcache1
.
pFree
=
p
;
pcache1
.
pFree
=
p
;
pBuf
=
(
void
*
)
&
((
char
*
)
pBuf
)[
sz
];
pBuf
=
(
void
*
)
&
((
char
*
)
pBuf
)[
sz
];
}
}
pcache1
.
pEnd
=
pBuf
;
pcache1
.
pEnd
=
pBuf
;
}
}
...
@@ -296,72 +279,72 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
...
@@ -296,72 +279,72 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
** Try to initialize the pCache->pFree and pCache->pBulk fields. Return
** Try to initialize the pCache->pFree and pCache->pBulk fields. Return
** true if pCache->pFree ends up containing one or more free pages.
** true if pCache->pFree ends up containing one or more free pages.
*/
*/
static
int
pcache1InitBulk
(
PCache1
*
pCache
){
static
int
pcache1InitBulk
(
PCache1
*
pCache
)
{
i64
szBulk
;
i64
szBulk
;
char
*
zBulk
;
char
*
zBulk
;
if
(
pcache1
.
nInitPage
==
0
)
return
0
;
if
(
pcache1
.
nInitPage
==
0
)
return
0
;
/* Do not bother with a bulk allocation if the cache size very small */
/* Do not bother with a bulk allocation if the cache size very small */
if
(
pCache
->
nMax
<
3
)
return
0
;
if
(
pCache
->
nMax
<
3
)
return
0
;
sqlite3BeginBenignMalloc
();
sqlite3BeginBenignMalloc
();
if
(
pcache1
.
nInitPage
>
0
)
{
if
(
pcache1
.
nInitPage
>
0
)
{
szBulk
=
pCache
->
szAlloc
*
(
i64
)
pcache1
.
nInitPage
;
szBulk
=
pCache
->
szAlloc
*
(
i64
)
pcache1
.
nInitPage
;
}
else
{
}
else
{
szBulk
=
-
1024
*
(
i64
)
pcache1
.
nInitPage
;
szBulk
=
-
1024
*
(
i64
)
pcache1
.
nInitPage
;
}
}
if
(
szBulk
>
pCache
->
szAlloc
*
(
i64
)
pCache
->
nMax
)
{
if
(
szBulk
>
pCache
->
szAlloc
*
(
i64
)
pCache
->
nMax
)
{
szBulk
=
pCache
->
szAlloc
*
(
i64
)
pCache
->
nMax
;
szBulk
=
pCache
->
szAlloc
*
(
i64
)
pCache
->
nMax
;
}
}
zBulk
=
pCache
->
pBulk
=
sqlite3Malloc
(
szBulk
);
zBulk
=
pCache
->
pBulk
=
sqlite3Malloc
(
szBulk
);
sqlite3EndBenignMalloc
();
sqlite3EndBenignMalloc
();
if
(
zBulk
)
{
if
(
zBulk
)
{
int
nBulk
=
sqlite3MallocSize
(
zBulk
)
/
pCache
->
szAlloc
;
int
nBulk
=
sqlite3MallocSize
(
zBulk
)
/
pCache
->
szAlloc
;
do
{
do
{
PgHdr1
*
pX
=
(
PgHdr1
*
)
&
zBulk
[
pCache
->
szPage
];
PgHdr1
*
pX
=
(
PgHdr1
*
)
&
zBulk
[
pCache
->
szPage
];
pX
->
page
.
pBuf
=
zBulk
;
pX
->
page
.
pBuf
=
zBulk
;
pX
->
page
.
pExtra
=
&
pX
[
1
];
pX
->
page
.
pExtra
=
&
pX
[
1
];
pX
->
isBulkLocal
=
1
;
pX
->
isBulkLocal
=
1
;
pX
->
isAnchor
=
0
;
pX
->
isAnchor
=
0
;
pX
->
pNext
=
pCache
->
pFree
;
pX
->
pNext
=
pCache
->
pFree
;
pX
->
pLruPrev
=
0
;
/* Initializing this saves a valgrind error */
pX
->
pLruPrev
=
0
;
/* Initializing this saves a valgrind error */
pCache
->
pFree
=
pX
;
pCache
->
pFree
=
pX
;
zBulk
+=
pCache
->
szAlloc
;
zBulk
+=
pCache
->
szAlloc
;
}
while
(
--
nBulk
);
}
while
(
--
nBulk
);
}
}
return
pCache
->
pFree
!=
0
;
return
pCache
->
pFree
!=
0
;
}
}
/*
/*
** Malloc function used within this file to allocate space from the buffer
** Malloc function used within this file to allocate space from the buffer
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
** such buffer exists or there is no space left in it, this function falls
** such buffer exists or there is no space left in it, this function falls
** back to sqlite3Malloc().
** back to sqlite3Malloc().
**
**
** Multiple threads can run this routine at the same time. Global variables
** Multiple threads can run this routine at the same time. Global variables
** in pcache1 need to be protected via mutex.
** in pcache1 need to be protected via mutex.
*/
*/
static
void
*
pcache1Alloc
(
int
nByte
){
static
void
*
pcache1Alloc
(
int
nByte
)
{
void
*
p
=
0
;
void
*
p
=
0
;
assert
(
sqlite3_mutex_notheld
(
pcache1
.
grp
.
mutex
)
);
assert
(
sqlite3_mutex_notheld
(
pcache1
.
grp
.
mutex
)
);
if
(
nByte
<=
pcache1
.
szSlot
)
{
if
(
nByte
<=
pcache1
.
szSlot
)
{
sqlite3_mutex_enter
(
pcache1
.
mutex
);
sqlite3_mutex_enter
(
pcache1
.
mutex
);
p
=
(
PgHdr1
*
)
pcache1
.
pFree
;
p
=
(
PgHdr1
*
)
pcache1
.
pFree
;
if
(
p
)
{
if
(
p
)
{
pcache1
.
pFree
=
pcache1
.
pFree
->
pNext
;
pcache1
.
pFree
=
pcache1
.
pFree
->
pNext
;
pcache1
.
nFreeSlot
--
;
pcache1
.
nFreeSlot
--
;
pcache1
.
bUnderPressure
=
pcache1
.
nFreeSlot
<
pcache1
.
nReserve
;
pcache1
.
bUnderPressure
=
pcache1
.
nFreeSlot
<
pcache1
.
nReserve
;
assert
(
pcache1
.
nFreeSlot
>=
0
);
assert
(
pcache1
.
nFreeSlot
>=
0
);
sqlite3StatusHighwater
(
SQLITE_STATUS_PAGECACHE_SIZE
,
nByte
);
sqlite3StatusHighwater
(
SQLITE_STATUS_PAGECACHE_SIZE
,
nByte
);
sqlite3StatusUp
(
SQLITE_STATUS_PAGECACHE_USED
,
1
);
sqlite3StatusUp
(
SQLITE_STATUS_PAGECACHE_USED
,
1
);
}
}
sqlite3_mutex_leave
(
pcache1
.
mutex
);
sqlite3_mutex_leave
(
pcache1
.
mutex
);
}
}
if
(
p
==
0
)
{
if
(
p
==
0
)
{
/* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
/* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
** it from sqlite3Malloc instead.
** it from sqlite3Malloc instead.
*/
*/
p
=
sqlite3Malloc
(
nByte
);
p
=
sqlite3Malloc
(
nByte
);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
if
(
p
)
{
if
(
p
)
{
int
sz
=
sqlite3MallocSize
(
p
);
int
sz
=
sqlite3MallocSize
(
p
);
sqlite3_mutex_enter
(
pcache1
.
mutex
);
sqlite3_mutex_enter
(
pcache1
.
mutex
);
sqlite3StatusHighwater
(
SQLITE_STATUS_PAGECACHE_SIZE
,
nByte
);
sqlite3StatusHighwater
(
SQLITE_STATUS_PAGECACHE_SIZE
,
nByte
);
...
@@ -377,21 +360,21 @@ static void *pcache1Alloc(int nByte){
...
@@ -377,21 +360,21 @@ static void *pcache1Alloc(int nByte){
/*
/*
** Free an allocated buffer obtained from pcache1Alloc().
** Free an allocated buffer obtained from pcache1Alloc().
*/
*/
static
void
pcache1Free
(
void
*
p
){
static
void
pcache1Free
(
void
*
p
)
{
if
(
p
==
0
)
return
;
if
(
p
==
0
)
return
;
if
(
SQLITE_WITHIN
(
p
,
pcache1
.
pStart
,
pcache1
.
pEnd
)
)
{
if
(
SQLITE_WITHIN
(
p
,
pcache1
.
pStart
,
pcache1
.
pEnd
))
{
PgFreeslot
*
pSlot
;
PgFreeslot
*
pSlot
;
sqlite3_mutex_enter
(
pcache1
.
mutex
);
sqlite3_mutex_enter
(
pcache1
.
mutex
);
sqlite3StatusDown
(
SQLITE_STATUS_PAGECACHE_USED
,
1
);
sqlite3StatusDown
(
SQLITE_STATUS_PAGECACHE_USED
,
1
);
pSlot
=
(
PgFreeslot
*
)
p
;
pSlot
=
(
PgFreeslot
*
)
p
;
pSlot
->
pNext
=
pcache1
.
pFree
;
pSlot
->
pNext
=
pcache1
.
pFree
;
pcache1
.
pFree
=
pSlot
;
pcache1
.
pFree
=
pSlot
;
pcache1
.
nFreeSlot
++
;
pcache1
.
nFreeSlot
++
;
pcache1
.
bUnderPressure
=
pcache1
.
nFreeSlot
<
pcache1
.
nReserve
;
pcache1
.
bUnderPressure
=
pcache1
.
nFreeSlot
<
pcache1
.
nReserve
;
assert
(
pcache1
.
nFreeSlot
<=
pcache1
.
nSlot
);
assert
(
pcache1
.
nFreeSlot
<=
pcache1
.
nSlot
);
sqlite3_mutex_leave
(
pcache1
.
mutex
);
sqlite3_mutex_leave
(
pcache1
.
mutex
);
}
else
{
}
else
{
assert
(
sqlite3MemdebugHasType
(
p
,
MEMTYPE_PCACHE
)
);
assert
(
sqlite3MemdebugHasType
(
p
,
MEMTYPE_PCACHE
)
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_HEAP
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_HEAP
);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
{
{
...
@@ -410,12 +393,12 @@ static void pcache1Free(void *p){
...
@@ -410,12 +393,12 @@ static void pcache1Free(void *p){
/*
/*
** Return the size of a pcache allocation
** Return the size of a pcache allocation
*/
*/
static
int
pcache1MemSize
(
void
*
p
){
static
int
pcache1MemSize
(
void
*
p
)
{
if
(
p
>=
pcache1
.
pStart
&&
p
<
pcache1
.
pEnd
)
{
if
(
p
>=
pcache1
.
pStart
&&
p
<
pcache1
.
pEnd
)
{
return
pcache1
.
szSlot
;
return
pcache1
.
szSlot
;
}
else
{
}
else
{
int
iSize
;
int
iSize
;
assert
(
sqlite3MemdebugHasType
(
p
,
MEMTYPE_PCACHE
)
);
assert
(
sqlite3MemdebugHasType
(
p
,
MEMTYPE_PCACHE
)
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_HEAP
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_HEAP
);
iSize
=
sqlite3MallocSize
(
p
);
iSize
=
sqlite3MallocSize
(
p
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_PCACHE
);
sqlite3MemdebugSetType
(
p
,
MEMTYPE_PCACHE
);
...
@@ -427,30 +410,32 @@ static int pcache1MemSize(void *p){
...
@@ -427,30 +410,32 @@ static int pcache1MemSize(void *p){
/*
/*
** Allocate a new page object initially associated with cache pCache.
** Allocate a new page object initially associated with cache pCache.
*/
*/
static
PgHdr1
*
pcache1AllocPage
(
PCache1
*
pCache
,
int
benignMalloc
){
static
PgHdr1
*
pcache1AllocPage
(
PCache1
*
pCache
,
int
benignMalloc
)
{
PgHdr1
*
p
=
0
;
PgHdr1
*
p
=
0
;
void
*
pPg
;
void
*
pPg
;
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
if
(
pCache
->
pFree
||
(
pCache
->
nPage
==
0
&&
pcache1InitBulk
(
pCache
))
)
{
if
(
pCache
->
pFree
||
(
pCache
->
nPage
==
0
&&
pcache1InitBulk
(
pCache
)))
{
assert
(
pCache
->
pFree
!=
0
);
assert
(
pCache
->
pFree
!=
0
);
p
=
pCache
->
pFree
;
p
=
pCache
->
pFree
;
pCache
->
pFree
=
p
->
pNext
;
pCache
->
pFree
=
p
->
pNext
;
p
->
pNext
=
0
;
p
->
pNext
=
0
;
}
else
{
}
else
{
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* The group mutex must be released before pcache1Alloc() is called. This
/* The group mutex must be released before pcache1Alloc() is called. This
** is because it might call sqlite3_release_memory(), which assumes that
** is because it might call sqlite3_release_memory(), which assumes that
** this mutex is not held. */
** this mutex is not held. */
assert
(
pcache1
.
separateCache
==
0
);
assert
(
pcache1
.
separateCache
==
0
);
assert
(
pCache
->
pGroup
==&
pcache1
.
grp
);
assert
(
pCache
->
pGroup
==
&
pcache1
.
grp
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
#endif
#endif
if
(
benignMalloc
){
sqlite3BeginBenignMalloc
();
}
if
(
benignMalloc
)
{
sqlite3BeginBenignMalloc
();
}
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
pPg
=
pcache1Alloc
(
pCache
->
szPage
);
pPg
=
pcache1Alloc
(
pCache
->
szPage
);
p
=
sqlite3Malloc
(
sizeof
(
PgHdr1
)
+
pCache
->
szExtra
);
p
=
sqlite3Malloc
(
sizeof
(
PgHdr1
)
+
pCache
->
szExtra
);
if
(
!
pPg
||
!
p
)
{
if
(
!
pPg
||
!
p
)
{
pcache1Free
(
pPg
);
pcache1Free
(
pPg
);
sqlite3_free
(
p
);
sqlite3_free
(
p
);
pPg
=
0
;
pPg
=
0
;
...
@@ -458,11 +443,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
...
@@ -458,11 +443,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
#else
#else
pPg
=
pcache1Alloc
(
pCache
->
szAlloc
);
pPg
=
pcache1Alloc
(
pCache
->
szAlloc
);
#endif
#endif
if
(
benignMalloc
){
sqlite3EndBenignMalloc
();
}
if
(
benignMalloc
)
{
sqlite3EndBenignMalloc
();
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex
(
pCache
->
pGroup
);
pcache1EnterMutex
(
pCache
->
pGroup
);
#endif
#endif
if
(
pPg
==
0
)
return
0
;
if
(
pPg
==
0
)
return
0
;
#ifndef SQLITE_PCACHE_SEPARATE_HEADER
#ifndef SQLITE_PCACHE_SEPARATE_HEADER
p
=
(
PgHdr1
*
)
&
((
u8
*
)
pPg
)[
pCache
->
szPage
];
p
=
(
PgHdr1
*
)
&
((
u8
*
)
pPg
)[
pCache
->
szPage
];
#endif
#endif
...
@@ -470,7 +457,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
...
@@ -470,7 +457,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
p
->
page
.
pExtra
=
&
p
[
1
];
p
->
page
.
pExtra
=
&
p
[
1
];
p
->
isBulkLocal
=
0
;
p
->
isBulkLocal
=
0
;
p
->
isAnchor
=
0
;
p
->
isAnchor
=
0
;
p
->
pLruPrev
=
0
;
/* Initializing this saves a valgrind error */
p
->
pLruPrev
=
0
;
/* Initializing this saves a valgrind error */
}
}
(
*
pCache
->
pnPurgeable
)
++
;
(
*
pCache
->
pnPurgeable
)
++
;
return
p
;
return
p
;
...
@@ -479,15 +466,15 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
...
@@ -479,15 +466,15 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
/*
/*
** Free a page object allocated by pcache1AllocPage().
** Free a page object allocated by pcache1AllocPage().
*/
*/
static
void
pcache1FreePage
(
PgHdr1
*
p
){
static
void
pcache1FreePage
(
PgHdr1
*
p
)
{
PCache1
*
pCache
;
PCache1
*
pCache
;
assert
(
p
!=
0
);
assert
(
p
!=
0
);
pCache
=
p
->
pCache
;
pCache
=
p
->
pCache
;
assert
(
sqlite3_mutex_held
(
p
->
pCache
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
p
->
pCache
->
pGroup
->
mutex
)
);
if
(
p
->
isBulkLocal
)
{
if
(
p
->
isBulkLocal
)
{
p
->
pNext
=
pCache
->
pFree
;
p
->
pNext
=
pCache
->
pFree
;
pCache
->
pFree
=
p
;
pCache
->
pFree
=
p
;
}
else
{
}
else
{
pcache1Free
(
p
->
page
.
pBuf
);
pcache1Free
(
p
->
page
.
pBuf
);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
sqlite3_free
(
p
);
sqlite3_free
(
p
);
...
@@ -501,18 +488,15 @@ static void pcache1FreePage(PgHdr1 *p){
...
@@ -501,18 +488,15 @@ static void pcache1FreePage(PgHdr1 *p){
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
** exists, this function falls back to sqlite3Malloc().
** exists, this function falls back to sqlite3Malloc().
*/
*/
void
*
sqlite3PageMalloc
(
int
sz
){
void
*
sqlite3PageMalloc
(
int
sz
)
{
assert
(
sz
<=
65536
+
8
);
/* These allocations are never very large */
assert
(
sz
<=
65536
+
8
);
/* These allocations are never very large */
return
pcache1Alloc
(
sz
);
return
pcache1Alloc
(
sz
);
}
}
/*
/*
** Free an allocated buffer obtained from sqlite3PageMalloc().
** Free an allocated buffer obtained from sqlite3PageMalloc().
*/
*/
void
sqlite3PageFree
(
void
*
p
){
void
sqlite3PageFree
(
void
*
p
)
{
pcache1Free
(
p
);
}
pcache1Free
(
p
);
}
/*
/*
** Return true if it desirable to avoid allocating a new page cache
** Return true if it desirable to avoid allocating a new page cache
...
@@ -530,10 +514,10 @@ void sqlite3PageFree(void *p){
...
@@ -530,10 +514,10 @@ void sqlite3PageFree(void *p){
** allocating a new page cache entry in order to avoid stressing
** allocating a new page cache entry in order to avoid stressing
** the heap even further.
** the heap even further.
*/
*/
static
int
pcache1UnderMemoryPressure
(
PCache1
*
pCache
){
static
int
pcache1UnderMemoryPressure
(
PCache1
*
pCache
)
{
if
(
pcache1
.
nSlot
&&
(
pCache
->
szPage
+
pCache
->
szExtra
)
<=
pcache1
.
szSlot
)
{
if
(
pcache1
.
nSlot
&&
(
pCache
->
szPage
+
pCache
->
szExtra
)
<=
pcache1
.
szSlot
)
{
return
pcache1
.
bUnderPressure
;
return
pcache1
.
bUnderPressure
;
}
else
{
}
else
{
return
sqlite3HeapNearlyFull
();
return
sqlite3HeapNearlyFull
();
}
}
}
}
...
@@ -547,28 +531,32 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
...
@@ -547,28 +531,32 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){
**
**
** The PCache mutex must be held when this function is called.
** The PCache mutex must be held when this function is called.
*/
*/
static
void
pcache1ResizeHash
(
PCache1
*
p
){
static
void
pcache1ResizeHash
(
PCache1
*
p
)
{
PgHdr1
**
apNew
;
PgHdr1
**
apNew
;
unsigned
int
nNew
;
unsigned
int
nNew
;
unsigned
int
i
;
unsigned
int
i
;
assert
(
sqlite3_mutex_held
(
p
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
p
->
pGroup
->
mutex
)
);
nNew
=
p
->
nHash
*
2
;
nNew
=
p
->
nHash
*
2
;
if
(
nNew
<
256
)
{
if
(
nNew
<
256
)
{
nNew
=
256
;
nNew
=
256
;
}
}
pcache1LeaveMutex
(
p
->
pGroup
);
pcache1LeaveMutex
(
p
->
pGroup
);
if
(
p
->
nHash
){
sqlite3BeginBenignMalloc
();
}
if
(
p
->
nHash
)
{
apNew
=
(
PgHdr1
**
)
sqlite3MallocZero
(
sizeof
(
PgHdr1
*
)
*
nNew
);
sqlite3BeginBenignMalloc
();
if
(
p
->
nHash
){
sqlite3EndBenignMalloc
();
}
}
apNew
=
(
PgHdr1
**
)
sqlite3MallocZero
(
sizeof
(
PgHdr1
*
)
*
nNew
);
if
(
p
->
nHash
)
{
sqlite3EndBenignMalloc
();
}
pcache1EnterMutex
(
p
->
pGroup
);
pcache1EnterMutex
(
p
->
pGroup
);
if
(
apNew
)
{
if
(
apNew
)
{
for
(
i
=
0
;
i
<
p
->
nHash
;
i
++
)
{
for
(
i
=
0
;
i
<
p
->
nHash
;
i
++
)
{
PgHdr1
*
pPage
;
PgHdr1
*
pPage
;
PgHdr1
*
pNext
=
p
->
apHash
[
i
];
PgHdr1
*
pNext
=
p
->
apHash
[
i
];
while
(
(
pPage
=
pNext
)
!=
0
)
{
while
((
pPage
=
pNext
)
!=
0
)
{
unsigned
int
h
=
pPage
->
iKey
%
nNew
;
unsigned
int
h
=
pPage
->
iKey
%
nNew
;
pNext
=
pPage
->
pNext
;
pNext
=
pPage
->
pNext
;
pPage
->
pNext
=
apNew
[
h
];
pPage
->
pNext
=
apNew
[
h
];
...
@@ -582,123 +570,120 @@ static void pcache1ResizeHash(PCache1 *p){
...
@@ -582,123 +570,120 @@ static void pcache1ResizeHash(PCache1 *p){
}
}
/*
/*
** This function is used internally to remove the page pPage from the
** This function is used internally to remove the page pPage from the
** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
** LRU list, then this function is a no-op.
** LRU list, then this function is a no-op.
**
**
** The PGroup mutex must be held when this function is called.
** The PGroup mutex must be held when this function is called.
*/
*/
static
PgHdr1
*
pcache1PinPage
(
PgHdr1
*
pPage
){
static
PgHdr1
*
pcache1PinPage
(
PgHdr1
*
pPage
)
{
assert
(
pPage
!=
0
);
assert
(
pPage
!=
0
);
assert
(
PAGE_IS_UNPINNED
(
pPage
)
);
assert
(
PAGE_IS_UNPINNED
(
pPage
)
);
assert
(
pPage
->
pLruNext
);
assert
(
pPage
->
pLruNext
);
assert
(
pPage
->
pLruPrev
);
assert
(
pPage
->
pLruPrev
);
assert
(
sqlite3_mutex_held
(
pPage
->
pCache
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
pPage
->
pCache
->
pGroup
->
mutex
)
);
pPage
->
pLruPrev
->
pLruNext
=
pPage
->
pLruNext
;
pPage
->
pLruPrev
->
pLruNext
=
pPage
->
pLruNext
;
pPage
->
pLruNext
->
pLruPrev
=
pPage
->
pLruPrev
;
pPage
->
pLruNext
->
pLruPrev
=
pPage
->
pLruPrev
;
pPage
->
pLruNext
=
0
;
pPage
->
pLruNext
=
0
;
/* pPage->pLruPrev = 0;
/* pPage->pLruPrev = 0;
** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */
** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */
assert
(
pPage
->
isAnchor
==
0
);
assert
(
pPage
->
isAnchor
==
0
);
assert
(
pPage
->
pCache
->
pGroup
->
lru
.
isAnchor
==
1
);
assert
(
pPage
->
pCache
->
pGroup
->
lru
.
isAnchor
==
1
);
pPage
->
pCache
->
nRecyclable
--
;
pPage
->
pCache
->
nRecyclable
--
;
return
pPage
;
return
pPage
;
}
}
/*
/*
** Remove the page supplied as an argument from the hash table
** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
** (PCache1.apHash structure) that it is currently stored in.
** Also free the page if freePage is true.
** Also free the page if freePage is true.
**
**
** The PGroup mutex must be held when this function is called.
** The PGroup mutex must be held when this function is called.
*/
*/
static
void
pcache1RemoveFromHash
(
PgHdr1
*
pPage
,
int
freeFlag
){
static
void
pcache1RemoveFromHash
(
PgHdr1
*
pPage
,
int
freeFlag
)
{
unsigned
int
h
;
unsigned
int
h
;
PCache1
*
pCache
=
pPage
->
pCache
;
PCache1
*
pCache
=
pPage
->
pCache
;
PgHdr1
**
pp
;
PgHdr1
**
pp
;
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
h
=
pPage
->
iKey
%
pCache
->
nHash
;
h
=
pPage
->
iKey
%
pCache
->
nHash
;
for
(
pp
=&
pCache
->
apHash
[
h
];
(
*
pp
)
!=
pPage
;
pp
=&
(
*
pp
)
->
pNext
);
for
(
pp
=
&
pCache
->
apHash
[
h
];
(
*
pp
)
!=
pPage
;
pp
=
&
(
*
pp
)
->
pNext
)
;
*
pp
=
(
*
pp
)
->
pNext
;
*
pp
=
(
*
pp
)
->
pNext
;
pCache
->
nPage
--
;
pCache
->
nPage
--
;
if
(
freeFlag
)
pcache1FreePage
(
pPage
);
if
(
freeFlag
)
pcache1FreePage
(
pPage
);
}
}
/*
/*
** If there are currently more than nMaxPage pages allocated, try
** If there are currently more than nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to nMaxPage.
** to recycle pages to reduce the number allocated to nMaxPage.
*/
*/
static
void
pcache1EnforceMaxPage
(
PCache1
*
pCache
){
static
void
pcache1EnforceMaxPage
(
PCache1
*
pCache
)
{
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
PgHdr1
*
p
;
PgHdr1
*
p
;
assert
(
sqlite3_mutex_held
(
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
pGroup
->
mutex
));
while
(
pGroup
->
nPurgeable
>
pGroup
->
nMaxPage
while
(
pGroup
->
nPurgeable
>
pGroup
->
nMaxPage
&&
(
p
=
pGroup
->
lru
.
pLruPrev
)
->
isAnchor
==
0
)
{
&&
(
p
=
pGroup
->
lru
.
pLruPrev
)
->
isAnchor
==
0
assert
(
p
->
pCache
->
pGroup
==
pGroup
);
){
assert
(
PAGE_IS_UNPINNED
(
p
));
assert
(
p
->
pCache
->
pGroup
==
pGroup
);
assert
(
PAGE_IS_UNPINNED
(
p
)
);
pcache1PinPage
(
p
);
pcache1PinPage
(
p
);
pcache1RemoveFromHash
(
p
,
1
);
pcache1RemoveFromHash
(
p
,
1
);
}
}
if
(
pCache
->
nPage
==
0
&&
pCache
->
pBulk
)
{
if
(
pCache
->
nPage
==
0
&&
pCache
->
pBulk
)
{
sqlite3_free
(
pCache
->
pBulk
);
sqlite3_free
(
pCache
->
pBulk
);
pCache
->
pBulk
=
pCache
->
pFree
=
0
;
pCache
->
pBulk
=
pCache
->
pFree
=
0
;
}
}
}
}
/*
/*
** Discard all pages from cache pCache with a page number (key value)
** Discard all pages from cache pCache with a page number (key value)
** greater than or equal to iLimit. Any pinned pages that meet this
** greater than or equal to iLimit. Any pinned pages that meet this
** criteria are unpinned before they are discarded.
** criteria are unpinned before they are discarded.
**
**
** The PCache mutex must be held when this function is called.
** The PCache mutex must be held when this function is called.
*/
*/
static
void
pcache1TruncateUnsafe
(
static
void
pcache1TruncateUnsafe
(
PCache1
*
pCache
,
/* The cache to truncate */
PCache1
*
pCache
,
/* The cache to truncate */
unsigned
int
iLimit
/* Drop pages with this pgno or larger */
unsigned
int
iLimit
/* Drop pages with this pgno or larger */
)
{
){
TESTONLY
(
int
nPage
=
0
;)
/* To assert pCache->nPage is correct */
TESTONLY
(
int
nPage
=
0
;
)
/* To assert pCache->nPage is correct */
unsigned
int
h
,
iStop
;
unsigned
int
h
,
iStop
;
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
assert
(
sqlite3_mutex_held
(
pCache
->
pGroup
->
mutex
)
);
assert
(
pCache
->
iMaxKey
>=
iLimit
);
assert
(
pCache
->
iMaxKey
>=
iLimit
);
assert
(
pCache
->
nHash
>
0
);
assert
(
pCache
->
nHash
>
0
);
if
(
pCache
->
iMaxKey
-
iLimit
<
pCache
->
nHash
)
{
if
(
pCache
->
iMaxKey
-
iLimit
<
pCache
->
nHash
)
{
/* If we are just shaving the last few pages off the end of the
/* If we are just shaving the last few pages off the end of the
** cache, then there is no point in scanning the entire hash table.
** cache, then there is no point in scanning the entire hash table.
** Only scan those hash slots that might contain pages that need to
** Only scan those hash slots that might contain pages that need to
** be removed. */
** be removed. */
h
=
iLimit
%
pCache
->
nHash
;
h
=
iLimit
%
pCache
->
nHash
;
iStop
=
pCache
->
iMaxKey
%
pCache
->
nHash
;
iStop
=
pCache
->
iMaxKey
%
pCache
->
nHash
;
TESTONLY
(
nPage
=
-
10
;
)
/* Disable the pCache->nPage validity check */
TESTONLY
(
nPage
=
-
10
;)
/* Disable the pCache->nPage validity check */
}
else
{
}
else
{
/* This is the general case where many pages are being removed.
/* This is the general case where many pages are being removed.
** It is necessary to scan the entire hash table */
** It is necessary to scan the entire hash table */
h
=
pCache
->
nHash
/
2
;
h
=
pCache
->
nHash
/
2
;
iStop
=
h
-
1
;
iStop
=
h
-
1
;
}
}
for
(;;)
{
for
(;;)
{
PgHdr1
**
pp
;
PgHdr1
**
pp
;
PgHdr1
*
pPage
;
PgHdr1
*
pPage
;
assert
(
h
<
pCache
->
nHash
);
assert
(
h
<
pCache
->
nHash
);
pp
=
&
pCache
->
apHash
[
h
];
pp
=
&
pCache
->
apHash
[
h
];
while
(
(
pPage
=
*
pp
)
!=
0
)
{
while
((
pPage
=
*
pp
)
!=
0
)
{
if
(
pPage
->
iKey
>=
iLimit
)
{
if
(
pPage
->
iKey
>=
iLimit
)
{
pCache
->
nPage
--
;
pCache
->
nPage
--
;
*
pp
=
pPage
->
pNext
;
*
pp
=
pPage
->
pNext
;
if
(
PAGE_IS_UNPINNED
(
pPage
)
)
pcache1PinPage
(
pPage
);
if
(
PAGE_IS_UNPINNED
(
pPage
)
)
pcache1PinPage
(
pPage
);
pcache1FreePage
(
pPage
);
pcache1FreePage
(
pPage
);
}
else
{
}
else
{
pp
=
&
pPage
->
pNext
;
pp
=
&
pPage
->
pNext
;
TESTONLY
(
if
(
nPage
>=
0
)
nPage
++
;
)
TESTONLY
(
if
(
nPage
>=
0
)
nPage
++
;
)
}
}
}
}
if
(
h
==
iStop
)
break
;
if
(
h
==
iStop
)
break
;
h
=
(
h
+
1
)
%
pCache
->
nHash
;
h
=
(
h
+
1
)
%
pCache
->
nHash
;
}
}
assert
(
nPage
<
0
||
pCache
->
nPage
==
(
unsigned
)
nPage
);
assert
(
nPage
<
0
||
pCache
->
nPage
==
(
unsigned
)
nPage
);
}
}
/******************************************************************************/
/******************************************************************************/
...
@@ -707,62 +692,54 @@ static void pcache1TruncateUnsafe(
...
@@ -707,62 +692,54 @@ static void pcache1TruncateUnsafe(
/*
/*
** Implementation of the sqlite3_pcache.xInit method.
** Implementation of the sqlite3_pcache.xInit method.
*/
*/
static
int
pcache1Init
(
void
*
NotUsed
){
static
int
pcache1Init
(
void
*
NotUsed
)
{
UNUSED_PARAMETER
(
NotUsed
);
assert
(
pcache1
.
isInit
==
0
);
assert
(
pcache1
.
isInit
==
0
);
memset
(
&
pcache1
,
0
,
sizeof
(
pcache1
));
memset
(
&
pcache1
,
0
,
sizeof
(
pcache1
));
// /*
/*
// ** The pcache1.separateCache variable is true if each PCache has its own
** The pcache1.separateCache variable is true if each PCache has its own
// ** private PGroup (mode-1). pcache1.separateCache is false if the single
** private PGroup (mode-1). pcache1.separateCache is false if the single
// ** PGroup in pcache1.grp is used for all page caches (mode-2).
** PGroup in pcache1.grp is used for all page caches (mode-2).
// **
**
// ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
// **
**
// ** * Use a unified cache in single-threaded applications that have
** * Use a unified cache in single-threaded applications that have
// ** configured a start-time buffer for use as page-cache memory using
** configured a start-time buffer for use as page-cache memory using
// ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
// ** pBuf argument.
** pBuf argument.
// **
**
// ** * Otherwise use separate caches (mode-1)
** * Otherwise use separate caches (mode-1)
// */
*/
// #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
// pcache1.separateCache = 0;
pcache1
.
separateCache
=
0
;
// #elif SQLITE_THREADSAFE
#elif SQLITE_THREADSAFE
// pcache1.separateCache = sqlite3GlobalConfig.pPage==0
pcache1
.
separateCache
=
sqlite3GlobalConfig
.
pPage
==
0
// || sqlite3GlobalConfig.bCoreMutex>0;
||
sqlite3GlobalConfig
.
bCoreMutex
>
0
;
// #else
#else
// pcache1.separateCache = sqlite3GlobalConfig.pPage==0;
pcache1
.
separateCache
=
sqlite3GlobalConfig
.
pPage
==
0
;
// #endif
#endif
pcache1
.
separateCache
=
1
;
#if SQLITE_THREADSAFE
pthread_mutex_init
(
&
pcache1
.
grp
.
mutex
,
NULL
);
if
(
sqlite3GlobalConfig
.
bCoreMutex
){
pthread_mutex_init
(
&
pcache1
.
mutex
,
NULL
);
pcache1
.
grp
.
mutex
=
sqlite3MutexAlloc
(
SQLITE_MUTEX_STATIC_LRU
);
pcache1
.
mutex
=
sqlite3MutexAlloc
(
SQLITE_MUTEX_STATIC_PMEM
);
// if (pcache1.separateCache && sqlite3GlobalConfig.nPage != 0 && sqlite3GlobalConfig.pPage == 0) {
}
// pcache1.nInitPage = sqlite3GlobalConfig.nPage;
#endif
// } else {
if
(
pcache1
.
separateCache
pcache1
.
nInitPage
=
0
;
&&
sqlite3GlobalConfig
.
nPage
!=
0
// }
&&
sqlite3GlobalConfig
.
pPage
==
0
){
pcache1
.
nInitPage
=
sqlite3GlobalConfig
.
nPage
;
}
else
{
pcache1
.
nInitPage
=
0
;
}
pcache1
.
grp
.
mxPinned
=
10
;
pcache1
.
grp
.
mxPinned
=
10
;
pcache1
.
isInit
=
1
;
pcache1
.
isInit
=
1
;
return
SQLITE_OK
;
return
0
;
}
}
/*
/*
** Implementation of the sqlite3_pcache.xShutdown method.
** Implementation of the sqlite3_pcache.xShutdown method.
** Note that the static mutex allocated in xInit does
** Note that the static mutex allocated in xInit does
** not need to be freed.
** not need to be freed.
*/
*/
static
void
pcache1Shutdown
(
void
*
NotUsed
){
static
void
pcache1Shutdown
(
void
*
NotUsed
)
{
UNUSED_PARAMETER
(
NotUsed
);
assert
(
pcache1
.
isInit
!=
0
);
assert
(
pcache1
.
isInit
!=
0
);
memset
(
&
pcache1
,
0
,
sizeof
(
pcache1
));
memset
(
&
pcache1
,
0
,
sizeof
(
pcache1
));
}
}
...
@@ -774,25 +751,25 @@ static void pcache1Destroy(sqlite3_pcache *p);
...
@@ -774,25 +751,25 @@ static void pcache1Destroy(sqlite3_pcache *p);
**
**
** Allocate a new cache.
** Allocate a new cache.
*/
*/
static
sqlite3_pcache
*
pcache1Create
(
int
szPage
,
int
szExtra
,
int
bPurgeable
){
static
sqlite3_pcache
*
pcache1Create
(
int
szPage
,
int
szExtra
,
int
bPurgeable
)
{
PCache1
*
pCache
;
/* The newly created page cache */
PCache1
*
pCache
;
/* The newly created page cache */
PGroup
*
pGroup
;
/* The group the new page cache will belong to */
PGroup
*
pGroup
;
/* The group the new page cache will belong to */
int
sz
;
/* Bytes of memory required to allocate the new cache */
int
sz
;
/* Bytes of memory required to allocate the new cache */
assert
(
(
szPage
&
(
szPage
-
1
))
==
0
&&
szPage
>=
512
&&
szPage
<=
65536
);
assert
(
(
szPage
&
(
szPage
-
1
))
==
0
&&
szPage
>=
512
&&
szPage
<=
65536
);
assert
(
szExtra
<
300
);
assert
(
szExtra
<
300
);
sz
=
sizeof
(
PCache1
)
+
sizeof
(
PGroup
)
*
pcache1
.
separateCache
;
sz
=
sizeof
(
PCache1
)
+
sizeof
(
PGroup
)
*
pcache1
.
separateCache
;
pCache
=
(
PCache1
*
)
sqlite3MallocZero
(
sz
);
pCache
=
(
PCache1
*
)
sqlite3MallocZero
(
sz
);
if
(
pCache
)
{
if
(
pCache
)
{
if
(
pcache1
.
separateCache
)
{
if
(
pcache1
.
separateCache
)
{
pGroup
=
(
PGroup
*
)
&
pCache
[
1
];
pGroup
=
(
PGroup
*
)
&
pCache
[
1
];
pGroup
->
mxPinned
=
10
;
pGroup
->
mxPinned
=
10
;
}
else
{
}
else
{
pGroup
=
&
pcache1
.
grp
;
pGroup
=
&
pcache1
.
grp
;
}
}
pcache1EnterMutex
(
pGroup
);
pcache1EnterMutex
(
pGroup
);
if
(
pGroup
->
lru
.
isAnchor
==
0
)
{
if
(
pGroup
->
lru
.
isAnchor
==
0
)
{
pGroup
->
lru
.
isAnchor
=
1
;
pGroup
->
lru
.
isAnchor
=
1
;
pGroup
->
lru
.
pLruPrev
=
pGroup
->
lru
.
pLruNext
=
&
pGroup
->
lru
;
pGroup
->
lru
.
pLruPrev
=
pGroup
->
lru
.
pLruNext
=
&
pGroup
->
lru
;
}
}
...
@@ -802,17 +779,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
...
@@ -802,17 +779,17 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache
->
szAlloc
=
szPage
+
szExtra
+
ROUND8
(
sizeof
(
PgHdr1
));
pCache
->
szAlloc
=
szPage
+
szExtra
+
ROUND8
(
sizeof
(
PgHdr1
));
pCache
->
bPurgeable
=
(
bPurgeable
?
1
:
0
);
pCache
->
bPurgeable
=
(
bPurgeable
?
1
:
0
);
pcache1ResizeHash
(
pCache
);
pcache1ResizeHash
(
pCache
);
if
(
bPurgeable
)
{
if
(
bPurgeable
)
{
pCache
->
nMin
=
10
;
pCache
->
nMin
=
10
;
pGroup
->
nMinPage
+=
pCache
->
nMin
;
pGroup
->
nMinPage
+=
pCache
->
nMin
;
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pCache
->
pnPurgeable
=
&
pGroup
->
nPurgeable
;
pCache
->
pnPurgeable
=
&
pGroup
->
nPurgeable
;
}
else
{
}
else
{
pCache
->
pnPurgeable
=
&
pCache
->
nPurgeableDummy
;
pCache
->
pnPurgeable
=
&
pCache
->
nPurgeableDummy
;
}
}
pcache1LeaveMutex
(
pGroup
);
pcache1LeaveMutex
(
pGroup
);
if
(
pCache
->
nHash
==
0
)
{
if
(
pCache
->
nHash
==
0
)
{
pcache1Destroy
((
sqlite3_pcache
*
)
pCache
);
pcache1Destroy
((
sqlite3_pcache
*
)
pCache
);
pCache
=
0
;
pCache
=
0
;
}
}
}
}
...
@@ -820,39 +797,39 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
...
@@ -820,39 +797,39 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
}
}
/*
/*
** Implementation of the sqlite3_pcache.xCachesize method.
** Implementation of the sqlite3_pcache.xCachesize method.
**
**
** Configure the cache_size limit for a cache.
** Configure the cache_size limit for a cache.
*/
*/
static
void
pcache1Cachesize
(
sqlite3_pcache
*
p
,
int
nMax
){
static
void
pcache1Cachesize
(
sqlite3_pcache
*
p
,
int
nMax
)
{
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
u32
n
;
u32
n
;
assert
(
nMax
>=
0
);
assert
(
nMax
>=
0
);
if
(
pCache
->
bPurgeable
)
{
if
(
pCache
->
bPurgeable
)
{
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
pcache1EnterMutex
(
pGroup
);
pcache1EnterMutex
(
pGroup
);
n
=
(
u32
)
nMax
;
n
=
(
u32
)
nMax
;
if
(
n
>
0x7fff0000
-
pGroup
->
nMaxPage
+
pCache
->
nMax
)
{
if
(
n
>
0x7fff0000
-
pGroup
->
nMaxPage
+
pCache
->
nMax
)
{
n
=
0x7fff0000
-
pGroup
->
nMaxPage
+
pCache
->
nMax
;
n
=
0x7fff0000
-
pGroup
->
nMaxPage
+
pCache
->
nMax
;
}
}
pGroup
->
nMaxPage
+=
(
n
-
pCache
->
nMax
);
pGroup
->
nMaxPage
+=
(
n
-
pCache
->
nMax
);
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pCache
->
nMax
=
n
;
pCache
->
nMax
=
n
;
pCache
->
n90pct
=
pCache
->
nMax
*
9
/
10
;
pCache
->
n90pct
=
pCache
->
nMax
*
9
/
10
;
pcache1EnforceMaxPage
(
pCache
);
pcache1EnforceMaxPage
(
pCache
);
pcache1LeaveMutex
(
pGroup
);
pcache1LeaveMutex
(
pGroup
);
}
}
}
}
/*
/*
** Implementation of the sqlite3_pcache.xShrink method.
** Implementation of the sqlite3_pcache.xShrink method.
**
**
** Free up as much memory as possible.
** Free up as much memory as possible.
*/
*/
static
void
pcache1Shrink
(
sqlite3_pcache
*
p
){
static
void
pcache1Shrink
(
sqlite3_pcache
*
p
)
{
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
if
(
pCache
->
bPurgeable
)
{
if
(
pCache
->
bPurgeable
)
{
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
unsigned
int
savedMaxPage
;
unsigned
int
savedMaxPage
;
pcache1EnterMutex
(
pGroup
);
pcache1EnterMutex
(
pGroup
);
savedMaxPage
=
pGroup
->
nMaxPage
;
savedMaxPage
=
pGroup
->
nMaxPage
;
...
@@ -864,18 +841,17 @@ static void pcache1Shrink(sqlite3_pcache *p){
...
@@ -864,18 +841,17 @@ static void pcache1Shrink(sqlite3_pcache *p){
}
}
/*
/*
** Implementation of the sqlite3_pcache.xPagecount method.
** Implementation of the sqlite3_pcache.xPagecount method.
*/
*/
static
int
pcache1Pagecount
(
sqlite3_pcache
*
p
){
static
int
pcache1Pagecount
(
sqlite3_pcache
*
p
)
{
int
n
;
int
n
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
pcache1EnterMutex
(
pCache
->
pGroup
);
pcache1EnterMutex
(
pCache
->
pGroup
);
n
=
pCache
->
nPage
;
n
=
pCache
->
nPage
;
pcache1LeaveMutex
(
pCache
->
pGroup
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
return
n
;
return
n
;
}
}
/*
/*
** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
** Implement steps 3, 4, and 5 of the pcache1Fetch() algorithm described
** in the header of the pcache1Fetch() procedure.
** in the header of the pcache1Fetch() procedure.
...
@@ -884,58 +860,49 @@ static int pcache1Pagecount(sqlite3_pcache *p){
...
@@ -884,58 +860,49 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** usually not needed, and by avoiding the stack initialization required
** usually not needed, and by avoiding the stack initialization required
** for these steps, the main pcache1Fetch() procedure can run faster.
** for these steps, the main pcache1Fetch() procedure can run faster.
*/
*/
static
SQLITE_NOINLINE
PgHdr1
*
pcache1FetchStage2
(
static
SQLITE_NOINLINE
PgHdr1
*
pcache1FetchStage2
(
PCache1
*
pCache
,
unsigned
int
iKey
,
int
createFlag
)
{
PCache1
*
pCache
,
unsigned
int
iKey
,
int
createFlag
){
unsigned
int
nPinned
;
unsigned
int
nPinned
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
PgHdr1
*
pPage
=
0
;
PgHdr1
*
pPage
=
0
;
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
assert
(
pCache
->
nPage
>=
pCache
->
nRecyclable
);
assert
(
pCache
->
nPage
>=
pCache
->
nRecyclable
);
nPinned
=
pCache
->
nPage
-
pCache
->
nRecyclable
;
nPinned
=
pCache
->
nPage
-
pCache
->
nRecyclable
;
assert
(
pGroup
->
mxPinned
==
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
);
assert
(
pGroup
->
mxPinned
==
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
);
assert
(
pCache
->
n90pct
==
pCache
->
nMax
*
9
/
10
);
assert
(
pCache
->
n90pct
==
pCache
->
nMax
*
9
/
10
);
if
(
createFlag
==
1
&&
(
if
(
createFlag
==
1
&&
(
nPinned
>=
pGroup
->
mxPinned
||
nPinned
>=
pCache
->
n90pct
||
nPinned
>=
pGroup
->
mxPinned
(
pcache1UnderMemoryPressure
(
pCache
)
&&
pCache
->
nRecyclable
<
nPinned
)))
{
||
nPinned
>=
pCache
->
n90pct
||
(
pcache1UnderMemoryPressure
(
pCache
)
&&
pCache
->
nRecyclable
<
nPinned
)
)){
return
0
;
return
0
;
}
}
if
(
pCache
->
nPage
>=
pCache
->
nHash
)
pcache1ResizeHash
(
pCache
);
if
(
pCache
->
nPage
>=
pCache
->
nHash
)
pcache1ResizeHash
(
pCache
);
assert
(
pCache
->
nHash
>
0
&&
pCache
->
apHash
);
assert
(
pCache
->
nHash
>
0
&&
pCache
->
apHash
);
/* Step 4. Try to recycle a page. */
/* Step 4. Try to recycle a page. */
if
(
pCache
->
bPurgeable
if
(
pCache
->
bPurgeable
&&
!
pGroup
->
lru
.
pLruPrev
->
isAnchor
&&
&&
!
pGroup
->
lru
.
pLruPrev
->
isAnchor
((
pCache
->
nPage
+
1
>=
pCache
->
nMax
)
||
pcache1UnderMemoryPressure
(
pCache
)))
{
&&
((
pCache
->
nPage
+
1
>=
pCache
->
nMax
)
||
pcache1UnderMemoryPressure
(
pCache
))
){
PCache1
*
pOther
;
PCache1
*
pOther
;
pPage
=
pGroup
->
lru
.
pLruPrev
;
pPage
=
pGroup
->
lru
.
pLruPrev
;
assert
(
PAGE_IS_UNPINNED
(
pPage
)
);
assert
(
PAGE_IS_UNPINNED
(
pPage
)
);
pcache1RemoveFromHash
(
pPage
,
0
);
pcache1RemoveFromHash
(
pPage
,
0
);
pcache1PinPage
(
pPage
);
pcache1PinPage
(
pPage
);
pOther
=
pPage
->
pCache
;
pOther
=
pPage
->
pCache
;
if
(
pOther
->
szAlloc
!=
pCache
->
szAlloc
)
{
if
(
pOther
->
szAlloc
!=
pCache
->
szAlloc
)
{
pcache1FreePage
(
pPage
);
pcache1FreePage
(
pPage
);
pPage
=
0
;
pPage
=
0
;
}
else
{
}
else
{
pGroup
->
nPurgeable
-=
(
pOther
->
bPurgeable
-
pCache
->
bPurgeable
);
pGroup
->
nPurgeable
-=
(
pOther
->
bPurgeable
-
pCache
->
bPurgeable
);
}
}
}
}
/* Step 5. If a usable page buffer has still not been found,
/* Step 5. If a usable page buffer has still not been found,
** attempt to allocate a new one.
** attempt to allocate a new one.
*/
*/
if
(
!
pPage
)
{
if
(
!
pPage
)
{
pPage
=
pcache1AllocPage
(
pCache
,
createFlag
==
1
);
pPage
=
pcache1AllocPage
(
pCache
,
createFlag
==
1
);
}
}
if
(
pPage
)
{
if
(
pPage
)
{
unsigned
int
h
=
iKey
%
pCache
->
nHash
;
unsigned
int
h
=
iKey
%
pCache
->
nHash
;
pCache
->
nPage
++
;
pCache
->
nPage
++
;
pPage
->
iKey
=
iKey
;
pPage
->
iKey
=
iKey
;
...
@@ -946,7 +913,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -946,7 +913,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** No need to clear pLruPrev since it is not accessed when pLruNext==0 */
** No need to clear pLruPrev since it is not accessed when pLruNext==0 */
*
(
void
**
)
pPage
->
page
.
pExtra
=
0
;
*
(
void
**
)
pPage
->
page
.
pExtra
=
0
;
pCache
->
apHash
[
h
]
=
pPage
;
pCache
->
apHash
[
h
]
=
pPage
;
if
(
iKey
>
pCache
->
iMaxKey
)
{
if
(
iKey
>
pCache
->
iMaxKey
)
{
pCache
->
iMaxKey
=
iKey
;
pCache
->
iMaxKey
=
iKey
;
}
}
}
}
...
@@ -954,13 +921,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -954,13 +921,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
}
}
/*
/*
** Implementation of the sqlite3_pcache.xFetch method.
** Implementation of the sqlite3_pcache.xFetch method.
**
**
** Fetch a page by key value.
** Fetch a page by key value.
**
**
** Whether or not a new page may be allocated by this function depends on
** Whether or not a new page may be allocated by this function depends on
** the value of the createFlag argument. 0 means do not allocate a new
** the value of the createFlag argument. 0 means do not allocate a new
** page. 1 means allocate a new page if space is easily available. 2
** page. 1 means allocate a new page if space is easily available. 2
** means to try really hard to allocate a new page.
** means to try really hard to allocate a new page.
**
**
** For a non-purgeable cache (a cache used as the storage for an in-memory
** For a non-purgeable cache (a cache used as the storage for an in-memory
...
@@ -971,7 +938,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -971,7 +938,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** There are three different approaches to obtaining space for a page,
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
**
**
** 1. Regardless of the value of createFlag, the cache is searched for a
** 1. Regardless of the value of createFlag, the cache is searched for a
** copy of the requested page. If one is found, it is returned.
** copy of the requested page. If one is found, it is returned.
**
**
** 2. If createFlag==0 and the page is not already in the cache, NULL is
** 2. If createFlag==0 and the page is not already in the cache, NULL is
...
@@ -985,13 +952,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -985,13 +952,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** PCache1.nMax, or
** PCache1.nMax, or
**
**
** (b) the number of pages pinned by the cache is greater than
** (b) the number of pages pinned by the cache is greater than
** the sum of nMax for all purgeable caches, less the sum of
** the sum of nMax for all purgeable caches, less the sum of
** nMin for all other purgeable caches, or
** nMin for all other purgeable caches, or
**
**
** 4. If none of the first three conditions apply and the cache is marked
** 4. If none of the first three conditions apply and the cache is marked
** as purgeable, and if one of the following is true:
** as purgeable, and if one of the following is true:
**
**
** (a) The number of pages allocated for the cache is already
** (a) The number of pages allocated for the cache is already
** PCache1.nMax, or
** PCache1.nMax, or
**
**
** (b) The number of pages allocated for all purgeable caches is
** (b) The number of pages allocated for all purgeable caches is
...
@@ -1003,7 +970,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -1003,7 +970,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
**
**
** then attempt to recycle a page from the LRU list. If it is the right
** then attempt to recycle a page from the LRU list. If it is the right
** size, return the recycled buffer. Otherwise, free the buffer and
** size, return the recycled buffer. Otherwise, free the buffer and
** proceed to step 5.
** proceed to step 5.
**
**
** 5. Otherwise, allocate and return a new page buffer.
** 5. Otherwise, allocate and return a new page buffer.
**
**
...
@@ -1012,103 +979,88 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
...
@@ -1012,103 +979,88 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper
** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper
** invokes the appropriate routine.
** invokes the appropriate routine.
*/
*/
static
PgHdr1
*
pcache1FetchNoMutex
(
static
PgHdr1
*
pcache1FetchNoMutex
(
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
)
{
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
){
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PgHdr1
*
pPage
=
0
;
PgHdr1
*
pPage
=
0
;
/* Step 1: Search the hash table for an existing entry. */
/* Step 1: Search the hash table for an existing entry. */
pPage
=
pCache
->
apHash
[
iKey
%
pCache
->
nHash
];
pPage
=
pCache
->
apHash
[
iKey
%
pCache
->
nHash
];
while
(
pPage
&&
pPage
->
iKey
!=
iKey
){
pPage
=
pPage
->
pNext
;
}
while
(
pPage
&&
pPage
->
iKey
!=
iKey
)
{
pPage
=
pPage
->
pNext
;
}
/* Step 2: If the page was found in the hash table, then return it.
/* Step 2: If the page was found in the hash table, then return it.
** If the page was not in the hash table and createFlag is 0, abort.
** If the page was not in the hash table and createFlag is 0, abort.
** Otherwise (page not in hash and createFlag!=0) continue with
** Otherwise (page not in hash and createFlag!=0) continue with
** subsequent steps to try to create the page. */
** subsequent steps to try to create the page. */
if
(
pPage
)
{
if
(
pPage
)
{
if
(
PAGE_IS_UNPINNED
(
pPage
)
)
{
if
(
PAGE_IS_UNPINNED
(
pPage
))
{
return
pcache1PinPage
(
pPage
);
return
pcache1PinPage
(
pPage
);
}
else
{
}
else
{
return
pPage
;
return
pPage
;
}
}
}
else
if
(
createFlag
)
{
}
else
if
(
createFlag
)
{
/* Steps 3, 4, and 5 implemented by this subroutine */
/* Steps 3, 4, and 5 implemented by this subroutine */
return
pcache1FetchStage2
(
pCache
,
iKey
,
createFlag
);
return
pcache1FetchStage2
(
pCache
,
iKey
,
createFlag
);
}
else
{
}
else
{
return
0
;
return
0
;
}
}
}
}
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
static
PgHdr1
*
pcache1FetchWithMutex
(
static
PgHdr1
*
pcache1FetchWithMutex
(
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
)
{
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
){
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PgHdr1
*
pPage
;
PgHdr1
*
pPage
;
pcache1EnterMutex
(
pCache
->
pGroup
);
pcache1EnterMutex
(
pCache
->
pGroup
);
pPage
=
pcache1FetchNoMutex
(
p
,
iKey
,
createFlag
);
pPage
=
pcache1FetchNoMutex
(
p
,
iKey
,
createFlag
);
assert
(
pPage
==
0
||
pCache
->
iMaxKey
>=
iKey
);
assert
(
pPage
==
0
||
pCache
->
iMaxKey
>=
iKey
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
return
pPage
;
return
pPage
;
}
}
#endif
#endif
static
sqlite3_pcache_page
*
pcache1Fetch
(
static
sqlite3_pcache_page
*
pcache1Fetch
(
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
)
{
sqlite3_pcache
*
p
,
unsigned
int
iKey
,
int
createFlag
){
#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
#endif
#endif
assert
(
offsetof
(
PgHdr1
,
page
)
==
0
);
assert
(
offsetof
(
PgHdr1
,
page
)
==
0
);
assert
(
pCache
->
bPurgeable
||
createFlag
!=
1
);
assert
(
pCache
->
bPurgeable
||
createFlag
!=
1
);
assert
(
pCache
->
bPurgeable
||
pCache
->
nMin
==
0
);
assert
(
pCache
->
bPurgeable
||
pCache
->
nMin
==
0
);
assert
(
pCache
->
bPurgeable
==
0
||
pCache
->
nMin
==
10
);
assert
(
pCache
->
bPurgeable
==
0
||
pCache
->
nMin
==
10
);
assert
(
pCache
->
nMin
==
0
||
pCache
->
bPurgeable
);
assert
(
pCache
->
nMin
==
0
||
pCache
->
bPurgeable
);
assert
(
pCache
->
nHash
>
0
);
assert
(
pCache
->
nHash
>
0
);
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
if
(
pCache
->
pGroup
->
mutex
)
{
if
(
pCache
->
pGroup
->
mutex
)
{
return
(
sqlite3_pcache_page
*
)
pcache1FetchWithMutex
(
p
,
iKey
,
createFlag
);
return
(
sqlite3_pcache_page
*
)
pcache1FetchWithMutex
(
p
,
iKey
,
createFlag
);
}
else
}
else
#endif
#endif
{
{
return
(
sqlite3_pcache_page
*
)
pcache1FetchNoMutex
(
p
,
iKey
,
createFlag
);
return
(
sqlite3_pcache_page
*
)
pcache1FetchNoMutex
(
p
,
iKey
,
createFlag
);
}
}
}
}
/*
/*
** Implementation of the sqlite3_pcache.xUnpin method.
** Implementation of the sqlite3_pcache.xUnpin method.
**
**
** Mark a page as unpinned (eligible for asynchronous recycling).
** Mark a page as unpinned (eligible for asynchronous recycling).
*/
*/
static
void
pcache1Unpin
(
static
void
pcache1Unpin
(
sqlite3_pcache
*
p
,
sqlite3_pcache_page
*
pPg
,
int
reuseUnlikely
)
{
sqlite3_pcache
*
p
,
sqlite3_pcache_page
*
pPg
,
int
reuseUnlikely
){
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PgHdr1
*
pPage
=
(
PgHdr1
*
)
pPg
;
PgHdr1
*
pPage
=
(
PgHdr1
*
)
pPg
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
assert
(
pPage
->
pCache
==
pCache
);
assert
(
pPage
->
pCache
==
pCache
);
pcache1EnterMutex
(
pGroup
);
pcache1EnterMutex
(
pGroup
);
/* It is an error to call this function if the page is already
/* It is an error to call this function if the page is already
** part of the PGroup LRU list.
** part of the PGroup LRU list.
*/
*/
assert
(
pPage
->
pLruNext
==
0
);
assert
(
pPage
->
pLruNext
==
0
);
assert
(
PAGE_IS_PINNED
(
pPage
)
);
assert
(
PAGE_IS_PINNED
(
pPage
)
);
if
(
reuseUnlikely
||
pGroup
->
nPurgeable
>
pGroup
->
nMaxPage
)
{
if
(
reuseUnlikely
||
pGroup
->
nPurgeable
>
pGroup
->
nMaxPage
)
{
pcache1RemoveFromHash
(
pPage
,
1
);
pcache1RemoveFromHash
(
pPage
,
1
);
}
else
{
}
else
{
/* Add the page to the PGroup LRU list. */
/* Add the page to the PGroup LRU list. */
PgHdr1
**
ppFirst
=
&
pGroup
->
lru
.
pLruNext
;
PgHdr1
**
ppFirst
=
&
pGroup
->
lru
.
pLruNext
;
pPage
->
pLruPrev
=
&
pGroup
->
lru
;
pPage
->
pLruPrev
=
&
pGroup
->
lru
;
...
@@ -1121,35 +1073,30 @@ static void pcache1Unpin(
...
@@ -1121,35 +1073,30 @@ static void pcache1Unpin(
}
}
/*
/*
** Implementation of the sqlite3_pcache.xRekey method.
** Implementation of the sqlite3_pcache.xRekey method.
*/
*/
static
void
pcache1Rekey
(
static
void
pcache1Rekey
(
sqlite3_pcache
*
p
,
sqlite3_pcache_page
*
pPg
,
unsigned
int
iOld
,
unsigned
int
iNew
)
{
sqlite3_pcache
*
p
,
PCache1
*
pCache
=
(
PCache1
*
)
p
;
sqlite3_pcache_page
*
pPg
,
PgHdr1
*
pPage
=
(
PgHdr1
*
)
pPg
;
unsigned
int
iOld
,
PgHdr1
**
pp
;
unsigned
int
iNew
unsigned
int
h
;
){
assert
(
pPage
->
iKey
==
iOld
);
PCache1
*
pCache
=
(
PCache1
*
)
p
;
assert
(
pPage
->
pCache
==
pCache
);
PgHdr1
*
pPage
=
(
PgHdr1
*
)
pPg
;
PgHdr1
**
pp
;
unsigned
int
h
;
assert
(
pPage
->
iKey
==
iOld
);
assert
(
pPage
->
pCache
==
pCache
);
pcache1EnterMutex
(
pCache
->
pGroup
);
pcache1EnterMutex
(
pCache
->
pGroup
);
h
=
iOld
%
pCache
->
nHash
;
h
=
iOld
%
pCache
->
nHash
;
pp
=
&
pCache
->
apHash
[
h
];
pp
=
&
pCache
->
apHash
[
h
];
while
(
(
*
pp
)
!=
pPage
)
{
while
((
*
pp
)
!=
pPage
)
{
pp
=
&
(
*
pp
)
->
pNext
;
pp
=
&
(
*
pp
)
->
pNext
;
}
}
*
pp
=
pPage
->
pNext
;
*
pp
=
pPage
->
pNext
;
h
=
iNew
%
pCache
->
nHash
;
h
=
iNew
%
pCache
->
nHash
;
pPage
->
iKey
=
iNew
;
pPage
->
iKey
=
iNew
;
pPage
->
pNext
=
pCache
->
apHash
[
h
];
pPage
->
pNext
=
pCache
->
apHash
[
h
];
pCache
->
apHash
[
h
]
=
pPage
;
pCache
->
apHash
[
h
]
=
pPage
;
if
(
iNew
>
pCache
->
iMaxKey
)
{
if
(
iNew
>
pCache
->
iMaxKey
)
{
pCache
->
iMaxKey
=
iNew
;
pCache
->
iMaxKey
=
iNew
;
}
}
...
@@ -1157,36 +1104,36 @@ static void pcache1Rekey(
...
@@ -1157,36 +1104,36 @@ static void pcache1Rekey(
}
}
/*
/*
** Implementation of the sqlite3_pcache.xTruncate method.
** Implementation of the sqlite3_pcache.xTruncate method.
**
**
** Discard all unpinned pages in the cache with a page number equal to
** Discard all unpinned pages in the cache with a page number equal to
** or greater than parameter iLimit. Any pinned pages with a page number
** or greater than parameter iLimit. Any pinned pages with a page number
** equal to or greater than iLimit are implicitly unpinned.
** equal to or greater than iLimit are implicitly unpinned.
*/
*/
static
void
pcache1Truncate
(
sqlite3_pcache
*
p
,
unsigned
int
iLimit
){
static
void
pcache1Truncate
(
sqlite3_pcache
*
p
,
unsigned
int
iLimit
)
{
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
pcache1EnterMutex
(
pCache
->
pGroup
);
pcache1EnterMutex
(
pCache
->
pGroup
);
if
(
iLimit
<=
pCache
->
iMaxKey
)
{
if
(
iLimit
<=
pCache
->
iMaxKey
)
{
pcache1TruncateUnsafe
(
pCache
,
iLimit
);
pcache1TruncateUnsafe
(
pCache
,
iLimit
);
pCache
->
iMaxKey
=
iLimit
-
1
;
pCache
->
iMaxKey
=
iLimit
-
1
;
}
}
pcache1LeaveMutex
(
pCache
->
pGroup
);
pcache1LeaveMutex
(
pCache
->
pGroup
);
}
}
/*
/*
** Implementation of the sqlite3_pcache.xDestroy method.
** Implementation of the sqlite3_pcache.xDestroy method.
**
**
** Destroy a cache allocated using pcache1Create().
** Destroy a cache allocated using pcache1Create().
*/
*/
static
void
pcache1Destroy
(
sqlite3_pcache
*
p
){
static
void
pcache1Destroy
(
sqlite3_pcache
*
p
)
{
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PCache1
*
pCache
=
(
PCache1
*
)
p
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
PGroup
*
pGroup
=
pCache
->
pGroup
;
assert
(
pCache
->
bPurgeable
||
(
pCache
->
nMax
==
0
&&
pCache
->
nMin
==
0
)
);
assert
(
pCache
->
bPurgeable
||
(
pCache
->
nMax
==
0
&&
pCache
->
nMin
==
0
)
);
pcache1EnterMutex
(
pGroup
);
pcache1EnterMutex
(
pGroup
);
if
(
pCache
->
nPage
)
pcache1TruncateUnsafe
(
pCache
,
0
);
if
(
pCache
->
nPage
)
pcache1TruncateUnsafe
(
pCache
,
0
);
assert
(
pGroup
->
nMaxPage
>=
pCache
->
nMax
);
assert
(
pGroup
->
nMaxPage
>=
pCache
->
nMax
);
pGroup
->
nMaxPage
-=
pCache
->
nMax
;
pGroup
->
nMaxPage
-=
pCache
->
nMax
;
assert
(
pGroup
->
nMinPage
>=
pCache
->
nMin
);
assert
(
pGroup
->
nMinPage
>=
pCache
->
nMin
);
pGroup
->
nMinPage
-=
pCache
->
nMin
;
pGroup
->
nMinPage
-=
pCache
->
nMin
;
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pGroup
->
mxPinned
=
pGroup
->
nMaxPage
+
10
-
pGroup
->
nMinPage
;
pcache1EnforceMaxPage
(
pCache
);
pcache1EnforceMaxPage
(
pCache
);
...
@@ -1196,42 +1143,16 @@ static void pcache1Destroy(sqlite3_pcache *p){
...
@@ -1196,42 +1143,16 @@ static void pcache1Destroy(sqlite3_pcache *p){
sqlite3_free
(
pCache
);
sqlite3_free
(
pCache
);
}
}
/*
** This function is called during initialization (sqlite3_initialize()) to
** install the default pluggable cache module, assuming the user has not
** already provided an alternative.
*/
void
sqlite3PCacheSetDefault
(
void
){
static
const
sqlite3_pcache_methods2
defaultMethods
=
{
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 */
};
sqlite3_config
(
SQLITE_CONFIG_PCACHE2
,
&
defaultMethods
);
}
/*
/*
** Return the size of the header on each page of this PCACHE implementation.
** Return the size of the header on each page of this PCACHE implementation.
*/
*/
int
sqlite3HeaderSizePcache1
(
void
){
return
ROUND8
(
sizeof
(
PgHdr1
));
}
int
sqlite3HeaderSizePcache1
(
void
)
{
return
ROUND8
(
sizeof
(
PgHdr1
));
}
/*
/*
** Return the global mutex used by this PCACHE implementation. The
** Return the global mutex used by this PCACHE implementation. The
** sqlite3_status() routine needs access to this mutex.
** sqlite3_status() routine needs access to this mutex.
*/
*/
sqlite3_mutex
*
sqlite3Pcache1Mutex
(
void
){
sqlite3_mutex
*
sqlite3Pcache1Mutex
(
void
)
{
return
pcache1
.
mutex
;
}
return
pcache1
.
mutex
;
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
/*
...
@@ -1240,25 +1161,22 @@ sqlite3_mutex *sqlite3Pcache1Mutex(void){
...
@@ -1240,25 +1161,22 @@ sqlite3_mutex *sqlite3Pcache1Mutex(void){
** by the current thread may be sqlite3_free()ed.
** by the current thread may be sqlite3_free()ed.
**
**
** nReq is the number of bytes of memory required. Once this much has
** nReq is the number of bytes of memory required. Once this much has
** been released, the function returns. The return value is the total number
** been released, the function returns. The return value is the total number
** of bytes of memory released.
** of bytes of memory released.
*/
*/
int
sqlite3PcacheReleaseMemory
(
int
nReq
){
int
sqlite3PcacheReleaseMemory
(
int
nReq
)
{
int
nFree
=
0
;
int
nFree
=
0
;
assert
(
sqlite3_mutex_notheld
(
pcache1
.
grp
.
mutex
)
);
assert
(
sqlite3_mutex_notheld
(
pcache1
.
grp
.
mutex
)
);
assert
(
sqlite3_mutex_notheld
(
pcache1
.
mutex
)
);
assert
(
sqlite3_mutex_notheld
(
pcache1
.
mutex
)
);
if
(
sqlite3GlobalConfig
.
pPage
==
0
)
{
if
(
sqlite3GlobalConfig
.
pPage
==
0
)
{
PgHdr1
*
p
;
PgHdr1
*
p
;
pcache1EnterMutex
(
&
pcache1
.
grp
);
pcache1EnterMutex
(
&
pcache1
.
grp
);
while
(
(
nReq
<
0
||
nFree
<
nReq
)
while
((
nReq
<
0
||
nFree
<
nReq
)
&&
(
p
=
pcache1
.
grp
.
lru
.
pLruPrev
)
!=
0
&&
p
->
isAnchor
==
0
)
{
&&
(
p
=
pcache1
.
grp
.
lru
.
pLruPrev
)
!=
0
&&
p
->
isAnchor
==
0
){
nFree
+=
pcache1MemSize
(
p
->
page
.
pBuf
);
nFree
+=
pcache1MemSize
(
p
->
page
.
pBuf
);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree
+=
sqlite3MemSize
(
p
);
nFree
+=
sqlite3MemSize
(
p
);
#endif
#endif
assert
(
PAGE_IS_UNPINNED
(
p
)
);
assert
(
PAGE_IS_UNPINNED
(
p
)
);
pcache1PinPage
(
p
);
pcache1PinPage
(
p
);
pcache1RemoveFromHash
(
p
,
1
);
pcache1RemoveFromHash
(
p
,
1
);
}
}
...
@@ -1273,16 +1191,15 @@ int sqlite3PcacheReleaseMemory(int nReq){
...
@@ -1273,16 +1191,15 @@ int sqlite3PcacheReleaseMemory(int nReq){
** This function is used by test procedures to inspect the internal state
** This function is used by test procedures to inspect the internal state
** of the global cache.
** of the global cache.
*/
*/
void
sqlite3PcacheStats
(
void
sqlite3PcacheStats
(
int
*
pnCurrent
,
/* OUT: Total number of pages cached */
int
*
pnCurrent
,
/* OUT: Total number of pages cached */
int
*
pnMax
,
/* OUT: Global maximum cache size */
int
*
pnMax
,
/* OUT: Global maximum cache size */
int
*
pnMin
,
/* OUT: Sum of PCache1.nMin for purgeable caches */
int
*
pnMin
,
/* OUT: Sum of PCache1.nMin for purgeable caches */
int
*
pnRecyclable
/* OUT: Total number of pages available for recycling */
int
*
pnRecyclable
/* OUT: Total number of pages available for recycling */
)
{
){
PgHdr1
*
p
;
PgHdr1
*
p
;
int
nRecyclable
=
0
;
int
nRecyclable
=
0
;
for
(
p
=
pcache1
.
grp
.
lru
.
pLruNext
;
p
&&
!
p
->
isAnchor
;
p
=
p
->
pLruNext
)
{
for
(
p
=
pcache1
.
grp
.
lru
.
pLruNext
;
p
&&
!
p
->
isAnchor
;
p
=
p
->
pLruNext
)
{
assert
(
PAGE_IS_UNPINNED
(
p
)
);
assert
(
PAGE_IS_UNPINNED
(
p
)
);
nRecyclable
++
;
nRecyclable
++
;
}
}
*
pnCurrent
=
pcache1
.
grp
.
nPurgeable
;
*
pnCurrent
=
pcache1
.
grp
.
nPurgeable
;
...
@@ -1291,3 +1208,19 @@ void sqlite3PcacheStats(
...
@@ -1291,3 +1208,19 @@ void sqlite3PcacheStats(
*
pnRecyclable
=
nRecyclable
;
*
pnRecyclable
=
nRecyclable
;
}
}
#endif
#endif
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 */
};
source/libs/tdb/src/sqliteinc/sqliteInt.h
浏览文件 @
7184778c
...
@@ -13,7 +13,10 @@
...
@@ -13,7 +13,10 @@
**
**
*/
*/
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <stdint.h>
#include <string.h>
#ifndef SQLITEINT_H
#ifndef SQLITEINT_H
#define SQLITEINT_H
#define SQLITEINT_H
...
@@ -32,6 +35,10 @@ typedef struct sqlite3_pcache_page {
...
@@ -32,6 +35,10 @@ typedef struct sqlite3_pcache_page {
void
*
pExtra
;
/* Extra information associated with the page */
void
*
pExtra
;
/* Extra information associated with the page */
}
sqlite3_pcache_page
;
}
sqlite3_pcache_page
;
#define ROUNDDOWN8(x) ((x) & ~7)
#define ROUND8(x) (((x) + 7) & ~7)
typedef
u32
Pgno
;
typedef
u32
Pgno
;
typedef
struct
Pager
Pager
;
typedef
struct
Pager
Pager
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录