void start(long latestIndex, File openSegmentFile) throws IOException { LOG.trace("{} start(latestIndex={}, openSegmentFile={})", name, latestIndex, openSegmentFile); lastWrittenIndex = latestIndex; flushedIndex = latestIndex; if (openSegmentFile != null) { Preconditions.assertTrue(openSegmentFile.exists()); out = new LogOutputStream(openSegmentFile, true, segmentMaxSize, preallocatedSize, bufferSize); } workerThread.start(); }
private void create() throws IOException { fc.truncate(0); fc.position(0); preallocatedPos = 0; preallocate(); // preallocate file out.write(SegmentedRaftLog.HEADER_BYTES); flush(); }
@Override public void execute() throws IOException { Preconditions.assertTrue(out != null); Preconditions.assertTrue(lastWrittenIndex + 1 == entry.getIndex(), "lastWrittenIndex == %s, entry == %s", lastWrittenIndex, entry); out.write(entry); lastWrittenIndex = entry.getIndex(); pendingFlushNum++; if (shouldFlush()) { flushWrites(); } }
/** * Format: * LogEntryProto's protobuf * 4-byte checksum of the above protobuf */ public void write(LogEntryProto entry) throws IOException { final int serialized = entry.getSerializedSize(); final int bufferSize = CodedOutputStream.computeUInt32SizeNoTag(serialized) + serialized; preallocateIfNecessary(bufferSize + 4); byte[] buf = new byte[bufferSize]; CodedOutputStream cout = CodedOutputStream.newInstance(buf); cout.writeUInt32NoTag(serialized); entry.writeTo(cout); checksum.reset(); checksum.update(buf, 0, buf.length); final int sum = (int) checksum.getValue(); out.write(buf); writeInt(sum); }
private LogEntryProto[] prepareLog(List<SegmentRange> list) throws IOException { List<LogEntryProto> entryList = new ArrayList<>(); for (SegmentRange range : list) { File file = range.isOpen ? storage.getStorageDir().getOpenLogFile(range.start) : storage.getStorageDir().getClosedLogFile(range.start, range.end); final int size = (int) (range.end - range.start + 1); LogEntryProto[] entries = new LogEntryProto[size]; try (LogOutputStream out = new LogOutputStream(file, false, segmentMaxSize, preallocatedSize, bufferSize)) { for (int i = 0; i < size; i++) { SimpleOperation m = new SimpleOperation("m" + (i + range.start)); entries[i] = ProtoUtils.toLogEntryProto(m.getLogEntryContent(), range.term, i + range.start, clientId, callId); out.write(entries[i]); } } Collections.addAll(entryList, entries); } return entryList.toArray(new LogEntryProto[entryList.size()]); }
LogOutputStream out = new LogOutputStream(openSegment, false, 16 * 1024 * 1024, 4 * 1024 * 1024, bufferSize); for (int i = 0; i < 10; i++) { entries[i] = ProtoUtils.toLogEntryProto(m.getLogEntryContent(), 0, i, clientId, callId); out.write(entries[i]); out.flush();
/** * Simulate the scenario that the peer is shutdown without truncating * log segment file padding. Make sure the reader can correctly handle this. */ @Test public void testReadWithPadding() throws IOException { final RaftStorage storage = new RaftStorage(storageDir, StartupOption.REGULAR); File openSegment = storage.getStorageDir().getOpenLogFile(0); long size = SegmentedRaftLog.HEADER_BYTES.length; LogEntryProto[] entries = new LogEntryProto[100]; LogOutputStream out = new LogOutputStream(openSegment, false, segmentMaxSize, preallocatedSize, bufferSize); size += writeMessages(entries, out); out.flush(); // make sure the file contains padding Assert.assertEquals( RaftServerConfigKeys.Log.PREALLOCATED_SIZE_DEFAULT.getSize(), openSegment.length()); // check if the reader can correctly read the log file LogEntryProto[] readEntries = readLog(openSegment, 0, RaftServerConstants.INVALID_LOG_INDEX, true); Assert.assertArrayEquals(entries, readEntries); out.close(); Assert.assertEquals(size, openSegment.length()); }
private void flushWrites() throws IOException { if (out != null) { LOG.debug("flush data to " + out + ", reset pending_sync_number to 0"); final Timer.Context timerContext = logFlushTimer.get().time(); try { out.flush(); } finally { timerContext.stop(); } updateFlushedIndex(); } }
private void preallocateIfNecessary(int size) throws IOException { if (out.position() + size > preallocatedPos) { preallocate(); } }
private LogEntryProto[] prepareLog(List<SegmentRange> list) throws IOException { List<LogEntryProto> entryList = new ArrayList<>(); for (SegmentRange range : list) { File file = range.isOpen ? storage.getStorageDir().getOpenLogFile(range.start) : storage.getStorageDir().getClosedLogFile(range.start, range.end); final int size = (int) (range.end - range.start + 1); LogEntryProto[] entries = new LogEntryProto[size]; try (LogOutputStream out = new LogOutputStream(file, false, segmentMaxSize, preallocatedSize, bufferSize)) { for (int i = 0; i < size; i++) { SimpleOperation m = new SimpleOperation("m" + (i + range.start)); entries[i] = ServerProtoUtils.toLogEntryProto(m.getLogEntryContent(), range.term, i + range.start); out.write(entries[i]); } } Collections.addAll(entryList, entries); } return entryList.toArray(new LogEntryProto[entryList.size()]); }
LogOutputStream out = new LogOutputStream(openSegment, false, 16 * 1024 * 1024, 4 * 1024 * 1024, bufferSize); for (int i = 0; i < 10; i++) { SimpleOperation m = new SimpleOperation("m" + i); entries[i] = ServerProtoUtils.toLogEntryProto(m.getLogEntryContent(), 0, i); out.write(entries[i]); out.flush();
/** * Simulate the scenario that the peer is shutdown without truncating * log segment file padding. Make sure the reader can correctly handle this. */ @Test public void testReadWithPadding() throws IOException { final RaftStorage storage = new RaftStorage(storageDir, StartupOption.REGULAR); File openSegment = storage.getStorageDir().getOpenLogFile(0); long size = SegmentedRaftLogFormat.getHeaderLength(); LogEntryProto[] entries = new LogEntryProto[100]; LogOutputStream out = new LogOutputStream(openSegment, false, segmentMaxSize, preallocatedSize, bufferSize); size += writeMessages(entries, out); out.flush(); // make sure the file contains padding Assert.assertEquals( RaftServerConfigKeys.Log.PREALLOCATED_SIZE_DEFAULT.getSize(), openSegment.length()); // check if the reader can correctly read the log file LogEntryProto[] readEntries = readLog(openSegment, 0, RaftServerConstants.INVALID_LOG_INDEX, true); Assert.assertArrayEquals(entries, readEntries); out.close(); Assert.assertEquals(size, openSegment.length()); }
private void flushWrites() throws IOException { if (out != null) { LOG.debug("{}: flush {}", name, out); final Timer.Context timerContext = logFlushTimer.get().time(); try { final CompletableFuture<Void> f = stateMachine != null ? stateMachine.flushStateMachineData(lastWrittenIndex) : CompletableFuture.completedFuture(null); if (stateMachineDataPolicy.isSync()) { stateMachineDataPolicy.getFromFuture(f, () -> this + "-flushStateMachineData"); } out.flush(); if (!stateMachineDataPolicy.isSync()) { IOUtils.getFromFuture(f, () -> this + "-flushStateMachineData"); } } finally { timerContext.stop(); } updateFlushedIndex(); } }
/** * Write the given entry to this output stream. * * Format: * (1) The serialized size of the entry. * (2) The entry. * (3) 4-byte checksum of the entry. * * Size in bytes to be written: * (size to encode n) + n + (checksum size), * where n is the entry serialized size and the checksum size is 4. */ public void write(LogEntryProto entry) throws IOException { final int serialized = entry.getSerializedSize(); final int bufferSize = CodedOutputStream.computeUInt32SizeNoTag(serialized) + serialized; preallocateIfNecessary(bufferSize + 4); byte[] buf = new byte[bufferSize]; CodedOutputStream cout = CodedOutputStream.newInstance(buf); cout.writeUInt32NoTag(serialized); entry.writeTo(cout); checksum.reset(); checksum.update(buf, 0, buf.length); final int sum = (int) checksum.getValue(); out.write(buf); writeInt(sum); }
private void preallocateIfNecessary(int size) throws IOException { if (out.position() + size > preallocatedPos) { preallocate(); } }
File openSegment = storage.getStorageDir().getOpenLogFile(0); try (LogOutputStream out = new LogOutputStream(openSegment, false, segmentMaxSize, preallocatedSize, bufferSize)) { for (int i = 0; i < 100; i++) { LogEntryProto entry = ServerProtoUtils.toLogEntryProto( new SimpleOperation("m" + i).getLogEntryContent(), 0, i); out.write(entry);
LOG.debug("Taking a snapshot with t:{}, i:{}, file:{}", termIndex.getTerm(), termIndex.getIndex(), snapshotFile); try (LogOutputStream out = new LogOutputStream(snapshotFile, false, segmentMaxSize, preallocatedSize, bufferSize)) { for (final LogEntryProto entry : indexMap.values()) { break; } else { out.write(entry); out.flush(); } catch (IOException e) { LOG.warn("Failed to take snapshot", e);
void start(long latestIndex, File openSegmentFile) throws IOException { LOG.trace("{} start(latestIndex={}, openSegmentFile={})", name, latestIndex, openSegmentFile); lastWrittenIndex = latestIndex; flushedIndex = latestIndex; if (openSegmentFile != null) { Preconditions.assertTrue(openSegmentFile.exists()); out = new LogOutputStream(openSegmentFile, true, segmentMaxSize, preallocatedSize, bufferSize); } workerThread.start(); }