aboutsummaryrefslogtreecommitdiff
path: root/src/fault.c
blob: d31dd43870e8f02d05df3d0b4f83e74d6868189b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
/*
** 2008 Jan 22
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement a fault-injector used for
** testing and verification of SQLite.
**
** Subsystems within SQLite can call sqlite3FaultStep() to see if
** they should simulate a fault.  sqlite3FaultStep() normally returns
** zero but will return non-zero if a fault should be simulated.
** Fault injectors can be used, for example, to simulate memory
** allocation failures or I/O errors.
**
** The fault injector is omitted from the code if SQLite is
** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1.  There is a very
** small performance hit for leaving the fault injector in the code.
** Commerical products will probably want to omit the fault injector
** from production builds.  But safety-critical systems who work
** under the motto "fly what you test and test what you fly" may
** choose to leave the fault injector enabled even in production.
*/
#include "sqliteInt.h"

#ifndef SQLITE_OMIT_BUILTIN_TEST

/*
** There can be various kinds of faults.  For example, there can be
** a memory allocation failure.  Or an I/O failure.  For each different
** fault type, there is a separate FaultInjector structure to keep track
** of the status of that fault.
*/
static struct FaultInjector {
  int iCountdown;   /* Number of pending successes before we hit a failure */
  int nRepeat;      /* Number of times to repeat the failure */
  int nBenign;      /* Number of benign failures seen since last config */
  int nFail;        /* Number of failures seen since last config */
  u8 enable;        /* True if enabled */
  u8 benign;        /* True if next failure will be benign */
} aFault[SQLITE_FAULTINJECTOR_COUNT];

/*
** This routine configures and enables a fault injector.  After
** calling this routine, aFaultStep() will return false (zero)
** nDelay times, then it will return true nRepeat times,
** then it will again begin returning false.
*/
void sqlite3FaultConfig(int id, int nDelay, int nRepeat){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  aFault[id].iCountdown = nDelay;
  aFault[id].nRepeat = nRepeat;
  aFault[id].nBenign = 0;
  aFault[id].nFail = 0;
  aFault[id].enable = nDelay>=0;
  aFault[id].benign = 0;
}

/*
** Return the number of faults (both hard and benign faults) that have
** occurred since the injector was last configured.
*/
int sqlite3FaultFailures(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  return aFault[id].nFail;
}

/*
** Return the number of benign faults that have occurred since the
** injector was last configured.
*/
int sqlite3FaultBenignFailures(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  return aFault[id].nBenign;
}

/*
** Return the number of successes that will occur before the next failure.
** If no failures are scheduled, return -1.
*/
int sqlite3FaultPending(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  if( aFault[id].enable ){
    return aFault[id].iCountdown;
  }else{
    return -1;
  }
}

/* 
** After this routine causes subsequent faults to be either benign
** or hard (not benign), according to the "enable" parameter.
**
** Most faults are hard.  In other words, most faults cause
** an error to be propagated back up to the application interface.
** However, sometimes a fault is easily recoverable.  For example,
** if a malloc fails while resizing a hash table, this is completely
** recoverable simply by not carrying out the resize.  The hash table
** will continue to function normally.  So a malloc failure during
** a hash table resize is a benign fault.  
*/
void sqlite3FaultBenign(int id, int enable){
  if( id<0 ){
    for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
      aFault[id].benign = enable;
    }
  }else{
    assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
    aFault[id].benign = enable;
  }
}

/*
** This routine exists as a place to set a breakpoint that will
** fire on any simulated fault.
*/
static void sqlite3Fault(void){
  static int cnt = 0;
  cnt++;
}


/*
** Check to see if a fault should be simulated.  Return true to simulate
** the fault.  Return false if the fault should not be simulated.
*/
int sqlite3FaultStep(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  if( likely(!aFault[id].enable) ){
    return 0;
  }
  if( aFault[id].iCountdown>0 ){
    aFault[id].iCountdown--;
    return 0;
  }
  sqlite3Fault();
  aFault[id].nFail++;
  if( aFault[id].benign ){
    aFault[id].nBenign++;
  }
  aFault[id].nRepeat--;
  if( aFault[id].nRepeat<=0 ){
    aFault[id].enable = 0;
  }
  return 1;  
}

#endif /* SQLITE_OMIT_BUILTIN_TEST */