32 | | More detailed information is [http://boinc.berkeley.edu/validate_logic.txt here]. |
| 32 | == Pseudocode == |
| 33 | {{{ |
| 34 | int check_set( |
| 35 | vector<RESULT> results, |
| 36 | DB_WORKUNIT& wu, |
| 37 | int& canonicalid, |
| 38 | double& credit, |
| 39 | bool& retry |
| 40 | ); |
| 41 | |
| 42 | Define N := length of result vector, and let M := N. |
| 43 | |
| 44 | check_set() will ALWAYS be called with N>=wu.min_quorum. |
| 45 | |
| 46 | check_set() will ALWAYS be called with ALL results satisfying |
| 47 | result.outcome == RESULT_OUTCOME_SUCCESS |
| 48 | result.validate_state == VALIDATE_STATE_INIT |
| 49 | |
| 50 | check_set() should NEVER modify wu [although it is not declared |
| 51 | const] |
| 52 | |
| 53 | [1] Syntax pass (optional) |
| 54 | |
| 55 | for (all N results) { |
| 56 | |
| 57 | if (one or more of the result's output files can be read |
| 58 | and one or more of those files contains erroneous or |
| 59 | invalid or incorrect output, i.e. bad file syntax) |
| 60 | { |
| 61 | set result.outcome=RESULT_OUTCOME_VALIDATE_ERROR; |
| 62 | set result.validate_state=VALIDATE_STATE_INVALID; |
| 63 | decrement counter: M = M-1; |
| 64 | } // erroneous or incorrect or invalid output files |
| 65 | |
| 66 | else if (result has a potentially recoverable error, |
| 67 | i.e. NFS directory not mounted, server |
| 68 | is unreachable, upload server unreachable) |
| 69 | { |
| 70 | dont not modify result.validate_state; |
| 71 | dont not modify result.outcome; |
| 72 | decrement counter M = M-1; |
| 73 | set retry=true; |
| 74 | } // recoverable error |
| 75 | |
| 76 | else if (every output file of the result is unreadable or |
| 77 | fails to exist) |
| 78 | { |
| 79 | set result.outcome=RESULT_OUTCOME_VALIDATE_ERROR; |
| 80 | set result.validate_state=VALIDATE_STATE_INIT; |
| 81 | decrement counter: M = M-1; |
| 82 | } // all result output files unreadable or nonexistent |
| 83 | |
| 84 | } // end of syntax pass loop over all N results |
| 85 | |
| 86 | Define REMAINING RESULTS to be those that do NOT fall into one of |
| 87 | the three categories above. There are M of these. If the syntax pass |
| 88 | has been skipped, then M == N. |
| 89 | |
| 90 | if (M < wu.min_quorum) |
| 91 | { |
| 92 | don't modify canonicalid; |
| 93 | don't modify credit; |
| 94 | leave retry as set above; |
| 95 | leave result.outcome unchanged for M remaining results; |
| 96 | leave result.validate_state unchanged for M remaining results; |
| 97 | return 0; |
| 98 | } // fewer than min_quorum results remain |
| 99 | |
| 100 | At any point in this process, if a major error occurs, check_set() |
| 101 | should return nonzero. This will cause the validator to exit. If |
| 102 | this happens, it does not matter how you have set or modified |
| 103 | result.outcome, result.validate_state, retry, credit, or canonicalid. |
| 104 | |
| 105 | // END OF OPTIONAL SYNTAX PASS |
| 106 | |
| 107 | |
| 108 | [2] Comparison pass (required). We have |
| 109 | M>=wu.min_quorum REMAINING RESULTS results with |
| 110 | result.outcome == RESULT_OUTCOME_SUCCESS |
| 111 | result.validate_state == VALIDATE_STATE_INIT |
| 112 | |
| 113 | All the output files of all of these results are |
| 114 | readable. All of the output files for a given result |
| 115 | are, when taken "in isolation" apparently valid. [If |
| 116 | these conditions are not met then you must do the |
| 117 | "syntax pass" above.] |
| 118 | |
| 119 | if (one of these results is determined to be THE correct |
| 120 | [canonical] result) |
| 121 | { |
| 122 | |
| 123 | for (correct result) { |
| 124 | set result.validate_state=VALIDATE_STATE_VALID; |
| 125 | set canonicalid=result.id; |
| 126 | } // canonical result |
| 127 | |
| 128 | for (the REMAINING M - 1 results) |
| 129 | { |
| 130 | // NOTE: what is below can be done by calling |
| 131 | // check_pair(result, canonical_result) |
| 132 | if (result is correct, matches canonical) |
| 133 | { |
| 134 | result.validate_state=VALIDATE_STATE_VALID; |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | result.validate_state=VALIDATE_STATE_INVALID; |
| 139 | } |
| 140 | } // loop over remaining M-1 results |
| 141 | |
| 142 | set credit; |
| 143 | |
| 144 | leave retry as set from the syntax pass above; |
| 145 | |
| 146 | return 0; |
| 147 | } // found canonical result |
| 148 | else |
| 149 | { |
| 150 | // You are UNABLE to determine if one of the M REMAINING RESULTS |
| 151 | // is correct, so: |
| 152 | |
| 153 | do not modify result.outcome for ANY of M remaining results; |
| 154 | do not modify result.validate_state for ANY of M remaining results; |
| 155 | do not set credit; |
| 156 | do not set canonicalid; |
| 157 | leave retry as set from the syntax pass; |
| 158 | return 0; |
| 159 | |
| 160 | } // did not find canonical result |
| 161 | |
| 162 | At any point in this process, if a major error occurs, check_set() |
| 163 | should return nonzero. This will cause the validator to exit. If |
| 164 | this happens, it does not matter how you have set result.outcome, |
| 165 | result.validate_state, retry, credit, or canonicalid for ANY of the |
| 166 | results. |
| 167 | |
| 168 | // end of Comparison pass |
| 169 | }}} |