/ Check-in [a0566382]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a problem allowing some conflicting transactions to be committed.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | begin-concurrent
Files: files | file ages | folders
SHA1: a0566382d564ca17fd13475a44fed8f714742d97
User & Date: dan 2015-08-26 18:02:20
Wiki:begin-concurrent
Context
2015-08-26
18:54
Fix an assert() in pager.c that could fail in a concurrent transaction. check-in: 69394dda user: dan tags: begin-concurrent
18:02
Fix a problem allowing some conflicting transactions to be committed. check-in: a0566382 user: dan tags: begin-concurrent
2015-08-25
19:10
Add miscellaneous test cases for concurrent transactions. check-in: 779b1d0e user: dan tags: begin-concurrent
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/wal.c.

2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
        rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
        if( rc==SQLITE_OK ){
          int i;
          int iMin = (iFirst - iZero);
          int iMax = (iHash==0) ? HASHTABLE_NPAGE_ONE : HASHTABLE_NPAGE;
          if( iMin<1 ) iMin = 1;
          if( iMax>head.mxFrame ) iMax = head.mxFrame;
          for(i=iMin; i<=iMax; i++){
            PgHdr *pPg;
            if( aPgno[i]==1 ){
              /* Check that the schema cookie has not been modified. If
              ** it has not, the commit can proceed. */
              u8 aNew[4];
              u8 *aOld = &((u8*)pPage1->pData)[40];
              int sz;







|







2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
        rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
        if( rc==SQLITE_OK ){
          int i;
          int iMin = (iFirst - iZero);
          int iMax = (iHash==0) ? HASHTABLE_NPAGE_ONE : HASHTABLE_NPAGE;
          if( iMin<1 ) iMin = 1;
          if( iMax>head.mxFrame ) iMax = head.mxFrame;
          for(i=iMin; rc==SQLITE_OK && i<=iMax; i++){
            PgHdr *pPg;
            if( aPgno[i]==1 ){
              /* Check that the schema cookie has not been modified. If
              ** it has not, the commit can proceed. */
              u8 aNew[4];
              u8 *aOld = &((u8*)pPage1->pData)[40];
              int sz;

Changes to test/concurrent3.test.

19
20
21
22
23
24
25






26
27
28
29
30
31
32
...
123
124
125
126
127
128
129
130



























































































131
132
set ::testprefix concurrent3

if {$AUTOVACUUM} { finish_test ; return }
ifcapable !concurrent {
  finish_test
  return
}







proc create_schema {} {
  db eval {
    PRAGMA journal_mode = wal;

    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
................................................................................
    db eval {PRAGMA integrity_check}
  } {ok}

  foreach db $DBLIST { 
    $db close 
  }
}




























































































finish_test








>
>
>
>
>
>







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
set ::testprefix concurrent3

if {$AUTOVACUUM} { finish_test ; return }
ifcapable !concurrent {
  finish_test
  return
}

db close
sqlite3_shutdown
#test_sqlite3_log xLog
#proc xLog {error_code msg} { puts "$error_code: $msg" }
reset_db

proc create_schema {} {
  db eval {
    PRAGMA journal_mode = wal;

    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
................................................................................
    db eval {PRAGMA integrity_check}
  } {ok}

  foreach db $DBLIST { 
    $db close 
  }
}

#-------------------------------------------------------------------------
#
proc create_schema2 {} {
  db eval {
    PRAGMA journal_mode = wal;
    CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
    CREATE INDEX i1 ON t1(y);
  }
}

proc randint {nMax} {
  db eval {SELECT abs(random() % $nMax)}
}

proc do_sql_op2 {db iOp} {
  switch -- $iOp {
    i {
      # Insert 1 rows.
      set r [randint 1000000000]
      set ::rows($r) 1
      #puts "insert row $r"
      $db eval { INSERT OR IGNORE INTO t1 VALUES($r, randomblob(50)); }
    }

    d {
      # Insert 1 row
      set keys [array names ::rows]
      set r [randint [llength $keys]]
      set rowid [lindex $keys $r]
      $db eval { DELETE FROM t1 WHERE x=$rowid }
      unset ::rows($rowid)
    }
  }
}

foreach {tn nRepeat oplist} {
  - - ----------------------------
  1 100 { 1iiiiiiiiii }
  2 100 { 1i 2d }
  3 100 { 1d 2i }
  4  50 { 1d 2i 3d }
  5 500 { 1i 2i 3i 4i }
} {
  if {[string range $oplist 0 0]=="-"} {
    array unset rows
    reset_db
    create_schema2
    continue
  }

  foreach db $DBLIST { 
    sqlite3 $db test.db 
    set stats($db,0) 0
    set stats($db,1) 0
  }
  array unset used

  do_test 2.$tn {

    for {set i 0} {$i < $nRepeat} {incr i} {
      foreach db $DBLIST { $db eval "BEGIN CONCURRENT" } 

      foreach op $oplist {
        set iDb [string range $op 0 0]
        set used(db$iDb) 1
        foreach char [split [string range $op 1 end] {}] {
          do_sql_op2 "db$iDb" $char
        }
      }

      foreach db $DBLIST { 
        if {$i==272 && $db=="db4"} breakpoint
        set rc [catch { $db eval COMMIT } msg]
        if {$rc} { $db eval ROLLBACK }
        incr stats($db,$rc)
      }
      set res [db eval {PRAGMA integrity_check}]
      if {$res != "ok"} { puts "after $db $rc: $res" ; after 1000000 }
    }
  } {}

  foreach db $DBLIST { 
    $db close 
  }
  foreach k [lsort [array names used]] {
    puts "$k: $stats($k,0) committed, $stats($k,1) rolled back"
  }
}



finish_test