@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); byte[] serReq = new byte[in.readInt()]; in.readFully(serReq); request = TOMMessage.bytesToMessage(serReq); request.serializedMessage = serReq; boolean signed = in.readBoolean(); if (signed) { byte[] serReqSign = new byte[in.readInt()]; in.readFully(serReqSign); request.serializedMessageSignature = serReqSign; } }
/** * This is the method invoked by the client side communication system. * * @param reply The reply delivered by the client side communication system */ @Override public void replyReceived(TOMMessage reply) { canReceiveLock.lock(); if (reqId == -1) { // no message being expected Logger.println( "throwing out request: sender=" + reply.getSender() + " reqId=" + reply.getSequence()); canReceiveLock.unlock(); return; } int pos = getViewManager().getCurrentViewPos(reply.getSender()); if (pos < 0) { // ignore messages that don't come from replicas canReceiveLock.unlock(); return; } if (reply.getSequence() == reqId && reply.getReqType() == requestType) { if (replyListener != null) { replyListener.replyReceived(reply); canReceiveLock.unlock(); return; } Logger.println( "Receiving reply from " + reply.getSender() + " with reqId:" + reply.getSequence() + ". Putting on pos=" + pos); if (replies[pos] == null) { receivedReplies++; } replies[pos] = reply; // Compare the reply just received, to the others int sameContent = 1; for (int i = 0; i < replies.length; i++) { if (i != pos && replies[i] != null && (comparator.compare(replies[i].getContent(), reply.getContent()) == 0)) { sameContent++; if (sameContent >= replyQuorum) { response = extractor.extractResponse(replies, sameContent, pos); reqId = -1; this.sm.release(); // resumes the thread that is executing the "invoke" method break; } } } if (response == null) { if (requestType.equals(TOMMessageType.ORDERED_REQUEST)) { if (receivedReplies == getViewManager().getCurrentViewN()) { reqId = -1; this.sm.release(); // resumes the thread that is executing the "invoke" method } } else { // UNORDERED if (receivedReplies != sameContent) { reqId = -1; this.sm.release(); // resumes the thread that is executing the "invoke" method } } } } // Critical section ends here. The semaphore can be released canReceiveLock.unlock(); }
/** * This method sends a request to the replicas, and returns the related reply. If the servers take * more than invokeTimeout seconds the method returns null. This method is thread-safe. * * @param request Request to be sent * @param reqType TOM_NORMAL_REQUESTS for service requests, and other for reconfig requests. * @return The reply from the replicas related to request */ public byte[] invoke(byte[] request, TOMMessageType reqType) { canSendLock.lock(); // Clean all statefull data to prepare for receiving next replies Arrays.fill(replies, null); receivedReplies = 0; response = null; replyListener = null; replyQuorum = (int) Math.ceil( (getViewManager().getCurrentViewN() + getViewManager().getCurrentViewF()) / 2) + 1; // Send the request to the replicas, and get its ID reqId = generateRequestId(reqType); requestType = reqType; TOMulticast(request, reqId, reqType); Logger.println("Sending request (" + reqType + ") with reqId=" + reqId); Logger.println("Expected number of matching replies: " + replyQuorum); // This instruction blocks the thread, until a response is obtained. // The thread will be unblocked when the method replyReceived is invoked // by the client side communication system try { if (!this.sm.tryAcquire(invokeTimeout, TimeUnit.SECONDS)) { Logger.println("###################TIMEOUT#######################"); Logger.println("Reply timeout for reqId=" + reqId); canSendLock.unlock(); System.out.print(getProcessId() + " // " + reqId + " // TIMEOUT // "); System.out.println("Replies received: " + receivedReplies); return null; } } catch (InterruptedException ex) { } Logger.println("Response extracted = " + response); byte[] ret = null; if (response == null) { // the response can be null if n-f replies are received but there isn't // a replyQuorum of matching replies Logger.println("Received n-f replies and no response could be extracted."); canSendLock.unlock(); if (reqType == TOMMessageType.UNORDERED_REQUEST) { // invoke the operation again, whitout the read-only flag Logger.println("###################RETRY#######################"); return invokeOrdered(request); } else { throw new RuntimeException("Received n-f replies without f+1 of them matching."); } } else { // normal operation // ******* EDUARDO BEGIN **************// if (reqType == TOMMessageType.ORDERED_REQUEST) { // Reply to a normal request! if (response.getViewID() == getViewManager().getCurrentViewId()) { ret = response.getContent(); // return the response } else { // if(response.getViewID() > getViewManager().getCurrentViewId()) // updated view received reconfigureTo((View) TOMUtil.getObject(response.getContent())); canSendLock.unlock(); return invoke(request, reqType); } } else { if (response.getViewID() > getViewManager().getCurrentViewId()) { // Reply to a reconfigure request! Logger.println("Reconfiguration request' reply received!"); Object r = TOMUtil.getObject(response.getContent()); if (r instanceof View) { // did not executed the request because it is using an outdated view reconfigureTo((View) r); canSendLock.unlock(); return invoke(request, reqType); } else { // reconfiguration executed! reconfigureTo(((ReconfigureReply) r).getView()); ret = response.getContent(); } } else { // Reply to readonly request ret = response.getContent(); } } } // ******* EDUARDO END **************// canSendLock.unlock(); return ret; }