/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2014-2015 ForgeRock AS */ package org.opends.server.replication.server.changelog.file; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.ConcurrentSkipListMap; import org.opends.server.replication.common.CSN; import org.opends.server.replication.protocol.UpdateMsg; import org.opends.server.replication.server.changelog.api.ChangelogException; import org.opends.server.replication.server.changelog.api.DBCursor; import org.opends.server.replication.server.changelog.api.ReplicationDomainDB; import org.opends.server.types.DN; /** * Cursor iterating over a replication domain's replica DBs. * * \@NotThreadSafe */ public class DomainDBCursor extends CompositeDBCursor<Void> { /** Replaces null CSNs in ConcurrentSkipListMap that does not support null values. */ private static final CSN NULL_CSN = new CSN(0, 0, 0); private final DN baseDN; private final ReplicationDomainDB domainDB; private final ConcurrentSkipListMap<Integer, CSN> newReplicas = new ConcurrentSkipListMap<>(); private final CursorOptions options; /** * Builds a DomainDBCursor instance. * * @param baseDN * the replication domain baseDN of this cursor * @param domainDB * the DB for the provided replication domain * @param options The cursor options */ public DomainDBCursor(final DN baseDN, final ReplicationDomainDB domainDB, CursorOptions options) { this.baseDN = baseDN; this.domainDB = domainDB; this.options = options; } /** * Returns the replication domain baseDN of this cursor. * * @return the replication domain baseDN of this cursor. */ public DN getBaseDN() { return baseDN; } /** * Adds a replicaDB for this cursor to iterate over. Added cursors will be * created and iterated over on the next call to {@link #next()}. * * @param serverId * the serverId of the replica * @param startCSN * the CSN to use as a starting point */ public void addReplicaDB(int serverId, CSN startCSN) { // only keep the oldest CSN that will be the new cursor's starting point newReplicas.putIfAbsent(serverId, startCSN != null ? startCSN : NULL_CSN); } /** {@inheritDoc} */ @Override protected void incorporateNewCursors() throws ChangelogException { for (Iterator<Entry<Integer, CSN>> iter = newReplicas.entrySet().iterator(); iter.hasNext();) { final Entry<Integer, CSN> pair = iter.next(); final int serverId = pair.getKey(); final CSN csn = pair.getValue(); final CSN startCSN = !NULL_CSN.equals(csn) ? csn : null; final DBCursor<UpdateMsg> cursor = domainDB.getCursorFrom(baseDN, serverId, startCSN, options); addCursor(cursor, null); iter.remove(); } } /** {@inheritDoc} */ @Override public void close() { super.close(); domainDB.unregisterCursor(this); newReplicas.clear(); } }