| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; |
| | |
| | | import org.opends.server.api.DirectoryThread; |
| | | import org.opends.server.api.SynchronizationProvider; |
| | | import org.opends.server.backends.task.Task; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.*; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchListener; |
| | |
| | | import org.opends.server.protocols.ldap.LDAPControl; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.protocols.ldap.LDAPModification; |
| | | import org.opends.server.replication.common.*; |
| | | import org.opends.server.replication.common.CSN; |
| | | import org.opends.server.replication.common.ServerState; |
| | | import org.opends.server.replication.common.ServerStatus; |
| | | import org.opends.server.replication.common.StatusMachineEvent; |
| | | import org.opends.server.replication.protocol.*; |
| | | import org.opends.server.replication.service.ReplicationBroker; |
| | | import org.opends.server.replication.service.ReplicationDomain; |
| | | import org.opends.server.tasks.PurgeConflictsHistoricalTask; |
| | | import org.opends.server.tasks.TaskUtils; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.Attributes; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.RDN; |
| | | import org.opends.server.types.operation.*; |
| | | import org.opends.server.util.LDIFReader; |
| | | import org.opends.server.util.TimeThread; |
| | |
| | | /** The number of unresolved naming conflicts. */ |
| | | private final AtomicInteger numUnresolvedNamingConflicts = |
| | | new AtomicInteger(); |
| | | private final PersistentServerState state; |
| | | /** The number of updates replayed successfully by the replication. */ |
| | | private final AtomicInteger numReplayedPostOpCalled = new AtomicInteger(); |
| | | |
| | | private final PersistentServerState state; |
| | | private volatile boolean generationIdSavedStatus = false; |
| | | |
| | | private final CSNGenerator generator; |
| | | |
| | | /** |
| | | * This object is used to store the list of update currently being |
| | | * done on the local database. |
| | |
| | | new AtomicReference<RSUpdater>(null); |
| | | |
| | | /** |
| | | * It contain the updates that were done on other servers, transmitted |
| | | * by the replication server and that are currently replayed. |
| | | * It is useful to make sure that dependencies between operations |
| | | * are correctly fulfilled and to to make sure that the ServerState is |
| | | * not updated too early. |
| | | * It contain the updates that were done on other servers, transmitted by the |
| | | * replication server and that are currently replayed. |
| | | * <p> |
| | | * It is useful to make sure that dependencies between operations are |
| | | * correctly fulfilled and to make sure that the ServerState is not updated |
| | | * too early. |
| | | */ |
| | | private final RemotePendingChanges remotePendingChanges; |
| | | private boolean solveConflictFlag = true; |
| | |
| | | * The generator time is adjusted to the time of the last CSN received from |
| | | * remote other servers. |
| | | */ |
| | | generator = getGenerator(); |
| | | |
| | | pendingChanges = new PendingChanges(generator, this); |
| | | pendingChanges = new PendingChanges(getGenerator(), this); |
| | | remotePendingChanges = new RemotePendingChanges(getServerState()); |
| | | |
| | | // listen for changes on the configuration |
| | |
| | | private SearchResultEntry findReplicationSearchResultEntry( |
| | | InternalSearchOperation searchOperation) |
| | | { |
| | | if (searchOperation.getResultCode() != ResultCode.SUCCESS) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | List<SearchResultEntry> result = searchOperation.getSearchEntries(); |
| | | SearchResultEntry resultEntry = result.get(0); |
| | | final SearchResultEntry resultEntry = getFirstResult(searchOperation); |
| | | if (resultEntry != null) |
| | | { |
| | | AttributeType synchronizationGenIDType = |
| | |
| | | * another entry. |
| | | * We must not let the change proceed, return a negative |
| | | * result and set the result code to NO_SUCH_OBJECT. |
| | | * When the operation will return, the thread that started the |
| | | * operation will try to find the correct entry and restart a new |
| | | * operation. |
| | | * When the operation will return, the thread that started the operation |
| | | * will try to find the correct entry and restart a new operation. |
| | | */ |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | | ResultCode.NO_SUCH_OBJECT, null); |
| | |
| | | 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectclass=*)"), |
| | | attrs); |
| | | |
| | | if (search.getResultCode() == ResultCode.SUCCESS) |
| | | final SearchResultEntry resultEntry = getFirstResult(search); |
| | | if (resultEntry != null) |
| | | { |
| | | final List<SearchResultEntry> result = search.getSearchEntries(); |
| | | if (!result.isEmpty()) |
| | | { |
| | | final SearchResultEntry resultEntry = result.get(0); |
| | | if (resultEntry != null) |
| | | { |
| | | return getEntryUUID(resultEntry); |
| | | } |
| | | } |
| | | return getEntryUUID(resultEntry); |
| | | } |
| | | } catch (DirectoryException e) |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | // never happens because the filter is always valid. |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private static SearchResultEntry getFirstResult(InternalSearchOperation search) |
| | | { |
| | | if (search.getResultCode() == ResultCode.SUCCESS) |
| | | { |
| | | final LinkedList<SearchResultEntry> results = search.getSearchEntries(); |
| | | if (!results.isEmpty()) |
| | | { |
| | | return results.getFirst(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * find the current DN of an entry from its entry UUID. |
| | | * |
| | |
| | | InternalSearchOperation search = conn.processSearch(getBaseDN(), |
| | | SearchScope.WHOLE_SUBTREE, |
| | | SearchFilter.createFilterFromString("entryuuid="+uuid)); |
| | | if (search.getResultCode() == ResultCode.SUCCESS) |
| | | final SearchResultEntry resultEntry = getFirstResult(search); |
| | | if (resultEntry != null) |
| | | { |
| | | final List<SearchResultEntry> results = search.getSearchEntries(); |
| | | if (!results.isEmpty()) |
| | | { |
| | | final SearchResultEntry resultEntry = results.get(0); |
| | | if (resultEntry != null) |
| | | { |
| | | return resultEntry.getName(); |
| | | } |
| | | } |
| | | return resultEntry.getName(); |
| | | } |
| | | } catch (DirectoryException e) |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | // never happens because the filter is always valid. |
| | | } |
| | |
| | | |
| | | if (op.getResultCode() == ResultCode.SUCCESS) |
| | | { |
| | | List<SearchResultEntry> entries = op.getSearchEntries(); |
| | | if (entries != null) |
| | | for (SearchResultEntry entry : op.getSearchEntries()) |
| | | { |
| | | for (SearchResultEntry entry : entries) |
| | | { |
| | | /* |
| | | * Check the ADD and ModRDN date of the child entry (All of them, |
| | | * not only the one that are newer than the DEL op) |
| | | * and keep the entry as a conflicting entry, |
| | | */ |
| | | conflict = true; |
| | | renameConflictEntry(conflictOp, entry.getName(), getEntryUUID(entry)); |
| | | } |
| | | /* |
| | | * Check the ADD and ModRDN date of the child entry |
| | | * (All of them, not only the one that are newer than the DEL op) |
| | | * and keep the entry as a conflicting entry. |
| | | */ |
| | | conflict = true; |
| | | renameConflictEntry(conflictOp, entry.getName(), getEntryUUID(entry)); |
| | | } |
| | | } |
| | | else |
| | |
| | | { |
| | | state.clearInMemory(); |
| | | state.loadState(); |
| | | getGenerator().adjust(state.getMaxCSN(getServerId())); |
| | | |
| | | generator.adjust(state.getMaxCSN(getServerId())); |
| | | // Retrieves the generation ID associated with the data imported |
| | | |
| | | generationId = loadGenerationId(); |
| | | } |
| | | |
| | |
| | | { |
| | | // Expand @objectclass references in attribute list if needed. |
| | | // We do this now in order to take into account dynamic schema changes. |
| | | Set<String> expandedNames = getExpandedNames(names); |
| | | |
| | | Entry filteredEntry = |
| | | final Set<String> expandedNames = getExpandedNames(names); |
| | | final Entry filteredEntry = |
| | | entry.filterEntry(expandedNames, false, false, false); |
| | | return filteredEntry.getAttributes(); |
| | | } |