| 183 | } |
| 184 | |
| 185 | Future<Option<RecoverResponse>> received( |
| 186 | const Future<RecoverResponse>& future) |
| 187 | { |
| 188 | // Enforced by the select semantics. |
| 189 | CHECK_READY(future); |
| 190 | |
| 191 | // Remove this future from 'responses' so that we do not listen on |
| 192 | // it the next time we invoke select. |
| 193 | responses.erase(future); |
| 194 | |
| 195 | const RecoverResponse& response = future.get(); |
| 196 | |
| 197 | LOG(INFO) << "Received a recover response from a replica in " |
| 198 | << response.status() << " status"; |
| 199 | |
| 200 | responsesReceived[response.status()]++; |
| 201 | |
| 202 | // We need to remember the lowest begin position and highest end |
| 203 | // position seen from VOTING replicas. |
| 204 | if (response.status() == Metadata::VOTING) { |
| 205 | CHECK(response.has_begin() && response.has_end()); |
| 206 | |
| 207 | lowestBeginPosition = min(lowestBeginPosition, response.begin()); |
| 208 | highestEndPosition = max(highestEndPosition, response.end()); |
| 209 | } |
| 210 | |
| 211 | // If we got responses from a quorum of VOTING replicas, the local |
| 212 | // replica will be put in RECOVERING status and start catching up. |
| 213 | // It is likely that the local replica is in RECOVERING status |
| 214 | // already. This is the case where the replica crashes during |
| 215 | // catch-up. When it restarts, we need to recalculate the lowest |
| 216 | // begin position and the highest end position since we haven't |
| 217 | // persisted this information on disk. |
| 218 | if (responsesReceived[Metadata::VOTING] >= quorum) { |
| 219 | process::discard(responses); |
| 220 | |
| 221 | CHECK_SOME(lowestBeginPosition); |
| 222 | CHECK_SOME(highestEndPosition); |
| 223 | CHECK_LE(lowestBeginPosition.get(), highestEndPosition.get()); |
| 224 | |
| 225 | RecoverResponse result; |
| 226 | result.set_status(Metadata::RECOVERING); |
| 227 | result.set_begin(lowestBeginPosition.get()); |
| 228 | result.set_end(highestEndPosition.get()); |
| 229 | |
| 230 | return result; |
| 231 | } |
| 232 | |
| 233 | // TODO(jieyu): Currently, we simply calculate the size of the |
| 234 | // cluster from the quorum size. In the future, we may want to |
| 235 | // allow users to specify the cluster size in case they want to |
| 236 | // use a non-standard quorum size (e.g., cluster size = 5, quorum |
| 237 | // size = 4). |
| 238 | size_t clusterSize = (2 * quorum) - 1; |
| 239 | |
| 240 | if (autoInitialize) { |
| 241 | // The following code handles the auto-initialization. Our idea |
| 242 | // is: we allow a replica in EMPTY status to become VOTING |