This fix resolves an issue with replication between Windows and Unix systems. The GenerationID was different on the systems for the same input due to differences in line separators and an inappropriate exception handling.
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | private long checksum = 0L; |
| | | |
| | | /** |
| | | * This is the generation id for an empty backend. |
| | | */ |
| | | public static final long EMPTY_BACKEND_GENERATION_ID = 48L; |
| | | |
| | | /** |
| | | * Update the checksum with one added byte. |
| | | */ |
| | | private void updateWithOneByte(byte b) |
| | | { |
| | | checksum += (long) b; |
| | | /** |
| | | * The "end of line" code is CRLF under windows but LF on UNIX. So to get |
| | | * the same checksum value on every platforms, we always exclude the CR and |
| | | * LF characters from the computation. |
| | | */ |
| | | if ((b != 0x0D) && (b != 0x0A)) // CR=0D and LF=0A |
| | | { |
| | | checksum += (long) b; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | public long getValue() |
| | | { |
| | | return checksum; |
| | | if (checksum != 0L) |
| | | { |
| | | return checksum; |
| | | } else |
| | | { |
| | | // Computing an empty backend writes the number of entries (0) only, which |
| | | // will not be added to the checksum as no entries will follow. To treat |
| | | // this special case, and to keep consistency with old versions, in that |
| | | // case we hardcode and return the generation id value for an empty |
| | | // backend. |
| | | return EMPTY_BACKEND_GENERATION_ID; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | import java.util.concurrent.BlockingQueue; |
| | | import java.util.concurrent.TimeoutException; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.zip.CheckedOutputStream; |
| | | import java.util.zip.DataFormatException; |
| | | |
| | | import org.opends.messages.Message; |
| | |
| | | { |
| | | long genID = 0; |
| | | Backend backend = retrievesBackend(this.baseDn); |
| | | long bec = backend.numSubordinates(baseDn, true) + 1; |
| | | long entryCount = (bec<1000?bec:1000); |
| | | long numberOfEntries = backend.numSubordinates(baseDn, true) + 1; |
| | | long entryCount = ( (numberOfEntries < 1000 )? numberOfEntries : 1000); |
| | | |
| | | // Acquire a shared lock for the backend. |
| | | try |
| | |
| | | ResultCode.OTHER, message, null); |
| | | } |
| | | |
| | | OutputStream os; |
| | | OutputStream os = null; |
| | | ReplLDIFOutputStream ros = null; |
| | | |
| | | if (checksumOutput) |
| | | { |
| | | ros = new ReplLDIFOutputStream(this, entryCount); |
| | | os = new CheckedOutputStream(ros, new GenerationIdChecksum()); |
| | | os = (OutputStream)new ReplLDIFOutputStream(entryCount); |
| | | ros = (ReplLDIFOutputStream)os; |
| | | try |
| | | { |
| | | os.write((Long.toString(backend.numSubordinates(baseDn, true) + 1)). |
| | | os.write((Long.toString(numberOfEntries)). |
| | | getBytes()); |
| | | } |
| | | catch(Exception e) |
| | |
| | | |
| | | if (checksumOutput) |
| | | { |
| | | genID = |
| | | ((CheckedOutputStream)os).getChecksum().getValue(); |
| | | genID = ros.getChecksumValue(); |
| | | } |
| | | |
| | | // Release the shared lock on the backend. |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | import java.io.IOException; |
| | | import java.io.OutputStream; |
| | | |
| | | import org.opends.server.replication.service.ReplicationDomain; |
| | | import org.opends.server.util.ServerConstants; |
| | | |
| | | /** |
| | | * This class creates an output stream that can be used to export entries |
| | | * to a synchonization domain. |
| | | * to a synchronization domain. |
| | | */ |
| | | public class ReplLDIFOutputStream |
| | | extends OutputStream |
| | | { |
| | | // The synchronization domain on which the export is done |
| | | ReplicationDomain domain; |
| | | |
| | | // The number of entries to be exported |
| | | long numEntries; |
| | | |
| | |
| | | private long numExportedEntries; |
| | | String entryBuffer = ""; |
| | | |
| | | // The checksum for computing the generation id |
| | | private GenerationIdChecksum checkSum = new GenerationIdChecksum(); |
| | | |
| | | /** |
| | | * Creates a new ReplLDIFOutputStream related to a replication |
| | | * domain. |
| | | * |
| | | * @param domain The replication domain |
| | | * @param numEntries The max number of entry to process. |
| | | */ |
| | | public ReplLDIFOutputStream(ReplicationDomain domain, long numEntries) |
| | | public ReplLDIFOutputStream(long numEntries) |
| | | { |
| | | this.domain = domain; |
| | | this.numEntries = numEntries; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Get the value of the underlying checksum. |
| | | * @return The value of the underlying checksum |
| | | */ |
| | | public long getChecksumValue() |
| | | { |
| | | return checkSum.getValue(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void write(byte b[], int off, int len) throws IOException |
| | |
| | | throw(new IOException()); |
| | | } |
| | | |
| | | // Add the entry bytes to the checksum |
| | | byte[] entryBytes = entryBuffer.getBytes(); |
| | | checkSum.update(entryBytes, 0, entryBytes.length); |
| | | |
| | | numExportedEntries++; |
| | | entryBuffer = ""; |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2007-2009 Sun Microsystems, Inc. |
| | | * Copyright 2007-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.replication; |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | private final long CLEAN_DB_GENERATION_ID = 7933L; |
| | | private final long CLEAN_DB_GENERATION_ID = 7883L; |
| | | /** |
| | | * Clean the database and replace with a single entry. |
| | | * |
| | |
| | | import java.util.SortedSet; |
| | | import java.util.TreeSet; |
| | | |
| | | import org.opends.messages.Category; |
| | | import org.opends.messages.Message; |
| | | import org.opends.messages.Severity; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.ConnectionHandler; |
| | |
| | | import org.testng.annotations.AfterClass; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.Test; |
| | | import static org.opends.server.loggers.ErrorLogger.logError; |
| | | |
| | | |
| | | /** |
| | |
| | | |
| | | try |
| | | { |
| | | // create 2 reguler brokers on the 2 suffixes |
| | | // create 2 regular brokers on the 2 suffixes |
| | | server01 = openReplicationSession( |
| | | DN.decode(TEST_ROOT_DN_STRING), 1201, |
| | | 100, replicationServerPort, |
| | |
| | | makeBrokerPublishEntries(server2, server2ID, server1ID, server2ID); |
| | | |
| | | // wait until the replication domain has expected generationID |
| | | // this should indicate that the import occured correctly. |
| | | // this should indicate that the import occurred correctly. |
| | | final long EXPECTED_GENERATION_ID = 52955L; |
| | | long readGenerationId = -1L; |
| | | for (int count = 0; count < 120; count++) |
| | | { |
| | | if (replDomain.getGenerationID() == 53235) |
| | | readGenerationId = replDomain.getGenerationID(); |
| | | if ( readGenerationId == EXPECTED_GENERATION_ID) |
| | | break; |
| | | log(testCase + " genId=" + replDomain.getGenerationID()); |
| | | log(testCase + " genId=" + readGenerationId); |
| | | Thread.sleep(1000); |
| | | } |
| | | |
| | | if (replDomain.getGenerationID() != 53235) |
| | | if (readGenerationId != EXPECTED_GENERATION_ID) |
| | | { |
| | | fail(testCase + " Import success waited longer than expected \n" + |
| | | TestCaseUtils.threadStacksToString()); |
| | | } |
| | | |
| | | |
| | | // Test that entries have been imported in S1 |
| | | testEntriesInDb(); |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.replication; |
| | | |
| | |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.replication.common.ServerState; |
| | | import org.opends.server.replication.plugin.GenerationIdChecksum; |
| | | import org.opends.server.replication.plugin.LDAPReplicationDomain; |
| | | import org.opends.server.replication.plugin.MultimasterReplication; |
| | | import org.opends.server.replication.plugin.PersistentServerState; |
| | |
| | | // This matches the backend obtained calling: |
| | | // TestCaseUtils.initializeTestBackend(true). |
| | | // (using the default TestCaseUtils.TEST_ROOT_DN_STRING suffix) |
| | | protected static final long TEST_DN_WITH_ROOT_ENTRY_GENID = 5095L; |
| | | protected static final long TEST_DN_WITH_ROOT_ENTRY_GENID = 5055L; |
| | | |
| | | /** |
| | | * Generation id for a fully empty domain. |
| | | */ |
| | | public static final long EMPTY_DN_GENID = 48L; |
| | | public static final long EMPTY_DN_GENID = GenerationIdChecksum.EMPTY_BACKEND_GENERATION_ID; |
| | | |
| | | /** |
| | | * The internal connection used for operation |
| | |
| | | /** |
| | | * Retrieves the domain associated to the baseDn, and the value of the generationId |
| | | * of this domain. If the domain does not exist, returns the default hard-coded\ |
| | | * value of the generationId corresponding to 'no entry'. |
| | | * value of the generationId corresponding to test backend with its default |
| | | * initial o=test root root entry. |
| | | * |
| | | * @param baseDn The baseDn for which we want the generationId |
| | | * @return The value of the generationId. |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.replication.plugin; |
| | | |
| | |
| | | GenerationIdChecksum checksum = new GenerationIdChecksum(); |
| | | |
| | | // Default value test |
| | | assertEquals(checksum.getValue(), 0L); |
| | | assertEquals(checksum.getValue(), GenerationIdChecksum.EMPTY_BACKEND_GENERATION_ID); |
| | | |
| | | // Update method simple version test |
| | | checksum.update(3); |
| | |
| | | |
| | | // Reset test |
| | | checksum.reset(); |
| | | assertEquals(checksum.getValue(), 0L); |
| | | assertEquals(checksum.getValue(), GenerationIdChecksum.EMPTY_BACKEND_GENERATION_ID); |
| | | |
| | | // Update method simple version test, again |
| | | checksum.update(101); |
| | |
| | | protected Object[][] arrayUpdateProvider() |
| | | { |
| | | return new Object[][] { |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 10, 55}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 10, 45}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 1, 1}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 2, 3}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0, 3, 6}, |
| | |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3, 3, 15}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 1, 8}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 2, 17}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 3, 27}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 9, 1, 10}, |
| | | {new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 0, 10, 65}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 3, 17}, |
| | | {new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 9, 2, 11}, |
| | | {new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 0, 10, 55}, |
| | | {new byte[]{118, 119, 120, 121, 122, 123, 124, 125, 126, 127}, 0, 10, 1225}}; |
| | | } |
| | | |