private KvReply perform(KvOperation operation) { final int MAX_ITERATIONS = 10000; KvReply reply = new KvReply(); for (int i = 0; i < MAX_ITERATIONS; i++) { // So it have been processed yet, do not advance to make // at-most-once semantic String last = lastOperationUUID.get(operation.clientId); if (last != null && last.compareTo(operation.uuid) == 0) { reply.status = KvReply.Status.Success; reply.payload = lastOperation.get(operation.clientId); return reply; } int instanceId = completedOperationId + 1; Paxos.Status status = paxos.getStatus(instanceId); KvOperation result = null; if (status.accepted) { result = (KvOperation) status.value; } else { paxos.start(instanceId, operation); result = waitAgreement(instanceId); // If empty, please skip the apply operation if (result == null) continue; } // Apply (result, instanceId); apply(instanceId, result); if (operation.uuid.compareTo(result.uuid) == 0) { reply.status = KvReply.Status.Success; reply.payload = lastOperation.get(operation.clientId); return reply; } } reply.status = KvReply.Status.InternalError; return reply; }
private void apply(int instanceId, KvOperation operation) { if (engineInstance.containsKey(operation.key)) { lastOperation.put(operation.clientId, engineInstance.get(operation.key)); } else { lastOperation.put(operation.clientId, null); } lastOperationUUID.put(operation.clientId, operation.uuid); if (operation.command == KvOperation.Command.PutOperation) { engineInstance.put(operation.key, operation.value); } completedOperationId++; paxos.done(instanceId); }