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&lt;serverId&gt;.
136   *
137   * @return a Map of domainBaseDN => List&lt;serverId&gt;.
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}