Skip to content

Commit b81be22

Browse files
committed
When a sub-transaction is released, if no pages required by containing sub-transactions were journaled, truncate the statement journal. This prevents out of control statement journal growth in some cases.
2 parents 693fcee + b3086c2 commit b81be22

File tree

2 files changed

+34
-22
lines changed

2 files changed

+34
-22
lines changed

src/memjournal.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ struct MemJournal {
7070
int nChunkSize; /* In-memory chunk-size */
7171

7272
int nSpill; /* Bytes of data before flushing */
73-
int nSize; /* Bytes of data currently in memory */
7473
FileChunk *pFirst; /* Head of in-memory chunk-list */
7574
FilePoint endpoint; /* Pointer to the end of the file */
7675
FilePoint readpoint; /* Pointer to the end of the last xRead() */
@@ -131,14 +130,13 @@ static int memjrnlRead(
131130
/*
132131
** Free the list of FileChunk structures headed at MemJournal.pFirst.
133132
*/
134-
static void memjrnlFreeChunks(MemJournal *p){
133+
static void memjrnlFreeChunks(FileChunk *pFirst){
135134
FileChunk *pIter;
136135
FileChunk *pNext;
137-
for(pIter=p->pFirst; pIter; pIter=pNext){
136+
for(pIter=pFirst; pIter; pIter=pNext){
138137
pNext = pIter->pNext;
139138
sqlite3_free(pIter);
140139
}
141-
p->pFirst = 0;
142140
}
143141

144142
/*
@@ -165,7 +163,7 @@ static int memjrnlCreateFile(MemJournal *p){
165163
}
166164
if( rc==SQLITE_OK ){
167165
/* No error has occurred. Free the in-memory buffers. */
168-
memjrnlFreeChunks(&copy);
166+
memjrnlFreeChunks(copy.pFirst);
169167
}
170168
}
171169
if( rc!=SQLITE_OK ){
@@ -248,30 +246,37 @@ static int memjrnlWrite(
248246
nWrite -= iSpace;
249247
p->endpoint.iOffset += iSpace;
250248
}
251-
p->nSize = iAmt + iOfst;
252249
}
253250
}
254251

255252
return SQLITE_OK;
256253
}
257254

258255
/*
259-
** Truncate the file.
260-
**
261-
** If the journal file is already on disk, truncate it there. Or, if it
262-
** is still in main memory but is being truncated to zero bytes in size,
263-
** ignore
256+
** Truncate the in-memory file.
264257
*/
265258
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
266259
MemJournal *p = (MemJournal *)pJfd;
267-
if( ALWAYS(size==0) ){
268-
memjrnlFreeChunks(p);
269-
p->nSize = 0;
270-
p->endpoint.pChunk = 0;
271-
p->endpoint.iOffset = 0;
272-
p->readpoint.pChunk = 0;
273-
p->readpoint.iOffset = 0;
260+
FileChunk *pIter = 0;
261+
262+
if( size==0 ){
263+
memjrnlFreeChunks(p->pFirst);
264+
p->pFirst = 0;
265+
}else{
266+
i64 iOff = p->nChunkSize;
267+
for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){
268+
iOff += p->nChunkSize;
269+
}
270+
if( pIter ){
271+
memjrnlFreeChunks(pIter->pNext);
272+
pIter->pNext = 0;
273+
}
274274
}
275+
276+
p->endpoint.pChunk = pIter;
277+
p->endpoint.iOffset = size;
278+
p->readpoint.pChunk = 0;
279+
p->readpoint.iOffset = 0;
275280
return SQLITE_OK;
276281
}
277282

@@ -280,7 +285,7 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
280285
*/
281286
static int memjrnlClose(sqlite3_file *pJfd){
282287
MemJournal *p = (MemJournal *)pJfd;
283-
memjrnlFreeChunks(p);
288+
memjrnlFreeChunks(p->pFirst);
284289
return SQLITE_OK;
285290
}
286291

src/pager.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ struct PagerSavepoint {
435435
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
436436
Pgno nOrig; /* Original number of pages in file */
437437
Pgno iSubRec; /* Index of first record in sub-journal */
438+
int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */
438439
#ifndef SQLITE_OMIT_WAL
439440
u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
440441
#endif
@@ -1070,6 +1071,9 @@ static int subjRequiresPage(PgHdr *pPg){
10701071
for(i=0; i<pPager->nSavepoint; i++){
10711072
p = &pPager->aSavepoint[i];
10721073
if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){
1074+
for(i=i+1; i<pPager->nSavepoint; i++){
1075+
pPager->aSavepoint[i].bTruncateOnRelease = 0;
1076+
}
10731077
return 1;
10741078
}
10751079
}
@@ -6848,6 +6852,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
68486852
}
68496853
aNew[ii].iSubRec = pPager->nSubRec;
68506854
aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
6855+
aNew[ii].bTruncateOnRelease = 1;
68516856
if( !aNew[ii].pInSavepoint ){
68526857
return SQLITE_NOMEM_BKPT;
68536858
}
@@ -6929,13 +6934,15 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
69296934
/* If this is a release of the outermost savepoint, truncate
69306935
** the sub-journal to zero bytes in size. */
69316936
if( op==SAVEPOINT_RELEASE ){
6932-
if( nNew==0 && isOpen(pPager->sjfd) ){
6937+
PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
6938+
if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
69336939
/* Only truncate if it is an in-memory sub-journal. */
69346940
if( sqlite3JournalIsInMemory(pPager->sjfd) ){
6935-
rc = sqlite3OsTruncate(pPager->sjfd, 0);
6941+
i64 sz = (pPager->pageSize+4)*pRel->iSubRec;
6942+
rc = sqlite3OsTruncate(pPager->sjfd, sz);
69366943
assert( rc==SQLITE_OK );
69376944
}
6938-
pPager->nSubRec = 0;
6945+
pPager->nSubRec = pRel->iSubRec;
69396946
}
69406947
}
69416948
/* Else this is a rollback operation, playback the specified savepoint.

0 commit comments

Comments
 (0)