@Override @SneakyThrows(StreamSegmentException.class) public boolean exists(String segmentName) { try { // Try to open-read the segment, this checks both the header file and the existence of the last SegmentChunk. openRead(segmentName); return true; } catch (StreamSegmentNotExistsException ex) { return false; } }
@Override public SegmentProperties getStreamSegmentInfo(String segmentName) throws StreamSegmentException { val handle = (RollingSegmentHandle) openRead(segmentName); return StreamSegmentInformation .builder() .name(handle.getSegmentName()) .sealed(handle.isSealed()) .length(handle.length()) .build(); }
/** * Tests the ability to concat using the header file for those cases when native concat cannot be used because the * source Segment has multiple SegmentChunks. */ @Test public void testConcatHeaderMultiFile() throws Exception { final int initialTargetLength = (int) DEFAULT_ROLLING_POLICY.getMaxLength() / 2; final String sourceSegmentName = "SourceSegment"; @Cleanup val baseStorage = new InMemoryStorage(); @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY); s.initialize(1); // Create a Target Segment and a Source Segment and write some data to them. s.create(SEGMENT_NAME); val targetHandle = (RollingSegmentHandle) s.openWrite(SEGMENT_NAME); val writeStream = new ByteArrayOutputStream(); populate(s, targetHandle, 1, initialTargetLength, initialTargetLength, writeStream); s.create(sourceSegmentName); val sourceHandle = (RollingSegmentHandle) s.openWrite(sourceSegmentName); populate(s, sourceHandle, APPENDS_PER_SEGMENT, initialTargetLength, initialTargetLength, writeStream); s.seal(sourceHandle); // Concat and verify the handle has been updated accordingly. s.concat(targetHandle, initialTargetLength, sourceSegmentName); checkConcatResult(s, targetHandle, sourceSegmentName, 1 + sourceHandle.chunks().size(), initialTargetLength + (int) sourceHandle.length()); checkWrittenData(writeStream.toByteArray(), s.openRead(SEGMENT_NAME), s); }
s.create(SEGMENT_NAME); val writeHandle = (RollingSegmentHandle) s.openWrite(SEGMENT_NAME); val readHandle = s.openRead(SEGMENT_NAME); // Open now, before writing, so we force a refresh. val writeStream = new ByteArrayOutputStream(); populate(s, writeHandle, writeStream);
/** * Tests the ability to concat using the header file for those cases when native concat cannot be used because the * source Segment has a single SegmentChunk, but it's too large to fit into the Target's active SegmentChunk. */ @Test public void testConcatHeaderSingleFile() throws Exception { final int initialTargetLength = (int) DEFAULT_ROLLING_POLICY.getMaxLength() / 2; final int bigSourceLength = (int) DEFAULT_ROLLING_POLICY.getMaxLength() - initialTargetLength + 1; final String sourceSegmentName = "SourceSegment"; @Cleanup val baseStorage = new InMemoryStorage(); @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY); s.initialize(1); // Create a Target Segment and a Source Segment and write some data to them. s.create(SEGMENT_NAME); val targetHandle = (RollingSegmentHandle) s.openWrite(SEGMENT_NAME); val writeStream = new ByteArrayOutputStream(); populate(s, targetHandle, 1, initialTargetLength, initialTargetLength, writeStream); s.create(sourceSegmentName); val sourceHandle = (RollingSegmentHandle) s.openWrite(sourceSegmentName); populate(s, sourceHandle, 1, bigSourceLength, bigSourceLength, writeStream); s.seal(sourceHandle); // Concat and verify the handle has been updated accordingly. s.concat(targetHandle, initialTargetLength, sourceSegmentName); checkConcatResult(s, targetHandle, sourceSegmentName, 2, initialTargetLength + bigSourceLength); checkWrittenData(writeStream.toByteArray(), s.openRead(SEGMENT_NAME), s); }
s.create(SEGMENT_NAME); val writeHandle = s.openWrite(SEGMENT_NAME); val readHandle = s.openRead(SEGMENT_NAME); // Open now, before writing, so we force a refresh. val writeStream = new ByteArrayOutputStream(); populate(s, writeHandle, writeStream);
/** * Tests the ability to use native concat for those cases when it's appropriate. */ @Test public void testConcatNatively() throws Exception { final int initialTargetLength = (int) DEFAULT_ROLLING_POLICY.getMaxLength() / 2; final int initialSourceLength = (int) DEFAULT_ROLLING_POLICY.getMaxLength() - initialTargetLength; final String sourceSegmentName = "SourceSegment"; @Cleanup val baseStorage = new InMemoryStorage(); @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY); s.initialize(1); // Create a target Segment and write a little data to it. s.create(SEGMENT_NAME); val targetHandle = (RollingSegmentHandle) s.openWrite(SEGMENT_NAME); val writeStream = new ByteArrayOutputStream(); populate(s, targetHandle, 1, initialTargetLength, initialTargetLength, writeStream); // Create a source Segment and write a little data to it, making sure it is small enough to fit into the target // when we need to concat. s.create(sourceSegmentName); val sourceHandle = (RollingSegmentHandle) s.openWrite(sourceSegmentName); populate(s, sourceHandle, 1, initialSourceLength, initialSourceLength, writeStream); s.seal(sourceHandle); // Concat and verify the handle has been updated accordingly. s.concat(targetHandle, initialTargetLength, sourceSegmentName); checkConcatResult(s, targetHandle, sourceSegmentName, 1, initialTargetLength + initialSourceLength); checkWrittenData(writeStream.toByteArray(), s.openRead(SEGMENT_NAME), s); }
s.concat(targetHandle, initialTargetLength, sourceSegmentName); checkConcatResult(s, targetHandle, sourceSegmentName, 1 + sourceHandle.chunks().size(), initialTargetLength + (int) sourceHandle.length()); checkWrittenData(writeStream.toByteArray(), s.openRead(SEGMENT_NAME), s);
checkWrittenData(writeStream.toByteArray(), s.openRead(SEGMENT_NAME), s);
/** * Tests the case when Create was interrupted after it created the Header file but before populating it. */ @Test public void testCreateRecovery() throws Exception { @Cleanup val baseStorage = new TestStorage(); @Cleanup val s = new RollingStorage(baseStorage, DEFAULT_ROLLING_POLICY); s.initialize(1); // Create an empty header file. This simulates a create() operation that failed mid-way. baseStorage.create(StreamSegmentNameUtils.getHeaderSegmentName(SEGMENT_NAME)); Assert.assertFalse("Not expecting Segment to exist.", s.exists(SEGMENT_NAME)); AssertExtensions.assertThrows( "Not expecting Segment to exist (getStreamSegmentInfo).", () -> s.getStreamSegmentInfo(SEGMENT_NAME), ex -> ex instanceof StreamSegmentNotExistsException); AssertExtensions.assertThrows( "Not expecting Segment to exist (openHandle).", () -> s.openRead(SEGMENT_NAME), ex -> ex instanceof StreamSegmentNotExistsException); // Retry the operation and verify everything is in place. s.create(SEGMENT_NAME); val si = s.getStreamSegmentInfo(SEGMENT_NAME); Assert.assertEquals("Expected the Segment to have been created.", 0, si.getLength()); }
val readHandle = s.openRead(segmentName); checkWrittenData(writtenData, readHandle, s); s.concat(nonHeaderHandle, 0, segmentName); Assert.assertFalse("NonHeader source still exists after concat to NonHeader Segment.", s.exists(segmentName)); checkWrittenData(writtenData, s.openRead(nonHeaderName), s); s.concat(withHeaderHandle, 0, nonHeaderName); Assert.assertFalse("NonHeader source still exists after concat to Header Segment.", s.exists(nonHeaderName)); val h1 = (RollingSegmentHandle) s.openRead(withHeaderName); checkWrittenData(writtenData, h1, s); Assert.assertEquals("Unexpected MaxLength after concat.", DEFAULT_ROLLING_POLICY.getMaxLength(), h1.getRollingPolicy().getMaxLength()); s.concat(s.openWrite(nonHeaderName), 0, withHeaderName); Assert.assertFalse("NonHeader source still exists after concat to Header Segment.", s.exists(withHeaderName)); val h2 = (RollingSegmentHandle) s.openRead(nonHeaderName); checkWrittenData(writtenData, h2, s); Assert.assertEquals("Unexpected MaxLength after concat into non-header segment.",