import io.atomix.storage.journal.index.JournalIndex;
import io.atomix.storage.journal.index.SparseJournalIndex;
import java.io.IOException;
-import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
private final JournalIndex index;
private final JournalSerdes namespace;
private final MappableJournalSegmentWriter<E> writer;
- private final Set<MappableJournalSegmentReader<E>> readers = ConcurrentHashMap.newKeySet();
+ private final Set<JournalSegmentReader<E>> readers = ConcurrentHashMap.newKeySet();
private final AtomicInteger references = new AtomicInteger();
private final FileChannel channel;
private boolean open = true;
* Acquires a reference to the log segment.
*/
void acquire() {
- if (references.getAndIncrement() == 0 && open) {
- map();
+ if (references.getAndIncrement() == 0 && storageLevel == StorageLevel.MAPPED) {
+ writer.map();
}
}
* Releases a reference to the log segment.
*/
void release() {
- if (references.decrementAndGet() == 0 && open) {
- unmap();
- }
- }
-
- /**
- * Maps the log segment into memory.
- */
- private void map() {
- if (storageLevel == StorageLevel.MAPPED) {
- MappedByteBuffer buffer = writer.map();
- readers.forEach(reader -> reader.map(buffer));
- }
- }
-
- /**
- * Unmaps the log segment from memory.
- */
- private void unmap() {
- if (storageLevel == StorageLevel.MAPPED) {
- writer.unmap();
- readers.forEach(reader -> reader.unmap());
+ if (references.decrementAndGet() == 0) {
+ if (storageLevel == StorageLevel.MAPPED) {
+ writer.unmap();
+ }
+ if (!open) {
+ finishClose();
+ }
}
}
*
* @return A new segment reader.
*/
- MappableJournalSegmentReader<E> createReader() {
+ JournalSegmentReader<E> createReader() {
checkOpen();
- MappableJournalSegmentReader<E> reader = new MappableJournalSegmentReader<>(channel, this, maxEntrySize, index,
- namespace);
- MappedByteBuffer buffer = writer.buffer();
- if (buffer != null) {
- reader.map(buffer);
- }
+ acquire();
+
+ final var buffer = writer.buffer();
+ final var reader = buffer == null
+ ? new FileChannelJournalSegmentReader<>(channel, this, maxEntrySize, index, namespace)
+ : new MappedJournalSegmentReader<>(buffer, this, maxEntrySize, index, namespace);
readers.add(reader);
return reader;
}
*
* @param reader the closed segment reader
*/
- void closeReader(MappableJournalSegmentReader<E> reader) {
- readers.remove(reader);
+ void closeReader(JournalSegmentReader<E> reader) {
+ if (readers.remove(reader)) {
+ release();
+ }
}
/**
*/
@Override
public void close() {
- unmap();
- writer.close();
- readers.forEach(reader -> reader.close());
+ if (!open) {
+ return;
+ }
+
open = false;
+ readers.forEach(JournalSegmentReader::close);
+ if (references.get() == 0) {
+ finishClose();
+ }
+ }
+
+ private void finishClose() {
+ writer.close();
try {
channel.close();
} catch (IOException e) {
private final JournalIndex index;
final JournalSerdes namespace;
private final long firstIndex;
+ private final JournalSegment<E> segment;
private Indexed<E> currentEntry;
private Indexed<E> nextEntry;
JournalSegmentReader(final JournalSegment<E> segment, final int maxEntrySize, final JournalIndex index,
final JournalSerdes namespace) {
+ this.segment = requireNonNull(segment);
this.maxEntrySize = maxEntrySize;
this.index = requireNonNull(index);
this.namespace = requireNonNull(namespace);
@Override
public final void close() {
- // FIXME: CONTROLLER-2098: remove this method
+ segment.closeReader(this);
}
/**
+++ /dev/null
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.atomix.storage.journal;
-
-import io.atomix.storage.journal.index.JournalIndex;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-
-/**
- * Mappable log segment reader.
- */
-final class MappableJournalSegmentReader<E> implements JournalReader<E> {
- private final JournalSegment<E> segment;
- private final FileChannel channel;
- private final int maxEntrySize;
- private final JournalIndex index;
- private final JournalSerdes namespace;
- private JournalSegmentReader<E> reader;
-
- MappableJournalSegmentReader(
- FileChannel channel,
- JournalSegment<E> segment,
- int maxEntrySize,
- JournalIndex index,
- JournalSerdes namespace) {
- this.channel = channel;
- this.segment = segment;
- this.maxEntrySize = maxEntrySize;
- this.index = index;
- this.namespace = namespace;
- this.reader = new FileChannelJournalSegmentReader<>(channel, segment, maxEntrySize, index, namespace);
- }
-
- /**
- * Converts the reader to a mapped reader using the given buffer.
- *
- * @param buffer the mapped buffer
- */
- void map(ByteBuffer buffer) {
- if (!(reader instanceof MappedJournalSegmentReader)) {
- JournalReader<E> reader = this.reader;
- this.reader = new MappedJournalSegmentReader<>(buffer, segment, maxEntrySize, index, namespace);
- this.reader.reset(reader.getNextIndex());
- reader.close();
- }
- }
-
- /**
- * Converts the reader to an unmapped reader.
- */
- void unmap() {
- if (reader instanceof MappedJournalSegmentReader) {
- JournalReader<E> reader = this.reader;
- this.reader = new FileChannelJournalSegmentReader<>(channel, segment, maxEntrySize, index, namespace);
- this.reader.reset(reader.getNextIndex());
- reader.close();
- }
- }
-
- @Override
- public long getFirstIndex() {
- return reader.getFirstIndex();
- }
-
- @Override
- public long getCurrentIndex() {
- return reader.getCurrentIndex();
- }
-
- @Override
- public Indexed<E> getCurrentEntry() {
- return reader.getCurrentEntry();
- }
-
- @Override
- public long getNextIndex() {
- return reader.getNextIndex();
- }
-
- @Override
- public boolean hasNext() {
- return reader.hasNext();
- }
-
- @Override
- public Indexed<E> next() {
- return reader.next();
- }
-
- @Override
- public void reset() {
- reader.reset();
- }
-
- @Override
- public void reset(long index) {
- reader.reset(index);
- }
-
- @Override
- public void close() {
- reader.close();
- segment.closeReader(this);
- }
-}
private final SegmentedJournal<E> journal;
private JournalSegment<E> currentSegment;
private Indexed<E> previousEntry;
- private MappableJournalSegmentReader<E> currentReader;
+ private JournalSegmentReader<E> currentReader;
private final Mode mode;
SegmentedJournalReader(SegmentedJournal<E> journal, long index, Mode mode) {
this.journal = journal;
this.mode = mode;
currentSegment = journal.getSegment(index);
- currentSegment.acquire();
currentReader = currentSegment.createReader();
long nextIndex = getNextIndex();
public void reset() {
previousEntry = null;
currentReader.close();
- currentSegment.release();
currentSegment = journal.getFirstSegment();
- currentSegment.acquire();
currentReader = currentSegment.createReader();
}
JournalSegment<E> segment = journal.getSegment(index - 1);
if (segment != null) {
currentReader.close();
- currentSegment.release();
currentSegment = segment;
- currentSegment.acquire();
currentReader = currentSegment.createReader();
}
}
previousEntry = currentReader.getCurrentEntry();
currentReader.close();
- currentSegment.release();
currentSegment = nextSegment;
- currentSegment.acquire();
currentReader = currentSegment.createReader();
return true;
}