xref: /sqlite-3.40.0/src/fault.c (revision 8a29dfde)
1 /*
2 ** 2008 Jan 22
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 ** This file contains code to implement a fault-injector used for
13 ** testing and verification of SQLite.
14 **
15 ** Subsystems within SQLite can call sqlite3FaultStep() to see if
16 ** they should simulate a fault.  sqlite3FaultStep() normally returns
17 ** zero but will return non-zero if a fault should be simulated.
18 ** Fault injectors can be used, for example, to simulate memory
19 ** allocation failures or I/O errors.
20 **
21 ** The fault injector is omitted from the code if SQLite is
22 ** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1.  There is a very
23 ** small performance hit for leaving the fault injector in the code.
24 ** Commerical products will probably want to omit the fault injector
25 ** from production builds.  But safety-critical systems who work
26 ** under the motto "fly what you test and test what you fly" may
27 ** choose to leave the fault injector enabled even in production.
28 */
29 #include "sqliteInt.h"
30 
31 #ifndef SQLITE_OMIT_BUILTIN_TEST
32 
33 /*
34 ** There can be various kinds of faults.  For example, there can be
35 ** a memory allocation failure.  Or an I/O failure.  For each different
36 ** fault type, there is a separate FaultInjector structure to keep track
37 ** of the status of that fault.
38 */
39 static struct FaultInjector {
40   int iCountdown;   /* Number of pending successes before we hit a failure */
41   int nRepeat;      /* Number of times to repeat the failure */
42   int nBenign;      /* Number of benign failures seen since last config */
43   int nFail;        /* Number of failures seen since last config */
44   u8 enable;        /* True if enabled */
45   u8 benign;        /* True if next failure will be benign */
46 } aFault[SQLITE_FAULTINJECTOR_COUNT];
47 
48 /*
49 ** This routine configures and enables a fault injector.  After
50 ** calling this routine, aFaultStep() will return false (zero)
51 ** nDelay times, then it will return true nRepeat times,
52 ** then it will again begin returning false.
53 */
54 void sqlite3FaultConfig(int id, int nDelay, int nRepeat){
55   assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
56   aFault[id].iCountdown = nDelay;
57   aFault[id].nRepeat = nRepeat;
58   aFault[id].nBenign = 0;
59   aFault[id].nFail = 0;
60   aFault[id].enable = nDelay>=0;
61   aFault[id].benign = 0;
62 }
63 
64 /*
65 ** Return the number of faults (both hard and benign faults) that have
66 ** occurred since the injector was last configured.
67 */
68 int sqlite3FaultFailures(int id){
69   assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
70   return aFault[id].nFail;
71 }
72 
73 /*
74 ** Return the number of benign faults that have occurred since the
75 ** injector was last configured.
76 */
77 int sqlite3FaultBenignFailures(int id){
78   assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
79   return aFault[id].nBenign;
80 }
81 
82 /*
83 ** Return the number of successes that will occur before the next failure.
84 ** If no failures are scheduled, return -1.
85 */
86 int sqlite3FaultPending(int id){
87   assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
88   if( aFault[id].enable ){
89     return aFault[id].iCountdown;
90   }else{
91     return -1;
92   }
93 }
94 
95 /*
96 ** After this routine causes subsequent faults to be either benign
97 ** or hard (not benign), according to the "enable" parameter.
98 **
99 ** Most faults are hard.  In other words, most faults cause
100 ** an error to be propagated back up to the application interface.
101 ** However, sometimes a fault is easily recoverable.  For example,
102 ** if a malloc fails while resizing a hash table, this is completely
103 ** recoverable simply by not carrying out the resize.  The hash table
104 ** will continue to function normally.  So a malloc failure during
105 ** a hash table resize is a benign fault.
106 */
107 void sqlite3FaultBenign(int id, int enable){
108   if( id<0 ){
109     for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
110       aFault[id].benign = enable;
111     }
112   }else{
113     assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
114     aFault[id].benign = enable;
115   }
116 }
117 
118 /*
119 ** This routine exists as a place to set a breakpoint that will
120 ** fire on any simulated fault.
121 */
122 static void sqlite3Fault(void){
123   static int cnt = 0;
124   cnt++;
125 }
126 
127 
128 /*
129 ** Check to see if a fault should be simulated.  Return true to simulate
130 ** the fault.  Return false if the fault should not be simulated.
131 */
132 int sqlite3FaultStep(int id){
133   assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
134   if( likely(!aFault[id].enable) ){
135     return 0;
136   }
137   if( aFault[id].iCountdown>0 ){
138     aFault[id].iCountdown--;
139     return 0;
140   }
141   sqlite3Fault();
142   aFault[id].nFail++;
143   if( aFault[id].benign ){
144     aFault[id].nBenign++;
145   }
146   aFault[id].nRepeat--;
147   if( aFault[id].nRepeat<=0 ){
148     aFault[id].enable = 0;
149   }
150   return 1;
151 }
152 
153 #endif /* SQLITE_OMIT_BUILTIN_TEST */
154