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}