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}