/** Abort all cursors opened on the provided log file. */ private void abortCursorsOpenOnLogFile(LogFile<K, V> logFile) { for (AbortableLogCursor<K, V> cursor : openCursors) { if (cursor.isAccessingLogFile(logFile)) { cursor.abort(); } } }
/** * Returns a cursor that allows to retrieve the records from this log. The starting position is * defined by the provided key, cursor matching strategy and cursor positioning strategy. * * @param key Key to use as a start position for the cursor. If key is {@code null}, cursor will * point at the first record of the log. * @param matchingStrategy Cursor key matching strategy. * @param positionStrategy The cursor positioning strategy. * @return a cursor on the log records, which is never {@code null} * @throws ChangelogException If the cursor can't be created. */ public RepositionableCursor<K, V> getCursor( final K key, final KeyMatchingStrategy matchingStrategy, final PositionStrategy positionStrategy) throws ChangelogException { if (key == null) { return getCursor(); } AbortableLogCursor<K, V> cursor = null; sharedLock.lock(); try { if (isClosed) { return new EmptyCursor<>(); } cursor = new AbortableLogCursor<>(this, new InternalLogCursor<K, V>(this)); final boolean isSuccessfullyPositioned = cursor.positionTo(key, matchingStrategy, positionStrategy); // 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; } else { StaticUtils.close(cursor); return new EmptyCursor<>(); } } catch (ChangelogException e) { StaticUtils.close(cursor); throw e; } finally { sharedLock.unlock(); } }
/** * Disable the cursors opened on the head log file log, by closing their underlying cursor. * Returns the state of each cursor just before the close operation. * * @return the pairs (cursor, cursor state) for each cursor pointing to head log file. * @throws ChangelogException If an error occurs. */ private List<Pair<AbortableLogCursor<K, V>, CursorState<K, V>>> disableOpenedCursorsOnHead() throws ChangelogException { final List<Pair<AbortableLogCursor<K, V>, CursorState<K, V>>> openCursorsStates = new ArrayList<>(); final LogFile<K, V> headLogFile = getHeadLogFile(); for (AbortableLogCursor<K, V> cursor : openCursors) { if (cursor.isAccessingLogFile(headLogFile)) { openCursorsStates.add(Pair.of(cursor, cursor.getState())); cursor.closeUnderlyingCursor(); } } return openCursorsStates; }
/** Update the cursors that were pointing to head after a rotation of the head log file. */ private void updateOpenedCursorsOnHeadAfterRotation( List<Pair<AbortableLogCursor<K, V>, CursorState<K, V>>> cursors) throws ChangelogException { for (Pair<AbortableLogCursor<K, V>, CursorState<K, V>> pair : cursors) { final CursorState<K, V> cursorState = pair.getSecond(); // Need to update the cursor only if it is pointing to the head log file if (cursorState.isValid() && isHeadLogFile(cursorState.logFile)) { final K previousKey = logFiles.lowerKey(recordParser.getMaxKey()); final LogFile<K, V> logFile = findLogFileFor(previousKey); final AbortableLogCursor<K, V> cursor = pair.getFirst(); cursor.reinitializeTo( new CursorState<K, V>(logFile, cursorState.filePosition, cursorState.record)); } } }
/** * Returns a cursor that allows to retrieve the records from this log, starting at the first * position. * * @return a cursor on the log records, which is never {@code null} * @throws ChangelogException If the cursor can't be created. */ public RepositionableCursor<K, V> getCursor() throws ChangelogException { AbortableLogCursor<K, V> cursor = null; sharedLock.lock(); try { if (isClosed) { return new EmptyCursor<>(); } cursor = new AbortableLogCursor<>(this, new InternalLogCursor<K, V>(this)); cursor.positionTo(null, null, null); registerCursor(cursor); return cursor; } catch (ChangelogException e) { StaticUtils.close(cursor); throw e; } finally { sharedLock.unlock(); } }
private void abortAllOpenCursors() throws ChangelogException { for (AbortableLogCursor<K, V> cursor : openCursors) { cursor.abort(); } }