99 | | * we actually appear to only have one instance of this pattern in Tahoe at time of writing, in {{{allmydata.util.dictutil}}}. It has the disadvantage of cluttering up the logic with calls to {{{_assert_invariants}}}, and should probably be used sparingly. -- DavidSarah |
| 99 | * we actually appear to only have one instance of this pattern in Tahoe at time of writing, in {{{allmydata.util.dictutil}}}. It has the disadvantage of cluttering up the logic with calls to {{{_assert_invariants}}}, and should probably be used sparingly. -- David-Sarah |
| 100 | |
| 101 | ==== assertion policy ==== |
| 102 | |
| 103 | One axis of interest is how time-consuming the checks are. Many precondition |
| 104 | checks can cause typical runtime to explode to O(n^2^) or O(n^3^), for example |
| 105 | {{{SortedList.__contains__}}} called {{{_assert_invariants}}} which took |
| 106 | O(n log n) each time, when {{{__contains__}}} ought to be O(log n). A caller who |
| 107 | was expecting {{{if b in list}}} to take O(log n) could easily wind up turning |
| 108 | their O(n log n) routine into O(n^2^) or worse. |
| 109 | |
| 110 | Another axis is "who could cause it to fail": some checks are looking only at |
| 111 | internal state. For example, if {{{SortedList._assert_invariants}}} fails, it |
| 112 | indicates a problem in some {{{SortedList}}} method. Other checks are |
| 113 | enforcing the external API, like those which do typechecks on input |
| 114 | arguments. Even after the {{{SortedList}}} developer has gained confidence in |
| 115 | the code and decides that internal checks are no longer necessary, it may be |
| 116 | useful to retain the external checks to isolate usage problems that exist in |
| 117 | callers. |
| 118 | |
| 119 | * The general rule is that nodes must be functional for light traffic even |
| 120 | when the assertions are turned on. When assertions are turned off (-O), |
| 121 | nodes must be functional for heavy traffic. |
| 122 | |
| 123 | * Time-consuming internal checks: once the code is working properly, |
| 124 | consider removing them, but they may be left in place as long as they |
| 125 | use {{{assert}}} (the form which gets turned off when -O is used). |
| 126 | |
| 127 | * Cheap internal checks: once the code is working properly, consider |
| 128 | removing them, but it is less of a concern than the time-consuming ones. |
| 129 | If they really are cheap, use {{{_assert}}} (the unconditional form |
| 130 | that gets used even with -O). |
| 131 | |
| 132 | * Time-consuming external checks: maybe leave them in place, but always |
| 133 | use {{{assert}}} so they will not be used with -O. |
| 134 | |
| 135 | * Cheap external checks: leave them in place, using the unconditional |
| 136 | {{{_assert}}} |
| 137 | |
| 138 | * Production grids could run with -O (in practice, the allmydata.com production grid runs without -O, because there are no expensive checks in the current codebase). |
| 139 | |
| 140 | * Testing grids might run without -O in order to detect more bugs. |
| 141 | |
| 142 | * Local developer tests will probably not use -O, and developers should be |
| 143 | prepared to experience the same CPU load problems if they subject their |
| 144 | nodes to real traffic levels. Developers can use -O to turn off everyone |
| 145 | else's checks, use {{{_assert}}} on their own code to enable their own |
| 146 | assertions, and then subject their nodes to heavy traffic, as long as they |
| 147 | are sure to change their checks to use {{{assert}}} (or remove them |
| 148 | altogether) before committing. |
| 149 | |
137 | | ==== assertion policy ==== |
138 | | |
139 | | One axis of interest is how time-consuming the checks are. Many precondition |
140 | | checks can cause typical runtime to explode to O(n^2^) or O(n^3^), for example |
141 | | {{{SortedList.__contains__}}} called {{{_assert_invariants}}} which took |
142 | | O(n log n) each time, when {{{__contains__}}} ought to be O(log n). A caller who |
143 | | was expecting {{{if b in list}}} to take O(log n) could easily wind up turning |
144 | | their O(n log n) routine into O(n^2^) or worse. |
145 | | |
146 | | Another axis is "who could cause it to fail": some checks are looking only at |
147 | | internal state. For example, if {{{SortedList._assert_invariants}}} fails, it |
148 | | indicates a problem in some {{{SortedList}}} method. Other checks are |
149 | | enforcing the external API, like those which do typechecks on input |
150 | | arguments. Even after the {{{SortedList}}} developer has gained confidence in |
151 | | the code and decides that internal checks are no longer necessary, it may be |
152 | | useful to retain the external checks to isolate usage problems that exist in |
153 | | callers. |
154 | | |
155 | | * The general rule is that nodes must be functional for light traffic even |
156 | | when the assertions are turned on. When assertions are turned off (-O), |
157 | | nodes must be functional for heavy traffic. |
158 | | |
159 | | * Time-consuming internal checks: once the code is working properly, |
160 | | consider removing them, but they may be left in place as long as they |
161 | | use {{{assert}}} (the form which gets turned off when -O is used). |
162 | | |
163 | | * Cheap internal checks: once the code is working properly, consider |
164 | | removing them, but it is less of a concern than the time-consuming ones. |
165 | | If they really are cheap, use {{{_assert}}} (the unconditional form |
166 | | that gets used even with -O). |
167 | | |
168 | | * Time-consuming external checks: maybe leave them in place, but always |
169 | | use {{{assert}}} so they will not be used with -O. |
170 | | |
171 | | * Cheap external checks: leave them in place, using the unconditional |
172 | | {{{_assert}}} |
173 | | |
174 | | * Production grids could run with -O (in practice, the allmydata.com production grid runs without -O, because there are no expensive checks in the current codebase). |
175 | | |
176 | | * Testing grids might run without -O in order to detect more bugs. |
177 | | |
178 | | * Local developer tests will probably not use -O, and developers should be |
179 | | prepared to experience the same CPU load problems if they subject their |
180 | | nodes to real traffic levels. Developers can use -O to turn off everyone |
181 | | else's checks, use {{{_assert}}} on their own code to enable their own |
182 | | assertions, and then subject their nodes to heavy traffic, as long as they |
183 | | are sure to change their checks to use {{{assert}}} (or remove them |
184 | | altogether) before committing. |
185 | | |
186 | | |