001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017package org.opends.server.replication.server; 018 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Set; 022 023import org.forgerock.i18n.slf4j.LocalizedLogger; 024import org.opends.server.replication.common.AssuredMode; 025import org.opends.server.replication.common.CSN; 026import org.opends.server.replication.protocol.AckMsg; 027 028/** 029 * This class holds every info needed about the expected acks for a received 030 * update message requesting assured replication with Safe Data sub-mode. 031 * It also includes info/routines for constructing the final ack to be sent to 032 * the sender of the update message. 033 */ 034public class SafeDataExpectedAcksInfo extends ExpectedAcksInfo 035{ 036 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 037 038 /** Requested level of safe data when the update message was received. */ 039 private byte safeDataLevel = -1; 040 041 /** 042 * Number of received acks for the matching update message, up to now Already 043 * set to 1 as the local RS receiving the message from a DS counts. 044 */ 045 private byte numReceivedAcks = 1; 046 047 /** 048 * Creates a new SafeDataExpectedAcksInfo. 049 * @param csn The CSN of the assured update message 050 * @param requesterServerHandler The server that sent the assured update 051 * message 052 * @param safeDataLevel The Safe Data level requested for the assured 053 * update message 054 * @param expectedServers The list of servers we want an ack from 055 */ 056 public SafeDataExpectedAcksInfo(CSN csn, 057 ServerHandler requesterServerHandler, byte safeDataLevel, 058 List<Integer> expectedServers) 059 { 060 super(csn, requesterServerHandler, AssuredMode.SAFE_DATA_MODE, 061 expectedServers); 062 this.safeDataLevel = safeDataLevel; 063 } 064 065 /** {@inheritDoc} */ 066 @Override 067 public boolean processReceivedAck(ServerHandler ackingServer, AckMsg ackMsg) 068 { 069 /* 070 * Security: although a DS should not respond to an update message sent to 071 * him with assured safe data mode, we double check here that the ack sender 072 * is a RS to take the ack into account. 073 */ 074 if (ackingServer.isDataServer()) 075 { 076 // Sanity check: this should never happen 077 if (logger.isTraceEnabled()) 078 { 079 logger.trace("Received unexpected SD ack from DS id: " 080 + ackingServer.getServerId() + " ack message: " + ackMsg); 081 } 082 return false; 083 } 084 085 // Get the ack status for the matching server 086 int ackingServerId = ackingServer.getServerId(); 087 boolean ackReceived = expectedServersAckStatus.get(ackingServerId); 088 if (ackReceived) 089 { 090 // Sanity check: this should never happen 091 if (logger.isTraceEnabled()) 092 { 093 logger.trace("Received unexpected ack from server id: " + 094 ackingServerId + " ack message: " + ackMsg); 095 } 096 return false; 097 } else 098 { 099 // Mark this ack received for the server 100 expectedServersAckStatus.put(ackingServerId, true); 101 numReceivedAcks++; 102 return numReceivedAcks == safeDataLevel; 103 } 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public AckMsg createAck(boolean timeout) 109 { 110 AckMsg ack = new AckMsg(csn); 111 112 if (timeout) 113 { 114 // Fill collected errors info 115 ack.setHasTimeout(true); 116 // Tell which servers did not send an ack in time 117 List<Integer> failedServers = new ArrayList<>(); 118 Set<Integer> serverIds = expectedServersAckStatus.keySet(); 119 serversInTimeout = new ArrayList<>(); // Use next loop to fill it 120 for (Integer serverId : serverIds) 121 { 122 boolean ackReceived = expectedServersAckStatus.get(serverId); 123 if (!ackReceived) 124 { 125 failedServers.add(serverId); 126 serversInTimeout.add(serverId); 127 } 128 } 129 ack.setFailedServers(failedServers); 130 } 131 132 return ack; 133 } 134}