/** * Serializes an entire RollingSegmentHandle into a new ByteArraySegment. * * @param handle The RollingSegmentHandle to serialize. * @return A ByteArraySegment with the serialization. */ @SneakyThrows(IOException.class) static ByteArraySegment serialize(RollingSegmentHandle handle) { try (EnhancedByteArrayOutputStream os = new EnhancedByteArrayOutputStream()) { //1. Policy Max Size. os.write(combine(KEY_POLICY_MAX_SIZE, Long.toString(handle.getRollingPolicy().getMaxLength()))); //2. Chunks. handle.chunks().forEach(chunk -> os.write(serializeChunk(chunk))); return os.getData(); } }
private void createHeader(RollingSegmentHandle handle) throws StreamSegmentException { Preconditions.checkArgument(handle.getHeaderHandle() == null, "handle already has a header."); // Create a new Header SegmentChunk. String headerName = StreamSegmentNameUtils.getHeaderSegmentName(handle.getSegmentName()); this.baseStorage.create(headerName); val headerHandle = this.baseStorage.openWrite(headerName); // Create a new Handle and serialize it, after which update the original handle. val newHandle = new RollingSegmentHandle(headerHandle, handle.getRollingPolicy(), handle.chunks()); serializeHandle(newHandle); handle.refresh(newHandle); }
private boolean shouldConcatNatively(RollingSegmentHandle source, RollingSegmentHandle target) { if (source.getHeaderHandle() == null) { // Source does not have a Header, hence we cannot do Header concat. return true; } SegmentChunk lastSource = source.lastChunk(); SegmentChunk lastTarget = target.lastChunk(); return lastSource != null && lastSource.getStartOffset() == 0 && lastTarget != null && !lastTarget.isSealed() && lastTarget.getLength() + lastSource.getLength() <= target.getRollingPolicy().getMaxLength(); }
@Override public void write(SegmentHandle handle, long offset, InputStream data, int length) throws StreamSegmentException { val h = asWritableHandle(handle); ensureNotDeleted(h); ensureNotSealed(h); ensureOffset(h, offset); long traceId = LoggerHelpers.traceEnter(log, "write", handle, offset, length); // We run this in a loop because we may have to split the write over multiple SegmentChunks in order to avoid exceeding // any SegmentChunk's maximum length. int bytesWritten = 0; while (bytesWritten < length) { if (h.getActiveChunkHandle() == null || h.lastChunk().getLength() >= h.getRollingPolicy().getMaxLength()) { rollover(h); } SegmentChunk last = h.lastChunk(); int writeLength = (int) Math.min(length - bytesWritten, h.getRollingPolicy().getMaxLength() - last.getLength()); assert writeLength > 0 : "non-positive write length"; long chunkOffset = offset + bytesWritten - last.getStartOffset(); this.baseStorage.write(h.getActiveChunkHandle(), chunkOffset, data, writeLength); last.increaseLength(writeLength); bytesWritten += writeLength; } LoggerHelpers.traceLeave(log, "write", traceId, handle, offset, bytesWritten); }
private void assertHandleEquals(RollingSegmentHandle expected, RollingSegmentHandle actual, SegmentHandle headerHandle) { Assert.assertEquals("getSegmentName", expected.getSegmentName(), actual.getSegmentName()); AssertExtensions.assertListEquals("chunks", expected.chunks(), actual.chunks(), this::chunkEquals); Assert.assertEquals("getRollingPolicy", expected.getRollingPolicy().getMaxLength(), actual.getRollingPolicy().getMaxLength()); Assert.assertEquals("getHeaderHandle", headerHandle, actual.getHeaderHandle()); Assert.assertEquals("isReadOnly", headerHandle.isReadOnly(), expected.isReadOnly()); }
Assert.assertEquals("Unexpected value for getHeaderHandle().", headerHandle, h.getHeaderHandle()); Assert.assertEquals("Unexpected segment name.", SEGMENT_NAME, h.getSegmentName()); Assert.assertEquals("Unexpected rolling policy.", DEFAULT_ROLLING_POLICY, h.getRollingPolicy()); Assert.assertTrue("Unexpected value for isReadOnly.", h.isReadOnly()); Assert.assertFalse("Unexpected value for isSealed.", h.isSealed());
val h1 = (RollingSegmentHandle) s.openRead(withHeaderName); checkWrittenData(writtenData, h1, s); Assert.assertEquals("Unexpected MaxLength after concat.", DEFAULT_ROLLING_POLICY.getMaxLength(), h1.getRollingPolicy().getMaxLength()); checkWrittenData(writtenData, h2, s); Assert.assertEquals("Unexpected MaxLength after concat into non-header segment.", SegmentRollingPolicy.NO_ROLLING.getMaxLength(), h2.getRollingPolicy().getMaxLength());