use of io.atomix.storage.StorageException in project atomix by atomix.
the class SegmentedJournal method createSegment.
/**
* Creates a new segment.
*/
JournalSegment<E> createSegment(JournalSegmentDescriptor descriptor) {
File segmentFile = JournalSegmentFile.createSegmentFile(name, directory, descriptor.id());
RandomAccessFile raf;
FileChannel channel;
try {
raf = new RandomAccessFile(segmentFile, "rw");
raf.setLength(descriptor.maxSegmentSize());
channel = raf.getChannel();
} catch (IOException e) {
throw new StorageException(e);
}
ByteBuffer buffer = ByteBuffer.allocate(JournalSegmentDescriptor.BYTES);
descriptor.copyTo(buffer);
buffer.flip();
try {
channel.write(buffer);
} catch (IOException e) {
throw new StorageException(e);
} finally {
try {
channel.close();
raf.close();
} catch (IOException e) {
}
}
JournalSegment<E> segment = newSegment(new JournalSegmentFile(segmentFile), descriptor);
log.debug("Created segment: {}", segment);
return segment;
}
use of io.atomix.storage.StorageException in project atomix by atomix.
the class FileChannelJournalSegmentReader method reset.
@Override
public void reset(long index) {
reset();
Position position = this.index.lookup(index - 1);
if (position != null) {
currentEntry = new Indexed<>(position.index() - 1, null, 0);
try {
channel.position(position.position());
memory.clear().flip();
} catch (IOException e) {
throw new StorageException(e);
}
readNext();
}
while (getNextIndex() < index && hasNext()) {
next();
}
}
use of io.atomix.storage.StorageException in project atomix by atomix.
the class FollowerRole method backup.
@Override
public CompletableFuture<BackupResponse> backup(BackupRequest request) {
logRequest(request);
// If the term is greater than the node's current term, update the term.
if (request.term() > context.currentTerm()) {
context.resetTerm(request.term(), request.leader());
} else // If the term is less than the node's current term, ignore the backup message.
if (request.term() < context.currentTerm()) {
return CompletableFuture.completedFuture(BackupResponse.error());
}
JournalWriter<LogEntry> writer = context.writer();
JournalReader<LogEntry> reader = context.reader();
// Iterate through all operations in the batch and append entries.
for (BackupOperation operation : request.batch()) {
// If the reader's next index does not align with the operation index, reset the reader.
if (reader.getNextIndex() != operation.index()) {
reader.reset(operation.index());
}
// If the reader has no next entry, append the entry to the journal.
if (!reader.hasNext()) {
try {
writer.append(new LogEntry(operation.term(), operation.timestamp(), operation.value()));
} catch (StorageException e) {
return CompletableFuture.completedFuture(BackupResponse.error());
}
} else // If the next entry's term does not match the operation term, append the entry to the journal.
if (reader.next().entry().term() != operation.term()) {
writer.truncate(operation.index());
try {
writer.append(new LogEntry(operation.term(), operation.timestamp(), operation.value()));
} catch (StorageException e) {
return CompletableFuture.completedFuture(BackupResponse.error());
}
}
}
return CompletableFuture.completedFuture(logResponse(BackupResponse.ok()));
}
use of io.atomix.storage.StorageException in project atomix by atomix.
the class FileChannelJournalSegmentWriter method append.
@Override
@SuppressWarnings("unchecked")
public <T extends E> Indexed<T> append(T entry) {
// Store the entry index.
final long index = getNextIndex();
try {
// Serialize the entry.
memory.clear();
memory.position(Integer.BYTES + Integer.BYTES);
try {
namespace.serialize(entry, memory);
} catch (KryoException e) {
throw new StorageException.TooLarge("Entry size exceeds maximum allowed bytes (" + maxEntrySize + ")");
}
memory.flip();
final int length = memory.limit() - (Integer.BYTES + Integer.BYTES);
// Ensure there's enough space left in the buffer to store the entry.
long position = channel.position();
if (segment.descriptor().maxSegmentSize() - position < length + Integer.BYTES + Integer.BYTES) {
throw new BufferOverflowException();
}
// If the entry length exceeds the maximum entry size then throw an exception.
if (length > maxEntrySize) {
throw new StorageException.TooLarge("Entry size " + length + " exceeds maximum allowed bytes (" + maxEntrySize + ")");
}
// Compute the checksum for the entry.
final Checksum crc32 = new CRC32();
crc32.update(memory.array(), Integer.BYTES + Integer.BYTES, memory.limit() - (Integer.BYTES + Integer.BYTES));
final long checksum = crc32.getValue();
// Create a single byte[] in memory for the entire entry and write it as a batch to the underlying buffer.
memory.putInt(0, length);
memory.putInt(Integer.BYTES, (int) checksum);
channel.write(memory);
// Update the last entry with the correct index/term/length.
Indexed<E> indexedEntry = new Indexed<>(index, entry, length);
this.lastEntry = indexedEntry;
this.index.index(index, (int) position);
return (Indexed<T>) indexedEntry;
} catch (IOException e) {
throw new StorageException(e);
}
}
use of io.atomix.storage.StorageException in project atomix by atomix.
the class FileChannelJournalSegmentWriter method reset.
@Override
public void reset(long index) {
long nextIndex = firstIndex;
// Clear the buffer indexes.
try {
channel.position(JournalSegmentDescriptor.BYTES);
memory.clear().flip();
// Record the current buffer position.
long position = channel.position();
// Read more bytes from the segment if necessary.
if (memory.remaining() < maxEntrySize) {
memory.clear();
channel.read(memory);
channel.position(position);
memory.flip();
}
// Read the entry length.
memory.mark();
int length = memory.getInt();
// If the length is non-zero, read the entry.
while (0 < length && length <= maxEntrySize && (index == 0 || nextIndex <= index)) {
// Read the checksum of the entry.
final long checksum = memory.getInt() & 0xFFFFFFFFL;
// Compute the checksum for the entry bytes.
final Checksum crc32 = new CRC32();
crc32.update(memory.array(), memory.position(), length);
// If the stored checksum equals the computed checksum, return the entry.
if (checksum == crc32.getValue()) {
int limit = memory.limit();
memory.limit(memory.position() + length);
final E entry = namespace.deserialize(memory);
memory.limit(limit);
lastEntry = new Indexed<>(nextIndex, entry, length);
this.index.index(nextIndex, (int) position);
nextIndex++;
} else {
break;
}
// Update the current position for indexing.
position = channel.position() + memory.position();
// Read more bytes from the segment if necessary.
if (memory.remaining() < maxEntrySize) {
channel.position(position);
memory.clear();
channel.read(memory);
channel.position(position);
memory.flip();
}
memory.mark();
length = memory.getInt();
}
// Reset the buffer to the previous mark.
channel.position(channel.position() + memory.reset().position());
} catch (BufferUnderflowException e) {
try {
channel.position(channel.position() + memory.reset().position());
} catch (IOException e2) {
throw new StorageException(e2);
}
} catch (IOException e) {
throw new StorageException(e);
}
}
Aggregations