/ Check-in [47e702bd]
Login

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

Overview
Comment:Fix some problems with OOM handling in vdbesort.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | threads
Files: files | file ages | folders
SHA1:47e702bd8392bc50c4edaf6a2c8c499af87b520e
User & Date: dan 2014-04-02 15:15:25
Context
2014-04-02
18:58
Add a big introductory comment to vdbesort.c explaining its operation at a high level. Also adjust some symbolic names and fix other comment issues in that file. check-in: eef60f1b user: drh tags: threads
15:15
Fix some problems with OOM handling in vdbesort.c. check-in: 47e702bd user: dan tags: threads
14:38
Change the name of the SorterThread object to "SortSubtask" to avoid confusion with the SQLiteThread object. check-in: 4ee2d910 user: drh tags: threads
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbesort.c.

439
440
441
442
443
444
445
446

447
448
449



450
451
452
453
454
455
456
...
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726


727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
....
1288
1289
1290
1291
1292
1293
1294
1295
1296

1297
1298
1299


1300
1301
1302
1303
1304
1305
1306
  assert( pThread->iTemp1Off>iStart );
  assert( pIter->aAlloc==0 );
  assert( pIter->aBuffer==0 );
  pIter->pFile = pThread->pTemp1;
  pIter->iReadOff = iStart;
  pIter->nAlloc = 128;
  pIter->aAlloc = (u8*)sqlite3Malloc(pIter->nAlloc);


  /* Try to xFetch() a mapping of the entire temp file. If this is possible,
  ** the PMA will be read via the mapping. Otherwise, use xRead().  */
  rc = sqlite3OsFetch(pIter->pFile, 0, pThread->iTemp1Off, &pMap);




  if( rc==SQLITE_OK ){
    if( pMap ){
      pIter->aMap = (u8*)pMap;
    }else{
      pIter->nBuffer = nBuf;
      pIter->aBuffer = (u8*)sqlite3Malloc(nBuf);
................................................................................
    pNew->aIter = (VdbeSorterIter*)&pNew[1];
    pNew->aTree = (int*)&pNew->aIter[N];
  }
  return pNew;
}

/*
** Reset a merger
*/
static void vdbeSorterMergerReset(SorterMerger *pMerger){
  int i;
  if( pMerger ){
    for(i=0; i<pMerger->nTree; i++){
      vdbeSorterIterZero(&pMerger->aIter[i]);
    }
  }
}


/*
** Free the SorterMerger object passed as the only argument.
*/
static void vdbeSorterMergerFree(SorterMerger *pMerger){
  vdbeSorterMergerReset(pMerger);
  sqlite3_free(pMerger);
}

/*
** Reset a sorting cursor back to its original empty state.
*/
void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
  int i;
  vdbeSorterJoinAll(pSorter, SQLITE_OK);


  for(i=0; i<pSorter->nThread; i++){
    SortSubtask *pThread = &pSorter->aThread[i];
    vdbeSortSubtaskCleanup(db, pThread);
  }
  if( pSorter->aMemory==0 ){
    vdbeSorterRecordFree(0, pSorter->pRecord);
  }
  vdbeSorterMergerReset(pSorter->pMerger);
  pSorter->pRecord = 0;
  pSorter->nInMemory = 0;
  pSorter->bUsePMA = 0;
  pSorter->iMemory = 0;
}

/*
................................................................................
        }
      }
      rc = sqlite3ThreadCreate(&pThread->pThread, vdbeSortSubtaskMain, pCtx);
    }else
#endif
    {
      /* Use the foreground thread for this operation */
      u8 *aMem;
      rc = vdbeSorterRunThread(pThread);

      aMem = pThread->aListMemory;
      pThread->aListMemory = pSorter->aMemory;
      pSorter->aMemory = aMem;


    }
  }

  return rc;
}

/*







<
>
|
|
|
>
>
>







 







|

|






<
<
<
<
<
<
<
<









>
>







<







 







<

>
|
|
|
>
>







439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454
455
456
457
458
459
...
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712








713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730

731
732
733
734
735
736
737
....
1284
1285
1286
1287
1288
1289
1290

1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
  assert( pThread->iTemp1Off>iStart );
  assert( pIter->aAlloc==0 );
  assert( pIter->aBuffer==0 );
  pIter->pFile = pThread->pTemp1;
  pIter->iReadOff = iStart;
  pIter->nAlloc = 128;
  pIter->aAlloc = (u8*)sqlite3Malloc(pIter->nAlloc);

  if( pIter->aAlloc ){
    /* Try to xFetch() a mapping of the entire temp file. If this is possible,
    ** the PMA will be read via the mapping. Otherwise, use xRead().  */
    rc = sqlite3OsFetch(pIter->pFile, 0, pThread->iTemp1Off, &pMap);
  }else{
    rc = SQLITE_NOMEM;
  }

  if( rc==SQLITE_OK ){
    if( pMap ){
      pIter->aMap = (u8*)pMap;
    }else{
      pIter->nBuffer = nBuf;
      pIter->aBuffer = (u8*)sqlite3Malloc(nBuf);
................................................................................
    pNew->aIter = (VdbeSorterIter*)&pNew[1];
    pNew->aTree = (int*)&pNew->aIter[N];
  }
  return pNew;
}

