Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a problem causing corruption when an UNLOCKED transaction is rolled back. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA1: |
7c36147846484c96023939864417b562 |
User & Date: | dan 2015-08-20 20:25:56.029 |
Context
2015-08-21
| ||
14:21 | Add extra tests and a fix for rollbacks of UNLOCKED transactions. (check-in: 82cd837e72 user: dan tags: begin-concurrent) | |
2015-08-20
| ||
20:25 | Fix a problem causing corruption when an UNLOCKED transaction is rolled back. (check-in: 7c36147846 user: dan tags: begin-concurrent) | |
2015-08-19
| ||
20:27 | When committing an unlocked transaction, relocate newly allocated database pages within the file to avoid conflicting with committed transactions. There are lots of things still to fix in this code. (check-in: 3bbc31d515 user: dan tags: begin-concurrent) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 | /* ** This function is called to rollback a transaction on a WAL database. */ static int pagerRollbackWal(Pager *pPager){ int rc; /* Return Code */ PgHdr *pList; /* List of dirty pages to revert */ /* For all pages in the cache that are currently dirty or have already ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); pList = sqlite3PcacheDirtyList(pPager->pPCache); while( pList && rc==SQLITE_OK ){ PgHdr *pNext = pList->pDirty; rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } return rc; } /* ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), | > > > > > > > > > | 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 | /* ** This function is called to rollback a transaction on a WAL database. */ static int pagerRollbackWal(Pager *pPager){ int rc; /* Return Code */ PgHdr *pList; /* List of dirty pages to revert */ int bPage1 = 0; /* True if page 1 has been undone */ /* For all pages in the cache that are currently dirty or have already ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or ** + Reload page content from the database (if refcount>0). */ pPager->dbSize = pPager->dbOrigSize; rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager); pList = sqlite3PcacheDirtyList(pPager->pPCache); while( pList && rc==SQLITE_OK ){ PgHdr *pNext = pList->pDirty; if( pList->pgno==1 ) bPage1 = 1; rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } /* If this is an UNLOCKED transaction, then page 1 must be reread from the ** db file, even if it is not dirty. This is because the b-tree layer may ** have already zeroed the nFree and iTrunk header fields. */ if( rc==SQLITE_OK && bPage1==0 && pPager->pAllRead ){ rc = pagerUndoCallback((void*)pPager, 1); } return rc; } /* ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), |
︙ | ︙ |
Changes to test/unlocked2.test.
︙ | ︙ | |||
86 87 88 89 90 91 92 | sql1 { BEGIN UNLOCKED; INSERT INTO t1 VALUES(randomblob(1500)); } sql2 { INSERT INTO t2 VALUES(randomblob(1500)); } | > > > > > > | > > > > > > | > | > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | sql1 { BEGIN UNLOCKED; INSERT INTO t1 VALUES(randomblob(1500)); } sql2 { INSERT INTO t2 VALUES(randomblob(1500)); } sql1 COMMIT } {} do_test 2.$tn.3 { sql3 { PRAGMA integrity_check } } {ok} do_test 2.$tn.4 { sql1 { BEGIN UNLOCKED; DELETE FROM t1; } sql2 { DELETE FROM t2; } sql1 COMMIT } {} do_test 2.$tn.5 { sql3 { PRAGMA integrity_check } } {ok} do_test 2.$tn.6 { sql1 { INSERT INTO t1 VALUES(randomblob(1500)); INSERT INTO t1 VALUES(randomblob(1500)); INSERT INTO t2 VALUES(randomblob(1500)); DELETE FROM t1 WHERE rowid=1; } sql1 { BEGIN UNLOCKED; DELETE FROM t1 WHERE rowid=2; } sql2 { DELETE FROM t2; } sql1 COMMIT } {} do_test 2.$tn.7 { sql3 { PRAGMA integrity_check } } {ok} } reset_db do_execsql_test 3.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500)); DELETE FROM t1; } {wal} db close sqlite3 db test.db breakpoint do_execsql_test 3.1 { BEGIN UNLOCKED; INSERT INTO t1 VALUES(1, 2); ROLLBACK; } do_execsql_test 3.2 { PRAGMA integrity_check; } {ok} do_execsql_test 3.3 { PRAGMA freelist_count; } {2} finish_test |