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 *      Copyright 2014-2015 ForgeRock AS
024 */
025package org.opends.server.replication.server.changelog.file;
026
027import java.util.Iterator;
028import java.util.Map.Entry;
029import java.util.concurrent.ConcurrentSkipListMap;
030
031import org.opends.server.replication.common.CSN;
032import org.opends.server.replication.protocol.UpdateMsg;
033import org.opends.server.replication.server.changelog.api.ChangelogException;
034import org.opends.server.replication.server.changelog.api.DBCursor;
035import org.opends.server.replication.server.changelog.api.ReplicationDomainDB;
036import org.opends.server.types.DN;
037
038/**
039 * Cursor iterating over a replication domain's replica DBs.
040 *
041 * \@NotThreadSafe
042 */
043public class DomainDBCursor extends CompositeDBCursor<Void>
044{
045  /** Replaces null CSNs in ConcurrentSkipListMap that does not support null values. */
046  private static final CSN NULL_CSN = new CSN(0, 0, 0);
047
048  private final DN baseDN;
049  private final ReplicationDomainDB domainDB;
050  private final ConcurrentSkipListMap<Integer, CSN> newReplicas = new ConcurrentSkipListMap<>();
051  private final CursorOptions options;
052
053  /**
054   * Builds a DomainDBCursor instance.
055   *
056   * @param baseDN
057   *          the replication domain baseDN of this cursor
058   * @param domainDB
059   *          the DB for the provided replication domain
060   * @param options The cursor options
061   */
062  public DomainDBCursor(final DN baseDN, final ReplicationDomainDB domainDB, CursorOptions options)
063  {
064    this.baseDN = baseDN;
065    this.domainDB = domainDB;
066    this.options = options;
067  }
068
069  /**
070   * Returns the replication domain baseDN of this cursor.
071   *
072   * @return the replication domain baseDN of this cursor.
073   */
074  public DN getBaseDN()
075  {
076    return baseDN;
077  }
078
079  /**
080   * Adds a replicaDB for this cursor to iterate over. Added cursors will be
081   * created and iterated over on the next call to {@link #next()}.
082   *
083   * @param serverId
084   *          the serverId of the replica
085   * @param startCSN
086   *          the CSN to use as a starting point
087   */
088  public void addReplicaDB(int serverId, CSN startCSN)
089  {
090    // only keep the oldest CSN that will be the new cursor's starting point
091    newReplicas.putIfAbsent(serverId, startCSN != null ? startCSN : NULL_CSN);
092  }
093
094  /** {@inheritDoc} */
095  @Override
096  protected void incorporateNewCursors() throws ChangelogException
097  {
098    for (Iterator<Entry<Integer, CSN>> iter = newReplicas.entrySet().iterator(); iter.hasNext();)
099    {
100      final Entry<Integer, CSN> pair = iter.next();
101      final int serverId = pair.getKey();
102      final CSN csn = pair.getValue();
103      final CSN startCSN = !NULL_CSN.equals(csn) ? csn : null;
104      final DBCursor<UpdateMsg> cursor = domainDB.getCursorFrom(baseDN, serverId, startCSN, options);
105      addCursor(cursor, null);
106      iter.remove();
107    }
108  }
109
110  /** {@inheritDoc} */
111  @Override
112  public void close()
113  {
114    super.close();
115    domainDB.unregisterCursor(this);
116    newReplicas.clear();
117  }
118
119}