/*
** Free the SorterMerger object passed as the only argument.
*/
static void vdbeSorterMergerFree(SorterMerger *pMerger){
  int i;
  if( pMerger ){
    for(i=0; i<pMerger->nTree; i++){
      vdbeSorterIterZero(&pMerger->aIter[i]);
    }
  }








  sqlite3_free(pMerger);
}

/*
** Reset a sorting cursor back to its original empty state.
*/
void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
  int i;
  vdbeSorterJoinAll(pSorter, SQLITE_OK);
  vdbeSorterMergerFree(pSorter->pMerger);
  pSorter->pMerger = 0;
  for(i=0; i<pSorter->nThread; i++){
    SortSubtask *pThread = &pSorter->aThread[i];
    vdbeSortSubtaskCleanup(db, pThread);
  }
  if( pSorter->aMemory==0 ){
    vdbeSorterRecordFree(0, pSorter->pRecord);
  }

  pSorter->pRecord = 0;
  pSorter->nInMemory = 0;
  pSorter->bUsePMA = 0;
  pSorter->iMemory = 0;
}

/*
................................................................................
        }
      }
      rc = sqlite3ThreadCreate(&pThread->pThread, vdbeSortSubtaskMain, pCtx);
    }else
#endif
    {
      /* Use the foreground thread for this operation */

      rc = vdbeSorterRunThread(pThread);
      if( rc==SQLITE_OK ){
        u8 *aMem = pThread->aListMemory;
        pThread->aListMemory = pSorter->aMemory;
        pSorter->aMemory = aMem;
        assert( pThread->pList==0 );
      }
    }
  }

  return rc;
}

/*

Changes to test/mallocA.test.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
111
112
113
114
115
116
117






















118
119
120
121
122
123
124
125
126
#
if {!$MEMDEBUG} {
   puts "Skipping mallocA tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}


# Construct a test database
#
forcedelete test.db.bu
db eval {
  CREATE TABLE t1(a COLLATE NOCASE,b,c);
  INSERT INTO t1 VALUES(1,2,3);
  INSERT INTO t1 VALUES(1,2,4);
................................................................................
      ANALYZE sqlite_master;
      SELECT rowid FROM t1 WHERE a='abc' AND b<'y';
    }
  } -test {
    faultsim_test_result [list 0 {1 2}]
  }
}























# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

forcedelete test.db.bu
finish_test







<







 







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









21
22
23
24
25
26
27

28
29
30
31
32
33
34
...
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
#
if {!$MEMDEBUG} {
   puts "Skipping mallocA tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}


# Construct a test database
#
forcedelete test.db.bu
db eval {
  CREATE TABLE t1(a COLLATE NOCASE,b,c);
  INSERT INTO t1 VALUES(1,2,3);
  INSERT INTO t1 VALUES(1,2,4);
................................................................................
      ANALYZE sqlite_master;
      SELECT rowid FROM t1 WHERE a='abc' AND b<'y';
    }
  } -test {
    faultsim_test_result [list 0 {1 2}]
  }
}

do_execsql_test 7.0 {
  PRAGMA cache_size = 5;
}
do_faultsim_test 7 -faults oom-trans* -prep {
  if {$iFail < 500} { set iFail 2000 }
  if {$iFail > 1215} { set iFail 2000 }
} -body {
  execsql {
    WITH r(x,y) AS (
      SELECT 1, randomblob(100)
      UNION ALL
      SELECT x+1, randomblob(100) FROM r
      LIMIT 1000
    )
    SELECT count(x), length(y) FROM r GROUP BY (x%5)
  }
} -test {
  set res [list 200 100 200 100 200 100 200 100 200 100]
  faultsim_test_result [list 0 $res]
}


# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
  catch {db close}
  set sqlite_open_file_count
} {0}

forcedelete test.db.bu
finish_test