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