| | |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.DirectoryThread; |
| | | import org.opends.server.api.SynchronizationProvider; |
| | | import org.opends.server.backends.jeb.BackendImpl; |
| | | import org.opends.server.backends.task.Task; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.*; |
| | |
| | | * Log an error for the repair tool |
| | | * that will need to re-synchronize the servers. |
| | | */ |
| | | message = ERR_CANNOT_RECOVER_CHANGES.get( |
| | | baseDn.toNormalizedString()); |
| | | message = ERR_CANNOT_RECOVER_CHANGES.get(baseDn.toNormalizedString()); |
| | | logError(message); |
| | | } |
| | | } catch (Exception e) |
| | |
| | | * Log an error for the repair tool |
| | | * that will need to re-synchronize the servers. |
| | | */ |
| | | message = ERR_CANNOT_RECOVER_CHANGES.get( |
| | | baseDn.toNormalizedString()); |
| | | message = ERR_CANNOT_RECOVER_CHANGES.get(baseDn.toNormalizedString()); |
| | | logError(message); |
| | | } |
| | | finally |
| | |
| | | * the last CSN seen from all LDAP servers in the topology. |
| | | */ |
| | | state = new PersistentServerState(baseDn, serverId, getServerState()); |
| | | |
| | | flushThread = new ServerStateFlush(); |
| | | |
| | | /* |
| | |
| | | */ |
| | | generator = getGenerator(); |
| | | |
| | | pendingChanges = |
| | | new PendingChanges(generator, this); |
| | | |
| | | pendingChanges = new PendingChanges(generator, this); |
| | | remotePendingChanges = new RemotePendingChanges(getServerState()); |
| | | |
| | | // listen for changes on the configuration |
| | |
| | | return false; |
| | | } |
| | | |
| | | /* |
| | | * Search the domain root entry that is used to save the generation id |
| | | */ |
| | | // Search the domain root entry that is used to save the generation id |
| | | ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString()); |
| | | Set<String> attributes = new LinkedHashSet<String>(3); |
| | | attributes.add(REPLICATION_GENERATION_ID); |
| | |
| | | * Compare configuration stored in passed fractional configuration |
| | | * attributes with local variable one |
| | | */ |
| | | |
| | | try |
| | | { |
| | | return FractionalConfig. |
| | |
| | | |
| | | // Create a list of filtered attributes for this entry |
| | | Entry concernedEntry = modifyDNOperation.getOriginalEntry(); |
| | | List<String> fractionalConcernedAttributes = |
| | | Set<String> fractionalConcernedAttributes = |
| | | createFractionalConcernedAttrList(fractionalConfig, |
| | | concernedEntry.getObjectClasses().keySet()); |
| | | |
| | |
| | | } |
| | | boolean attributeToBeFiltered = (fractionalExclusive && found) |
| | | || (!fractionalExclusive && !found); |
| | | if (attributeToBeFiltered && |
| | | !newRdn.hasAttributeType(attributeType) && |
| | | !modifyDNOperation.deleteOldRDN()) |
| | | if (attributeToBeFiltered |
| | | && !newRdn.hasAttributeType(attributeType) |
| | | && !modifyDNOperation.deleteOldRDN()) |
| | | { |
| | | /* |
| | | * A forbidden attribute is in the old RDN and no more in the new RDN, |
| | |
| | | * fractional replication configuration |
| | | */ |
| | | |
| | | List<String> fractionalConcernedAttributes = |
| | | Set<String> fractionalConcernedAttributes = |
| | | createFractionalConcernedAttrList(fractionalConfig, classes.keySet()); |
| | | boolean fractionalExclusive = fractionalConfig.isFractionalExclusive(); |
| | | if (fractionalExclusive && fractionalConcernedAttributes.isEmpty()) |
| | |
| | | } |
| | | |
| | | private static boolean canRemoveAttribute(AttributeType attributeType, |
| | | boolean fractionalExclusive, List<String> fractionalConcernedAttributes) |
| | | boolean fractionalExclusive, Set<String> fractionalConcernedAttributes) |
| | | { |
| | | String attributeName = attributeType.getPrimaryName(); |
| | | String attributeOid = attributeType.getOID(); |
| | |
| | | || (!foundAttribute && !fractionalExclusive); |
| | | } |
| | | |
| | | private static boolean contains(List<String> fractionalConcernedAttributes, |
| | | private static boolean contains(Set<String> fractionalConcernedAttributes, |
| | | String attributeName, String attributeOid) |
| | | { |
| | | final boolean foundAttribute = |
| | |
| | | * @return The list of attributes of the entry to be excluded/included |
| | | * when the operation will be performed. |
| | | */ |
| | | private static List<String> createFractionalConcernedAttrList( |
| | | private static Set<String> createFractionalConcernedAttrList( |
| | | FractionalConfig fractionalConfig, Set<ObjectClass> entryObjectClasses) |
| | | { |
| | | /* |
| | | * Is the concerned entry of a type concerned by fractional replication |
| | | * configuration ? If yes, add the matching attribute names to a list of |
| | | * configuration ? If yes, add the matching attribute names to a set of |
| | | * attributes to take into account for filtering |
| | | * (inclusive or exclusive mode) |
| | | * (inclusive or exclusive mode). |
| | | * Using a Set to avoid duplicate attributes (from 2 inheriting classes for |
| | | * instance) |
| | | */ |
| | | |
| | | List<String> fractionalConcernedAttributes = new ArrayList<String>(); |
| | | Set<String> fractionalConcernedAttributes = new HashSet<String>(); |
| | | |
| | | // Get object classes the entry matches |
| | | List<String> fractionalAllClassesAttributes = |
| | |
| | | { |
| | | if (entryObjectClass.hasNameOrOID(fractionalClass.toLowerCase())) |
| | | { |
| | | List<String> attrList = |
| | | fractionalSpecificClassesAttributes.get(fractionalClass); |
| | | for(String attr : attrList) |
| | | { |
| | | // Avoid duplicate attributes (from 2 inheriting classes for |
| | | // instance) |
| | | if (!fractionalConcernedAttributes.contains(attr)) |
| | | { |
| | | fractionalConcernedAttributes.add(attr); |
| | | } |
| | | } |
| | | fractionalConcernedAttributes.addAll( |
| | | fractionalSpecificClassesAttributes.get(fractionalClass)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * Add to the list any attribute which is class independent |
| | | */ |
| | | for (String attr : fractionalAllClassesAttributes) |
| | | { |
| | | if (!fractionalConcernedAttributes.contains(attr)) |
| | | { |
| | | fractionalConcernedAttributes.add(attr); |
| | | } |
| | | } |
| | | // Add to the set any attribute which is class independent |
| | | fractionalConcernedAttributes.addAll(fractionalAllClassesAttributes); |
| | | |
| | | return fractionalConcernedAttributes; |
| | | } |
| | |
| | | */ |
| | | |
| | | Entry modifiedEntry = modifyOperation.getCurrentEntry(); |
| | | List<String> fractionalConcernedAttributes = |
| | | Set<String> fractionalConcernedAttributes = |
| | | createFractionalConcernedAttrList(fractionalConfig, |
| | | modifiedEntry.getObjectClasses().keySet()); |
| | | boolean fractionalExclusive = fractionalConfig.isFractionalExclusive(); |
| | |
| | | // found, return immediately the answer; |
| | | return FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES; |
| | | } |
| | | else |
| | | |
| | | // Found a modification to remove, remove it from the list. |
| | | modsIt.remove(); |
| | | result = FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES; |
| | | if (mods.isEmpty()) |
| | | { |
| | | // Found a modification to remove, remove it from the list. |
| | | modsIt.remove(); |
| | | result = FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES; |
| | | if (mods.isEmpty()) |
| | | { |
| | | // This operation must become a no-op as no more modification in it |
| | | return FRACTIONAL_BECOME_NO_OP; |
| | | } |
| | | // This operation must become a no-op as no more modification in it |
| | | return FRACTIONAL_BECOME_NO_OP; |
| | | } |
| | | } |
| | | |
| | |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | | ResultCode.NO_SUCH_OBJECT, null); |
| | | } |
| | | else |
| | | |
| | | DN entryDN = addOperation.getEntryDN(); |
| | | DN parentDnFromEntryDn = entryDN.getParentDNInSuffix(); |
| | | if (parentDnFromEntryDn != null |
| | | && !parentDnFromCtx.equals(parentDnFromEntryDn)) |
| | | { |
| | | DN entryDN = addOperation.getEntryDN(); |
| | | DN parentDnFromEntryDn = entryDN.getParentDNInSuffix(); |
| | | if (parentDnFromEntryDn != null |
| | | && !parentDnFromCtx.equals(parentDnFromEntryDn)) |
| | | { |
| | | // parentEntry has been renamed |
| | | // replication name conflict resolution is expected to fix that |
| | | // later in the flow |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | | ResultCode.NO_SUCH_OBJECT, null); |
| | | } |
| | | // parentEntry has been renamed |
| | | // replication name conflict resolution is expected to fix that |
| | | // later in the flow |
| | | return new SynchronizationProviderResult.StopProcessing( |
| | | ResultCode.NO_SUCH_OBJECT, null); |
| | | } |
| | | } |
| | | } |
| | |
| | | * 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); |
| | | } |
| | | |
| | | if (modifyDNOperation.getNewSuperior() != null) |
| | | { |
| | | /* |
| | |
| | | ResultCode.NO_SUCH_OBJECT, null); |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * If the object has been renamed more recently than this |
| | | * operation, cancel the operation. |
| | |
| | | LDAPFilter filter = LDAPFilter.createEqualityFilter(DS_SYNC_CONFLICT, |
| | | ByteString.valueOf(freedDN.toString())); |
| | | |
| | | Set<String> attrs = new LinkedHashSet<String>(1); |
| | | attrs.add(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME); |
| | | attrs.add(EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME); |
| | | attrs.add("*"); |
| | | Set<String> attrs = allOperationalAttributes(); |
| | | InternalSearchOperation searchOp = conn.processSearch( |
| | | ByteString.valueOf(baseDn.toString()), |
| | | SearchScope.WHOLE_SUBTREE, |
| | |
| | | * @return generationId The retrieved value of generationId |
| | | * @throws DirectoryException When an error occurs. |
| | | */ |
| | | private long loadGenerationId() |
| | | throws DirectoryException |
| | | private long loadGenerationId() throws DirectoryException |
| | | { |
| | | long aGenerationId=-1; |
| | | |
| | | if (debugEnabled()) |
| | | TRACER.debugInfo("Attempt to read generation ID from DB " + baseDn); |
| | | |
| | | ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString()); |
| | | boolean found = false; |
| | | LDAPFilter filter; |
| | | try |
| | | { |
| | |
| | | * Search the database entry that is used to periodically |
| | | * save the generation id |
| | | */ |
| | | ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString()); |
| | | Set<String> attributes = new LinkedHashSet<String>(1); |
| | | attributes.add(REPLICATION_GENERATION_ID); |
| | | InternalSearchOperation search = conn.processSearch(asn1BaseDn, |
| | |
| | | filter,attributes); |
| | | if (search.getResultCode() == ResultCode.NO_SUCH_OBJECT) |
| | | { |
| | | // FIXME JNR Am I dreaming, or next code is doing exactly the same thing |
| | | // as code before if statement? |
| | | |
| | | // if the base entry does not exist look for the generationID |
| | | // in the config entry. |
| | | asn1BaseDn = ByteString.valueOf(baseDn.toString()); |
| | |
| | | DereferencePolicy.DEREF_ALWAYS, 0, 0, false, |
| | | filter,attributes); |
| | | } |
| | | |
| | | boolean found = false; |
| | | long aGenerationId = -1; |
| | | if (search.getResultCode() != ResultCode.SUCCESS) |
| | | { |
| | | if (search.getResultCode() != ResultCode.NO_SUCH_OBJECT) |
| | |
| | | * Total Update >> |
| | | */ |
| | | |
| | | |
| | | |
| | | /** |
| | | * Clears all the entries from the JE backend determined by the |
| | | * be id passed into the method. |
| | | * |
| | | * @param createBaseEntry Indicate whether to automatically create the base |
| | | * entry and add it to the backend. |
| | | * @param beID The be id to clear. |
| | | * @param dn The suffix of the backend to create if the the createBaseEntry |
| | | * boolean is true. |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | public static void clearJEBackend(boolean createBaseEntry, String beID, |
| | | String dn) throws Exception |
| | | { |
| | | BackendImpl backend = (BackendImpl)DirectoryServer.getBackend(beID); |
| | | |
| | | // FIXME Should setBackendEnabled be part of TaskUtils ? |
| | | TaskUtils.disableBackend(beID); |
| | | |
| | | try |
| | | { |
| | | String lockFile = LockFileManager.getBackendLockFileName(backend); |
| | | StringBuilder failureReason = new StringBuilder(); |
| | | |
| | | if (!LockFileManager.acquireExclusiveLock(lockFile, failureReason)) |
| | | { |
| | | throw new RuntimeException(failureReason.toString()); |
| | | } |
| | | |
| | | try |
| | | { |
| | | backend.clearBackend(); |
| | | } |
| | | finally |
| | | { |
| | | LockFileManager.releaseLock(lockFile, failureReason); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | TaskUtils.enableBackend(beID); |
| | | } |
| | | |
| | | if (createBaseEntry) |
| | | { |
| | | DN baseDN = DN.decode(dn); |
| | | Entry e = createEntry(baseDN); |
| | | backend = (BackendImpl)DirectoryServer.getBackend(beID); |
| | | backend.addEntry(e, null); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * This method trigger an export of the replicated data. |
| | | * |
| | |
| | | * |
| | | * @throws DirectoryException when an error occurred |
| | | */ |
| | | protected long exportBackend(OutputStream output, boolean checksumOutput) |
| | | throws DirectoryException |
| | | private long exportBackend(OutputStream output, boolean checksumOutput) |
| | | throws DirectoryException |
| | | { |
| | | long genID = 0; |
| | | Backend backend = retrievesBackend(this.baseDn); |
| | | long numberOfEntries = backend.numSubordinates(baseDn, true) + 1; |
| | | long entryCount = Math.min(numberOfEntries, 1000); |
| | | |
| | | // Acquire a shared lock for the backend. |
| | | try |
| | |
| | | Message message = ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get( |
| | | backend.getBackendID(), String.valueOf(failureReason)); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get( |
| | | backend.getBackendID(), e.getLocalizedMessage()); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | |
| | | long numberOfEntries = backend.numSubordinates(baseDn, true) + 1; |
| | | long entryCount = Math.min(numberOfEntries, 1000); |
| | | OutputStream os; |
| | | ReplLDIFOutputStream ros = null; |
| | | |
| | | if (checksumOutput) |
| | | { |
| | | ros = new ReplLDIFOutputStream(entryCount); |
| | |
| | | { |
| | | os = output; |
| | | } |
| | | LDIFExportConfig exportConfig = new LDIFExportConfig(os); |
| | | |
| | | // baseDn branch is the only one included in the export |
| | | List<DN> includeBranches = new ArrayList<DN>(1); |
| | | includeBranches.add(this.baseDn); |
| | | LDIFExportConfig exportConfig = new LDIFExportConfig(os); |
| | | exportConfig.setIncludeBranches(includeBranches); |
| | | |
| | | // For the checksum computing mode, only consider the 'stable' attributes |
| | |
| | | } |
| | | |
| | | // Launch the export. |
| | | long genID = 0; |
| | | try |
| | | { |
| | | backend.exportLDIF(exportConfig); |
| | |
| | | Message message = |
| | | ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(de.getMessageObject()); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | Message message = ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get( |
| | | stackTraceToSingleLineString(e)); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | finally |
| | | { |
| | |
| | | Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get( |
| | | backend.getBackendID(), String.valueOf(failureReason)); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get( |
| | | backend.getBackendID(), stackTraceToSingleLineString(e)); |
| | | logError(message); |
| | | throw new DirectoryException( |
| | | ResultCode.OTHER, message, null); |
| | | throw new DirectoryException(ResultCode.OTHER, message, null); |
| | | } |
| | | } |
| | | return genID; |
| | |
| | | * @param backend The backend. |
| | | * @throws Exception |
| | | */ |
| | | private void preBackendImport(Backend backend) |
| | | throws Exception |
| | | private void preBackendImport(Backend backend) throws Exception |
| | | { |
| | | // Stop saving state |
| | | stateSavingDisabled = true; |
| | |
| | | Message message = ERR_INIT_IMPORT_NOT_SUPPORTED.get( |
| | | backend.getBackendID()); |
| | | if (ieContext.getException() == null) |
| | | ieContext.setException(new DirectoryException(ResultCode.OTHER, |
| | | message)); |
| | | ieContext.setException(new DirectoryException(OTHER, message)); |
| | | } |
| | | else |
| | | { |
| | |
| | | LDAPReplicationDomain replicationDomain = null; |
| | | |
| | | // Retrieves the domain |
| | | DirectoryServer.getSynchronizationProviders(); |
| | | for (SynchronizationProvider<?> provider : |
| | | DirectoryServer.getSynchronizationProviders()) |
| | | { |
| | | if (!( provider instanceof MultimasterReplication)) |
| | | { |
| | | Message message = ERR_INVALID_PROVIDER.get(); |
| | | throw new DirectoryException(ResultCode.OTHER, |
| | | message); |
| | | throw new DirectoryException(ResultCode.OTHER, message); |
| | | } |
| | | |
| | | // From the domainDN retrieves the replication domain |
| | |
| | | { |
| | | // Should never happen |
| | | Message message = ERR_MULTIPLE_MATCHING_DOMAIN.get(); |
| | | throw new DirectoryException(ResultCode.OTHER, |
| | | message); |
| | | throw new DirectoryException(ResultCode.OTHER, message); |
| | | } |
| | | replicationDomain = domain; |
| | | } |
| | |
| | | configuration.getHeartbeatInterval(), |
| | | (byte)configuration.getGroupId()); |
| | | |
| | | // Read assured configuration and reconnect if needed |
| | | // Read assured + fractional configuration and each time reconnect if needed |
| | | readAssuredConfig(configuration, true); |
| | | |
| | | // Read fractional configuration and reconnect if needed |
| | | readFractionalConfig(configuration, true); |
| | | |
| | | solveConflictFlag = isSolveConflict(configuration); |
| | |
| | | Iterator<CSN> it = replayOperations.keySet().iterator(); |
| | | while (it.hasNext()) |
| | | { |
| | | if (it.next().olderOrEqual(startCSN)) |
| | | { |
| | | it.remove(); |
| | | } |
| | | else |
| | | if (it.next().newer(startCSN)) |
| | | { |
| | | break; |
| | | } |
| | | it.remove(); |
| | | } |
| | | } |
| | | |
| | |
| | | do |
| | | { |
| | | lastRetrievedChange = null; |
| | | // We can't do the search in one go because we need to |
| | | // store the results so that we are sure we send the operations |
| | | // in order and because the list might be large |
| | | // So we search by interval of 10 seconds |
| | | // and store the results in the replayOperations list |
| | | // so that they are sorted before sending them. |
| | | // We can't do the search in one go because we need to store the results |
| | | // so that we are sure we send the operations in order and because the |
| | | // list might be large. |
| | | // So we search by interval of 10 seconds and store the results in the |
| | | // replayOperations list so that they are sorted before sending them. |
| | | long missingChangesDelta = currentStartCSN.getTime() + 10000; |
| | | CSN endCSN = new CSN(missingChangesDelta, 0xffffffff, serverId); |
| | | |
| | |
| | | while (itOp.hasNext()) |
| | | { |
| | | FakeOperation fakeOp = itOp.next(); |
| | | if (fakeOp.getCSN().olderOrEqual(endCSN) |
| | | && state.cover(fakeOp.getCSN())) |
| | | { |
| | | lastRetrievedChange = fakeOp.getCSN(); |
| | | opsToSend.add(fakeOp); |
| | | itOp.remove(); |
| | | } |
| | | else |
| | | if (fakeOp.getCSN().newer(endCSN) // sanity check |
| | | || !state.cover(fakeOp.getCSN())) |
| | | { |
| | | break; |
| | | } |
| | | |
| | | lastRetrievedChange = fakeOp.getCSN(); |
| | | opsToSend.add(fakeOp); |
| | | itOp.remove(); |
| | | } |
| | | } |
| | | |
| | |
| | | * @throws Exception |
| | | * when raised. |
| | | */ |
| | | public static InternalSearchOperation searchForChangedEntries(DN baseDn, |
| | | private static InternalSearchOperation searchForChangedEntries(DN baseDn, |
| | | CSN fromCSN, CSN lastCSN, InternalSearchListener resultListener) |
| | | throws Exception |
| | | { |
| | |
| | | "(&(" + HISTORICAL_ATTRIBUTE_NAME + ">=dummy:" + fromCSN + ")" + |
| | | "(" + HISTORICAL_ATTRIBUTE_NAME + "<=dummy:" + maxValueForId + "))"); |
| | | |
| | | Set<String> attrs = new LinkedHashSet<String>(3); |
| | | attrs.add(HISTORICAL_ATTRIBUTE_NAME); |
| | | attrs.add(ENTRYUUID_ATTRIBUTE_NAME); |
| | | attrs.add("*"); |
| | | Set<String> attrs = allOperationalAttributes(); |
| | | return conn.processSearch( |
| | | ByteString.valueOf(baseDn.toString()), |
| | | SearchScope.WHOLE_SUBTREE, |
| | |
| | | resultListener); |
| | | } |
| | | |
| | | private static Set<String> allOperationalAttributes() |
| | | { |
| | | Set<String> attrs = new LinkedHashSet<String>(3); |
| | | attrs.add(HISTORICAL_ATTRIBUTE_NAME); |
| | | attrs.add(ENTRYUUID_ATTRIBUTE_NAME); |
| | | attrs.add("*"); |
| | | return attrs; |
| | | } |
| | | |
| | | /** |
| | | * Search for the changes that happened since fromCSN based on the historical |
| | | * attribute. The only changes that will be send will be the one generated on |
| | |
| | | throw new ConfigException( |
| | | NOTE_ERR_FRACTIONAL_CONFIG_BOTH_MODES.get()); |
| | | } |
| | | else |
| | | { |
| | | fractionalMode = EXCLUSIVE_FRACTIONAL; |
| | | iterator = exclIt; |
| | | } |
| | | |
| | | fractionalMode = EXCLUSIVE_FRACTIONAL; |
| | | iterator = exclIt; |
| | | } |
| | | else |
| | | { |
| | |
| | | // Not possible. We know the filter just above is correct. |
| | | } |
| | | |
| | | Set<String> attrs = new LinkedHashSet<String>(3); |
| | | attrs.add(HISTORICAL_ATTRIBUTE_NAME); |
| | | attrs.add(ENTRYUUID_ATTRIBUTE_NAME); |
| | | attrs.add("*"); |
| | | Set<String> attrs = allOperationalAttributes(); |
| | | InternalSearchOperation searchOp = conn.processSearch( |
| | | ByteString.valueOf(baseDn.toString()), |
| | | SearchScope.WHOLE_SUBTREE, |