OPENDJ-1116 Introduce abstraction for the changelog DB
Changes after review from Matthew Swift.
Renamed CNIndexRecord to ChangeNumberIndexRecord to be consistent with ChangeNumberIndexDB name.
1 files renamed
8 files modified
| | |
| | | import org.opends.server.replication.common.ServerState; |
| | | import org.opends.server.replication.common.ServerStatus; |
| | | import org.opends.server.replication.protocol.*; |
| | | import org.opends.server.replication.server.changelog.api.CNIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangeNumberIndexDB; |
| | | 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.*; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.util.ServerConstants; |
| | | |
| | |
| | | private String operationId; |
| | | |
| | | /** Cursor on the {@link ChangeNumberIndexDB}. */ |
| | | private DBCursor<CNIndexRecord> cnIndexDBCursor; |
| | | private DBCursor<ChangeNumberIndexRecord> cnIndexDBCursor; |
| | | |
| | | private boolean draftCompat = false; |
| | | /** |
| | |
| | | { |
| | | // Request filter DOES NOT contain any start change number |
| | | // So we'll generate from the oldest change number in the CNIndexDB |
| | | final CNIndexRecord oldestRecord = cnIndexDB.getOldestRecord(); |
| | | final ChangeNumberIndexRecord oldestRecord = cnIndexDB.getOldestRecord(); |
| | | if (oldestRecord == null) |
| | | { // DB is empty or closed |
| | | isEndOfCNIndexDBReached = true; |
| | |
| | | // Request filter DOES contain a startChangeNumber |
| | | |
| | | // Read the CNIndexDB to see whether it contains startChangeNumber |
| | | DBCursor<CNIndexRecord> cursor = cnIndexDB.getCursorFrom(startChangeNumber); |
| | | final CNIndexRecord startRecord = cursor.getRecord(); |
| | | DBCursor<ChangeNumberIndexRecord> cursor = |
| | | cnIndexDB.getCursorFrom(startChangeNumber); |
| | | final ChangeNumberIndexRecord startRecord = cursor.getRecord(); |
| | | if (startRecord != null) |
| | | { |
| | | // found the provided startChangeNumber, let's return it |
| | |
| | | if (startChangeNumber < oldestChangeNumber) |
| | | { |
| | | cursor = cnIndexDB.getCursorFrom(oldestChangeNumber); |
| | | final CNIndexRecord oldestRecord = cursor.getRecord(); |
| | | final ChangeNumberIndexRecord oldestRecord = cursor.getRecord(); |
| | | if (oldestRecord == null) |
| | | { |
| | | // This should not happen |
| | |
| | | { |
| | | // startChangeNumber is between oldest and potential newest and has never |
| | | // been returned yet |
| | | final CNIndexRecord newestRecord = cnIndexDB.getNewestRecord(); |
| | | final ChangeNumberIndexRecord newestRecord = cnIndexDB.getNewestRecord(); |
| | | if (newestRecord == null) |
| | | { |
| | | isEndOfCNIndexDBReached = true; |
| | |
| | | throw new DirectoryException(ResultCode.SUCCESS, Message.raw("")); |
| | | } |
| | | |
| | | private DBCursor<CNIndexRecord> getCursorFrom(ChangeNumberIndexDB cnIndexDB, |
| | | long startChangeNumber) throws ChangelogException |
| | | private DBCursor<ChangeNumberIndexRecord> getCursorFrom( |
| | | ChangeNumberIndexDB cnIndexDB, long startChangeNumber) |
| | | throws ChangelogException |
| | | { |
| | | DBCursor<CNIndexRecord> cursor = cnIndexDB.getCursorFrom(startChangeNumber); |
| | | DBCursor<ChangeNumberIndexRecord> cursor = |
| | | cnIndexDB.getCursorFrom(startChangeNumber); |
| | | if (cursor.getRecord() == null) |
| | | { |
| | | close(cursor); |
| | |
| | | return true; |
| | | } |
| | | |
| | | final CNIndexRecord currentRecord = cnIndexDBCursor.getRecord(); |
| | | final ChangeNumberIndexRecord currentRecord = cnIndexDBCursor.getRecord(); |
| | | final CSN csnFromCNIndexDB = currentRecord.getCSN(); |
| | | final DN dnFromCNIndexDB = currentRecord.getBaseDN(); |
| | | |
| | |
| | | private void assignNewChangeNumberAndStore(ECLUpdateMsg change) |
| | | throws ChangelogException |
| | | { |
| | | final CNIndexRecord record = new CNIndexRecord(previousCookie.toString(), |
| | | change.getBaseDN(), change.getUpdateMsg().getCSN()); |
| | | final ChangeNumberIndexRecord record = |
| | | new ChangeNumberIndexRecord(previousCookie.toString(), |
| | | change.getBaseDN(), change.getUpdateMsg().getCSN()); |
| | | // store in CNIndexDB the pair |
| | | // (change number of the current change, state before this change) |
| | | change.setChangeNumber( |
| | |
| | | import org.opends.server.replication.common.*; |
| | | import org.opends.server.replication.plugin.MultimasterReplication; |
| | | import org.opends.server.replication.protocol.*; |
| | | import org.opends.server.replication.server.changelog.api.CNIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangeNumberIndexDB; |
| | | import org.opends.server.replication.server.changelog.api.ChangelogDB; |
| | | import org.opends.server.replication.server.changelog.api.ChangelogException; |
| | | import org.opends.server.replication.server.changelog.api.*; |
| | | import org.opends.server.replication.server.changelog.je.JEChangelogDB; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.util.LDIFReader; |
| | |
| | | try |
| | | { |
| | | final ChangeNumberIndexDB cnIndexDB = getChangeNumberIndexDB(); |
| | | final CNIndexRecord oldestRecord = cnIndexDB.getOldestRecord(); |
| | | final CNIndexRecord newestRecord = cnIndexDB.getNewestRecord(); |
| | | final ChangeNumberIndexRecord oldestRecord = cnIndexDB.getOldestRecord(); |
| | | final ChangeNumberIndexRecord newestRecord = cnIndexDB.getNewestRecord(); |
| | | |
| | | boolean dbEmpty = true; |
| | | long oldestChangeNumber = 0; |
| | |
| | | { |
| | | // There are records in the CNIndexDB (so already returned to clients) |
| | | // BUT |
| | | // There is nothing related to this domain in the newest CNIndexRecord |
| | | // There is nothing related to this domain in the newest record |
| | | // (maybe this domain was disabled when this record was returned). |
| | | // In that case, are counted the changes from the time of the most |
| | | // recent change |
| | |
| | | |
| | | /** |
| | | * This class stores an index of all the changes seen by this server in the form |
| | | * of {@link CNIndexRecord}s. The records are sorted by a global ordering as |
| | | * defined in the CSN class. The index links a <code>changeNumber</code> to the |
| | | * corresponding CSN. The CSN then links to a corresponding change in one of the |
| | | * ReplicaDBs. |
| | | * of {@link ChangeNumberIndexRecord}s. The records are sorted by a global |
| | | * ordering as defined in the CSN class. The index links a |
| | | * <code>changeNumber</code> to the corresponding CSN. The CSN then links to a |
| | | * corresponding change in one of the ReplicaDBs. |
| | | * |
| | | * @see <a href= |
| | | * "https://wikis.forgerock.org/confluence/display/OPENDJ/OpenDJ+Domain+Names" |
| | |
| | | /** |
| | | * Get the oldest record stored in this DB. |
| | | * |
| | | * @return Returns the oldest {@link CNIndexRecord} in this DB, null when the |
| | | * DB is empty or closed |
| | | * @return Returns the oldest {@link ChangeNumberIndexRecord} in this DB, null |
| | | * when the DB is empty or closed |
| | | * @throws ChangelogException |
| | | * if a database problem occurs. |
| | | */ |
| | | CNIndexRecord getOldestRecord() throws ChangelogException; |
| | | ChangeNumberIndexRecord getOldestRecord() throws ChangelogException; |
| | | |
| | | /** |
| | | * Get the newest record stored in this DB. |
| | | * |
| | | * @return Returns the newest {@link CNIndexRecord} in this DB, null when the |
| | | * DB is empty or closed |
| | | * @return Returns the newest {@link ChangeNumberIndexRecord} in this DB, null |
| | | * when the DB is empty or closed |
| | | * @throws ChangelogException |
| | | * if a database problem occurs. |
| | | */ |
| | | CNIndexRecord getNewestRecord() throws ChangelogException; |
| | | ChangeNumberIndexRecord getNewestRecord() throws ChangelogException; |
| | | |
| | | /** |
| | | * Add an update to the list of messages that must be saved to this DB managed |
| | |
| | | * for lazily building the ChangeNumberIndexDB. |
| | | * |
| | | * @param record |
| | | * The {@link CNIndexRecord} to add to this DB. |
| | | * The {@link ChangeNumberIndexRecord} to add to this DB. |
| | | * @return the change number associated to this record on adding to this DB |
| | | * @throws ChangelogException |
| | | * if a database problem occurs. |
| | | */ |
| | | long addRecord(CNIndexRecord record) throws ChangelogException; |
| | | long addRecord(ChangeNumberIndexRecord record) throws ChangelogException; |
| | | |
| | | /** |
| | | * Generate a new {@link DBCursor} that allows to browse the db managed by |
| | |
| | | * @throws ChangelogException |
| | | * if a database problem occurs. |
| | | */ |
| | | DBCursor<CNIndexRecord> getCursorFrom(long startChangeNumber) |
| | | DBCursor<ChangeNumberIndexRecord> getCursorFrom(long startChangeNumber) |
| | | throws ChangelogException; |
| | | |
| | | } |
| File was renamed from opends/src/server/org/opends/server/replication/server/changelog/api/CNIndexRecord.java |
| | |
| | | import org.opends.server.types.DN; |
| | | |
| | | /** |
| | | * The Change Number Index Data class represents records stored in the |
| | | * The Change Number Index Record class represents records stored in the |
| | | * {@link ChangeNumberIndexDB}. |
| | | */ |
| | | public final class CNIndexRecord |
| | | public final class ChangeNumberIndexRecord |
| | | { |
| | | |
| | | /** This is the key used to store the rest of the . */ |
| | |
| | | * @param csn |
| | | * the replication CSN field |
| | | */ |
| | | public CNIndexRecord(long changeNumber, String previousCookie, DN baseDN, |
| | | CSN csn) |
| | | public ChangeNumberIndexRecord(long changeNumber, String previousCookie, |
| | | DN baseDN, CSN csn) |
| | | { |
| | | this.changeNumber = changeNumber; |
| | | this.previousCookie = previousCookie; |
| | |
| | | * the baseDN |
| | | * @param csn |
| | | * the replication CSN field |
| | | * @see #CNIndexRecord(long, String, DN, CSN) |
| | | * @see #ChangeNumberIndexRecord(long, String, DN, CSN) |
| | | */ |
| | | public CNIndexRecord(String previousCookie, DN baseDN, CSN csn) |
| | | public ChangeNumberIndexRecord(String previousCookie, DN baseDN, CSN csn) |
| | | { |
| | | this(0, previousCookie, baseDN, csn); |
| | | } |
| | |
| | | |
| | | import org.opends.messages.MessageBuilder; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.replication.server.changelog.api.CNIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangelogException; |
| | | import org.opends.server.replication.server.changelog.api.*; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | |
| | | import com.sleepycat.je.*; |
| | |
| | | * Add a record to the database. |
| | | * |
| | | * @param record |
| | | * the provided {@link CNIndexRecord} to be stored. |
| | | * the provided {@link ChangeNumberIndexRecord} to be stored. |
| | | */ |
| | | public void addRecord(CNIndexRecord record) |
| | | public void addRecord(ChangeNumberIndexRecord record) |
| | | { |
| | | try |
| | | { |
| | |
| | | * @throws ChangelogException |
| | | * if a database problem occurred |
| | | */ |
| | | public CNIndexRecord readFirstRecord() throws ChangelogException |
| | | public ChangeNumberIndexRecord readFirstRecord() throws ChangelogException |
| | | { |
| | | try |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private CNIndexRecord newCNIndexRecord(ReplicationDraftCNKey key, |
| | | private ChangeNumberIndexRecord newCNIndexRecord(ReplicationDraftCNKey key, |
| | | DatabaseEntry data) throws ChangelogException |
| | | { |
| | | return new DraftCNData(key.getChangeNumber(), data.getData()).getRecord(); |
| | |
| | | * @throws ChangelogException |
| | | * if a database problem occurred |
| | | */ |
| | | public CNIndexRecord readLastRecord() throws ChangelogException |
| | | public ChangeNumberIndexRecord readLastRecord() throws ChangelogException |
| | | { |
| | | try |
| | | { |
| | |
| | | private final Transaction txn; |
| | | private final ReplicationDraftCNKey key; |
| | | private final DatabaseEntry entry = new DatabaseEntry(); |
| | | private CNIndexRecord record; |
| | | private ChangeNumberIndexRecord record; |
| | | private boolean isClosed = false; |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the {@link CNIndexRecord} at the current position of the cursor. |
| | | * Returns the {@link ChangeNumberIndexRecord} at the current position of |
| | | * the cursor. |
| | | * |
| | | * @return The current {@link CNIndexRecord}. |
| | | * @return The current {@link ChangeNumberIndexRecord}. |
| | | */ |
| | | public CNIndexRecord currentRecord() |
| | | public ChangeNumberIndexRecord currentRecord() |
| | | { |
| | | if (isClosed) |
| | | { |
| | |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.replication.common.CSN; |
| | | import org.opends.server.replication.server.changelog.api.CNIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangelogException; |
| | | import org.opends.server.replication.server.changelog.api.*; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | |
| | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | private long changeNumber; |
| | | private CNIndexRecord record; |
| | | private ChangeNumberIndexRecord record; |
| | | |
| | | /** |
| | | * Creates a record to be stored in the DraftCNDB. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Decode and returns a {@link CNIndexRecord}. |
| | | * Decode and returns a {@link ChangeNumberIndexRecord}. |
| | | * |
| | | * @param changeNumber |
| | | * @param data |
| | | * the provided byte array. |
| | | * @return the decoded {@link CNIndexRecord} |
| | | * @return the decoded {@link ChangeNumberIndexRecord} |
| | | * @throws ChangelogException |
| | | * when a problem occurs. |
| | | */ |
| | | private CNIndexRecord decodeData(long changeNumber, byte[] data) |
| | | private ChangeNumberIndexRecord decodeData(long changeNumber, byte[] data) |
| | | throws ChangelogException |
| | | { |
| | | try |
| | |
| | | String stringData = new String(data, "UTF-8"); |
| | | String[] str = stringData.split(FIELD_SEPARATOR, 3); |
| | | final DN baseDN = DN.decode(str[1]); |
| | | return new CNIndexRecord(changeNumber, str[0], baseDN, new CSN(str[2])); |
| | | final CSN csn = new CSN(str[2]); |
| | | return new ChangeNumberIndexRecord(changeNumber, str[0], baseDN, csn); |
| | | } |
| | | catch (UnsupportedEncodingException e) |
| | | { |
| | |
| | | /** |
| | | * Getter for the decoded record. |
| | | * |
| | | * @return the {@link CNIndexRecord} record. |
| | | * @return the {@link ChangeNumberIndexRecord} record. |
| | | * @throws ChangelogException |
| | | * when a problem occurs. |
| | | */ |
| | | public CNIndexRecord getRecord() throws ChangelogException |
| | | public ChangeNumberIndexRecord getRecord() throws ChangelogException |
| | | { |
| | | if (record == null) |
| | | record = decodeData(changeNumber, getData()); |
| | |
| | | |
| | | // DB initialization |
| | | db = new DraftCNDB(dbenv); |
| | | final CNIndexRecord oldestRecord = db.readFirstRecord(); |
| | | final CNIndexRecord newestRecord = db.readLastRecord(); |
| | | final ChangeNumberIndexRecord oldestRecord = db.readFirstRecord(); |
| | | final ChangeNumberIndexRecord newestRecord = db.readLastRecord(); |
| | | oldestChangeNumber = getChangeNumber(oldestRecord); |
| | | newestChangeNumber = getChangeNumber(newestRecord); |
| | | // initialization of the lastGeneratedChangeNumber from the DB content |
| | |
| | | trimmingThread.start(); |
| | | } |
| | | |
| | | private long getChangeNumber(CNIndexRecord record) throws ChangelogException |
| | | private long getChangeNumber(ChangeNumberIndexRecord record) |
| | | throws ChangelogException |
| | | { |
| | | if (record != null) |
| | | { |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public long addRecord(CNIndexRecord record) throws ChangelogException |
| | | public long addRecord(ChangeNumberIndexRecord record) |
| | | throws ChangelogException |
| | | { |
| | | long changeNumber = nextChangeNumber(); |
| | | final CNIndexRecord newRecord = |
| | | new CNIndexRecord(changeNumber, record.getPreviousCookie(), record |
| | | .getBaseDN(), record.getCSN()); |
| | | final ChangeNumberIndexRecord newRecord = |
| | | new ChangeNumberIndexRecord(changeNumber, record.getPreviousCookie(), |
| | | record.getBaseDN(), record.getCSN()); |
| | | db.addRecord(newRecord); |
| | | |
| | | if (debugEnabled()) |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public CNIndexRecord getOldestRecord() throws ChangelogException |
| | | public ChangeNumberIndexRecord getOldestRecord() throws ChangelogException |
| | | { |
| | | return db.readFirstRecord(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public CNIndexRecord getNewestRecord() throws ChangelogException |
| | | public ChangeNumberIndexRecord getNewestRecord() throws ChangelogException |
| | | { |
| | | return db.readLastRecord(); |
| | | } |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DBCursor<CNIndexRecord> getCursorFrom(long startChangeNumber) |
| | | public DBCursor<ChangeNumberIndexRecord> getCursorFrom(long startChangeNumber) |
| | | throws ChangelogException |
| | | { |
| | | return new JEChangeNumberIndexDBCursor(db, startChangeNumber); |
| | |
| | | return; |
| | | } |
| | | |
| | | final CNIndexRecord record = cursor.currentRecord(); |
| | | final ChangeNumberIndexRecord record = cursor.currentRecord(); |
| | | if (baseDNToClear != null && baseDNToClear.equals(record.getBaseDN())) |
| | | { |
| | | cursor.delete(); |
| | |
| | | { |
| | | try |
| | | { |
| | | CNIndexRecord record = |
| | | final ChangeNumberIndexRecord record = |
| | | isFirst ? db.readFirstRecord() : db.readLastRecord(); |
| | | if (record != null) |
| | | { |
| | |
| | | * This class allows to iterate through the changes received from a given |
| | | * LDAP Server Identifier. |
| | | */ |
| | | public class JEChangeNumberIndexDBCursor implements DBCursor<CNIndexRecord> |
| | | public class JEChangeNumberIndexDBCursor implements |
| | | DBCursor<ChangeNumberIndexRecord> |
| | | { |
| | | private static final DebugTracer TRACER = getTracer(); |
| | | private DraftCNDBCursor draftCNDbCursor; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public CNIndexRecord getRecord() |
| | | public ChangeNumberIndexRecord getRecord() |
| | | { |
| | | try |
| | | { |
| | |
| | | import org.opends.server.replication.common.CSN; |
| | | import org.opends.server.replication.server.ReplServerFakeConfiguration; |
| | | import org.opends.server.replication.server.ReplicationServer; |
| | | import org.opends.server.replication.server.changelog.api.CNIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangeNumberIndexRecord; |
| | | import org.opends.server.replication.server.changelog.api.ChangelogException; |
| | | import org.opends.server.replication.server.changelog.api.DBCursor; |
| | | import org.opends.server.types.DN; |
| | |
| | | CSN[] csns = newCSNs(1, 0, 3); |
| | | |
| | | // Add records |
| | | long cn1 = cnIndexDB.addRecord(new CNIndexRecord(value1, baseDN1, csns[0])); |
| | | cnIndexDB.addRecord(new CNIndexRecord(value2, baseDN2, csns[1])); |
| | | long cn3 = cnIndexDB.addRecord(new CNIndexRecord(value3, baseDN3, csns[2])); |
| | | long cn1 = addRecord(cnIndexDB, value1, baseDN1, csns[0]); |
| | | addRecord(cnIndexDB, value2, baseDN2, csns[1]); |
| | | long cn3 = addRecord(cnIndexDB, value3, baseDN3, csns[2]); |
| | | |
| | | // The ChangeNumber should not get purged |
| | | final long oldestCN = cnIndexDB.getOldestRecord().getChangeNumber(); |
| | | assertEquals(oldestCN, cn1); |
| | | assertEquals(cnIndexDB.getNewestRecord().getChangeNumber(), cn3); |
| | | |
| | | DBCursor<CNIndexRecord> cursor = cnIndexDB.getCursorFrom(oldestCN); |
| | | DBCursor<ChangeNumberIndexRecord> cursor = cnIndexDB.getCursorFrom(oldestCN); |
| | | try |
| | | { |
| | | assertEqualTo(cursor.getRecord(), csns[0], baseDN1, value1); |
| | |
| | | } |
| | | } |
| | | |
| | | private void assertEqualTo(CNIndexRecord record, CSN csn, DN baseDN, String cookie) |
| | | private long addRecord(JEChangeNumberIndexDB cnIndexDB, String cookie, DN baseDN, CSN csn) |
| | | throws ChangelogException |
| | | { |
| | | return cnIndexDB.addRecord(new ChangeNumberIndexRecord(cookie, baseDN, csn)); |
| | | } |
| | | |
| | | private void assertEqualTo(ChangeNumberIndexRecord record, CSN csn, DN baseDN, String cookie) |
| | | { |
| | | assertEquals(record.getCSN(), csn); |
| | | assertEquals(record.getBaseDN(), baseDN); |
| | |
| | | CSN[] csns = newCSNs(1, 0, 3); |
| | | |
| | | // Add records |
| | | long cn1 = cnIndexDB.addRecord(new CNIndexRecord(value1, baseDN1, csns[0])); |
| | | long cn2 = cnIndexDB.addRecord(new CNIndexRecord(value2, baseDN2, csns[1])); |
| | | long cn3 = cnIndexDB.addRecord(new CNIndexRecord(value3, baseDN3, csns[2])); |
| | | long cn1 = addRecord(cnIndexDB, value1, baseDN1, csns[0]); |
| | | long cn2 = addRecord(cnIndexDB, value2, baseDN2, csns[1]); |
| | | long cn3 = addRecord(cnIndexDB, value3, baseDN3, csns[2]); |
| | | |
| | | // Checks |
| | | assertEquals(cnIndexDB.getOldestRecord().getChangeNumber(), cn1); |
| | |
| | | assertEquals(getPreviousCookie(cnIndexDB, cn2), value2); |
| | | assertEquals(getPreviousCookie(cnIndexDB, cn3), value3); |
| | | |
| | | DBCursor<CNIndexRecord> cursor = cnIndexDB.getCursorFrom(cn1); |
| | | DBCursor<ChangeNumberIndexRecord> cursor = cnIndexDB.getCursorFrom(cn1); |
| | | assertCursorReadsInOrder(cursor, cn1, cn2, cn3); |
| | | |
| | | cursor = cnIndexDB.getCursorFrom(cn2); |
| | |
| | | private String getPreviousCookie(JEChangeNumberIndexDB cnIndexDB, |
| | | long changeNumber) throws Exception |
| | | { |
| | | DBCursor<CNIndexRecord> cursor = cnIndexDB.getCursorFrom(changeNumber); |
| | | DBCursor<ChangeNumberIndexRecord> cursor = cnIndexDB.getCursorFrom(changeNumber); |
| | | try |
| | | { |
| | | return cursor.getRecord().getPreviousCookie(); |
| | |
| | | } |
| | | } |
| | | |
| | | private void assertCursorReadsInOrder(DBCursor<CNIndexRecord> cursor, |
| | | private void assertCursorReadsInOrder(DBCursor<ChangeNumberIndexRecord> cursor, |
| | | long... cns) throws ChangelogException |
| | | { |
| | | try |