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