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 2013-2016 ForgeRock AS. 015 */ 016package org.opends.server.replication.server; 017 018import java.util.HashSet; 019import java.util.Map; 020import java.util.Set; 021import java.util.concurrent.ConcurrentSkipListMap; 022 023import net.jcip.annotations.ThreadSafe; 024 025import org.opends.server.replication.common.CSN; 026import org.opends.server.replication.common.MultiDomainServerState; 027import org.forgerock.opendj.ldap.DN; 028 029/** 030 * This is the changelog state stored in the changelogStateDB. For each 031 * replication domain, it contains: 032 * <ul> 033 * <li>its generationId</li> 034 * <li>the list of serverIds composing it</li> 035 * </ul> 036 * <p> 037 * This class is used during replication initialization to decouple the code 038 * that reads the changelogStateDB from the code that makes use of its data. 039 */ 040@ThreadSafe 041public class ChangelogState 042{ 043 private final ConcurrentSkipListMap<DN, Long> domainToGenerationId = new ConcurrentSkipListMap<>(); 044 private final ConcurrentSkipListMap<DN, Set<Integer>> domainToServerIds = new ConcurrentSkipListMap<>(); 045 private final MultiDomainServerState offlineReplicas = new MultiDomainServerState(); 046 047 /** 048 * Sets the generationId for the supplied replication domain. 049 * 050 * @param baseDN 051 * the targeted replication domain baseDN 052 * @param generationId 053 * the generation Id to set 054 */ 055 public void setDomainGenerationId(DN baseDN, long generationId) 056 { 057 domainToGenerationId.put(baseDN, generationId); 058 } 059 060 /** 061 * Adds the serverId to the serverIds list of the supplied replication domain. 062 * 063 * @param serverId 064 * the serverId to add 065 * @param baseDN 066 * the targeted replication domain baseDN 067 */ 068 public void addServerIdToDomain(int serverId, DN baseDN) 069 { 070 Set<Integer> serverIds = domainToServerIds.get(baseDN); 071 if (serverIds == null) 072 { 073 serverIds = new HashSet<>(); 074 final Set<Integer> existingServerIds = 075 domainToServerIds.putIfAbsent(baseDN, serverIds); 076 if (existingServerIds != null) 077 { 078 serverIds = existingServerIds; 079 } 080 } 081 serverIds.add(serverId); 082 } 083 084 /** 085 * Adds the following replica information to the offline list. 086 * 087 * @param baseDN 088 * the baseDN of the offline replica 089 * @param offlineCSN 090 * the CSN (serverId + timestamp) of the offline replica 091 */ 092 public void addOfflineReplica(DN baseDN, CSN offlineCSN) 093 { 094 offlineReplicas.update(baseDN, offlineCSN); 095 } 096 097 /** 098 * Removes the following replica information from the offline list. 099 * 100 * @param baseDN 101 * the baseDN of the offline replica 102 * @param serverId 103 * the serverId that is not offline anymore 104 */ 105 public void removeOfflineReplica(DN baseDN, int serverId) 106 { 107 CSN csn; 108 do 109 { 110 csn = offlineReplicas.getCSN(baseDN, serverId); 111 } 112 while (csn != null && !offlineReplicas.removeCSN(baseDN, csn)); 113 } 114 115 /** 116 * Returns the Map of domainBaseDN => generationId. 117 * 118 * @return a Map of domainBaseDN => generationId 119 */ 120 public Map<DN, Long> getDomainToGenerationId() 121 { 122 return domainToGenerationId; 123 } 124 125 /** 126 * Returns the Map of domainBaseDN => List<serverId>. 127 * 128 * @return a Map of domainBaseDN => List<serverId>. 129 */ 130 public Map<DN, Set<Integer>> getDomainToServerIds() 131 { 132 return domainToServerIds; 133 } 134 135 /** 136 * Returns the internal MultiDomainServerState for offline replicas. 137 * 138 * @return the MultiDomainServerState for offline replicas. 139 */ 140 public MultiDomainServerState getOfflineReplicas() 141 { 142 return offlineReplicas; 143 } 144 145 /** 146 * Returns whether the current ChangelogState is equal to the provided 147 * ChangelogState. 148 * <p> 149 * Note: Only use for tests!!<br> 150 * This method should only be used by tests because it creates a lot of 151 * intermediate objects which is not suitable for production. 152 * 153 * @param other 154 * the ChangelogState to compare with 155 * @return true if the current ChangelogState is equal to the provided 156 * ChangelogState, false otherwise. 157 */ 158 public boolean isEqualTo(ChangelogState other) 159 { 160 if (other == null) 161 { 162 return false; 163 } 164 if (this == other) 165 { 166 return true; 167 } 168 return domainToGenerationId.equals(other.domainToGenerationId) 169 && domainToServerIds.equals(other.domainToServerIds) 170 // Note: next line is not suitable for production 171 // because it creates lots of Lists and Maps 172 && offlineReplicas.getSnapshot().equals(other.offlineReplicas.getSnapshot()); 173 } 174 175 /** {@inheritDoc} */ 176 @Override 177 public String toString() 178 { 179 return "domainToGenerationId=" + domainToGenerationId 180 + ", domainToServerIds=" + domainToServerIds 181 + ", offlineReplicas=" + offlineReplicas; 182 } 183}