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