| | |
| | | final long markerPosition = searchClosestBlockStartToKey(key); |
| | | if (markerPosition >= 0) |
| | | { |
| | | return positionToKeySequentially(markerPosition, key, matchStrategy, positionStrategy); |
| | | return positionToKey(markerPosition, key, matchStrategy, positionStrategy); |
| | | } |
| | | return Pair.of(false, null); |
| | | } |
| | |
| | | |
| | | /** |
| | | * Position before, at or after provided key, starting from provided block |
| | | * start position and reading sequentially until key is found according to |
| | | * matching and positioning strategies. |
| | | * start position and reading until key is found according to matching and positioning strategies. |
| | | * |
| | | * @param blockStartPosition |
| | | * Position of read pointer in the file, expected to be the start of |
| | |
| | | * @throws ChangelogException |
| | | * If an error occurs. |
| | | */ |
| | | Pair<Boolean, Record<K,V>> positionToKeySequentially(final long blockStartPosition, final K key, |
| | | Pair<Boolean, Record<K,V>> positionToKey(final long blockStartPosition, final K key, |
| | | final KeyMatchingStrategy matchStrategy, final PositionStrategy positionStrategy) throws ChangelogException |
| | | { |
| | | Record<K,V> record = readRecord(blockStartPosition); |
| | | Record<K,V> previousRecord = null; |
| | | long previousPosition = blockStartPosition; |
| | | boolean matchingKeyIsLowerThanAnyRecord = true; |
| | | while (record != null) |
| | | { |
| | | final int keysComparison = record.getKey().compareTo(key); |
| | | if (keysComparison <= 0) |
| | | { |
| | | matchingKeyIsLowerThanAnyRecord = false; |
| | | } |
| | | if ((keysComparison == 0 && matchStrategy == EQUAL_TO_KEY) |
| | | || (keysComparison >= 0 && matchStrategy != EQUAL_TO_KEY)) |
| | | { |
| | | return getMatchingRecord(matchStrategy, positionStrategy, keysComparison, matchingKeyIsLowerThanAnyRecord, |
| | | record, previousRecord, previousPosition); |
| | | return getMatchingRecord( |
| | | matchStrategy, positionStrategy, keysComparison, record, previousRecord, previousPosition); |
| | | } |
| | | previousRecord = record; |
| | | previousPosition = getFilePosition(); |
| | |
| | | return Pair.of(false, null); |
| | | } |
| | | |
| | | private Pair<Boolean,Record<K,V>> getMatchingRecord(KeyMatchingStrategy matchStrategy, |
| | | PositionStrategy positionStrategy, int keysComparison, boolean matchKeyIsLowerThanAnyRecord, |
| | | Record<K, V> currentRecord, Record<K, V> previousRecord, long previousPosition) |
| | | throws ChangelogException |
| | | private Pair<Boolean, Record<K, V>> getMatchingRecord(KeyMatchingStrategy matchStrategy, |
| | | PositionStrategy positionStrategy, int keysComparison, Record<K, V> currentRecord, Record<K, V> previousRecord, |
| | | long previousPosition) throws ChangelogException |
| | | { |
| | | Record<K, V> record = currentRecord; |
| | | |
| | | if (positionStrategy == AFTER_MATCHING_KEY) |
| | | { |
| | | if (matchStrategy == LESS_THAN_OR_EQUAL_TO_KEY && matchKeyIsLowerThanAnyRecord) |
| | | { |
| | | return Pair.of(false, null); |
| | | } |
| | | if (keysComparison == 0) |
| | | { |
| | | // skip matching key |
| | |
| | | } |
| | | cursor = new AbortableLogCursor<K, V>(this, new InternalLogCursor<K, V>(this)); |
| | | final boolean isSuccessfullyPositioned = cursor.positionTo(key, matchingStrategy, positionStrategy); |
| | | // Allow for cursor re-initialization after exhaustion in case of GREATER_THAN_OR_EQUAL_TO_KEY strategy |
| | | if (isSuccessfullyPositioned || matchingStrategy == GREATER_THAN_OR_EQUAL_TO_KEY) |
| | | // Allow for cursor re-initialization after exhaustion in case of |
| | | // LESS_THAN_OR_EQUAL_TO_KEY ands GREATER_THAN_OR_EQUAL_TO_KEY strategies |
| | | if (isSuccessfullyPositioned || matchingStrategy != EQUAL_TO_KEY) |
| | | { |
| | | registerCursor(cursor); |
| | | return cursor; |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the oldest (first) record from this log. |
| | | * |
| | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | import org.assertj.core.api.SoftAssertions; |
| | | import org.forgerock.opendj.ldap.ByteSequenceReader; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | |
| | | { records(1,2,3), 3, LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, record(3), true }, |
| | | { records(1,2,3), 4, LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, record(3), true }, |
| | | |
| | | { records(1,2,3), 0, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, null, false }, |
| | | { records(1,2,3), 0, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(1), true }, |
| | | { records(1,2,3), 1, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(2), true }, |
| | | { records(1,2,3), 2, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(3), true }, |
| | | { records(1,2,3), 3, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, null, true }, |
| | |
| | | { records(1,2,3,4,5,6,7,8,9,10), 10, LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, record(10), true }, |
| | | { records(1,2,3,4,5,6,7,8,9,10), 11, LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, record(10), true }, |
| | | |
| | | { records(1,2,3,4,5,6,7,8,9,10), 0, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, null, false }, |
| | | { records(1,2,3,4,5,6,7,8,9,10), 0, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(1), true }, |
| | | { records(1,2,3,4,5,6,7,8,9,10), 1, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(2), true }, |
| | | { records(1,2,3,4,5,6,7,8,9,10), 5, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(6), true }, |
| | | { records(1,2,3,4,5,7,8,9,10), 6, LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, record(7), true }, |
| | |
| | | { |
| | | Pair<Boolean, Record<Integer, Integer>> result = reader.seekToRecord(key, matchingStrategy, positionStrategy); |
| | | |
| | | assertThat(result.getFirst()).isEqualTo(shouldBeFound); |
| | | assertThat(result.getSecond()).isEqualTo(expectedRecord); |
| | | final SoftAssertions softly = new SoftAssertions(); |
| | | softly.assertThat(result.getFirst()).isEqualTo(shouldBeFound); |
| | | softly.assertThat(result.getSecond()).isEqualTo(expectedRecord); |
| | | softly.assertAll(); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | long ts = System.nanoTime(); |
| | | Pair<Boolean, Record<Integer, Integer>> result = |
| | | reader.positionToKeySequentially(0, val, GREATER_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY); |
| | | reader.positionToKey(0, val, GREATER_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY); |
| | | assertThat(result.getSecond()).isEqualTo(Record.from(val, val)); |
| | | long te = System.nanoTime() - ts; |
| | | if (te < minTime) minTime = te; |
| | |
| | | { "key11", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, true, 10, 10}, |
| | | |
| | | // key00 is a special case : position is not found but cursor is positioned on beginning |
| | | // so it is possible to iterate on it from 2 to end |
| | | { "key00", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, false, 2, 10}, |
| | | // so it is possible to iterate on it from 1 to end |
| | | { "key00", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, true, 1, 10 }, |
| | | { "key02", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, true, 3, 10}, |
| | | { "key05", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, true, 6, 10}, |
| | | { "key050", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, true, 6, 10}, |
| | |
| | | { "key010", EQUAL_TO_KEY, AFTER_MATCHING_KEY, -1, -1 }, |
| | | { "key011", EQUAL_TO_KEY, AFTER_MATCHING_KEY, -1, -1 }, |
| | | |
| | | { "key000", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, -1, -1 }, |
| | | { "key000", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 1, 10 }, |
| | | { "key001", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 1, 10 }, |
| | | { "key004", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 4, 10 }, |
| | | { "key005", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 5, 10 }, |
| | |
| | | { "key010", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 10, 10 }, |
| | | { "key011", LESS_THAN_OR_EQUAL_TO_KEY, ON_MATCHING_KEY, 10, 10 }, |
| | | |
| | | { "key000", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, -1, -1 }, |
| | | { "key000", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, 1, 10 }, |
| | | { "key001", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, 2, 10 }, |
| | | { "key004", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, 5, 10 }, |
| | | { "key005", LESS_THAN_OR_EQUAL_TO_KEY, AFTER_MATCHING_KEY, 6, 10 }, |