package com.orientechnologies.orient.core.storage.impl.local.paginated.wal; import com.orientechnologies.common.serialization.types.OIntegerSerializer; import com.orientechnologies.orient.core.storage.impl.local.paginated.OLocalPaginatedStorage; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.io.File; import java.util.*; import java.util.concurrent.*; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * @author Andrey Lomakin <a href="mailto:lomakin.andrey@gmail.com">Andrey Lomakin</a> * @since 24/12/14 */ @Test(enabled = false) public class WALSegmentCreation { private ODiskWriteAheadLog writeAheadLog; private File testDir; private volatile boolean stop = false; private ExecutorService writerExecutor; private OLocalPaginatedStorage localPaginatedStorage; @BeforeClass(enabled = false) public void beforeClass() throws Exception { OWALRecordsFactory.INSTANCE.registerNewRecord((byte) 129, TestRecordTwo.class); OWALRecordsFactory.INSTANCE.registerNewRecord((byte) 128, TestRecordOne.class); String buildDirectory = System.getProperty("buildDirectory"); if (buildDirectory == null || buildDirectory.isEmpty()) buildDirectory = "."; testDir = new File(buildDirectory, "WALSegmentCreationTest"); if (!testDir.exists()) testDir.mkdir(); localPaginatedStorage = mock(OLocalPaginatedStorage.class); when(localPaginatedStorage.getStoragePath()).thenReturn(testDir.getAbsolutePath()); when(localPaginatedStorage.getName()).thenReturn("WALSegmentCreationTest"); writeAheadLog = new ODiskWriteAheadLog(400, 500, 64 * 1024L * 1024L, null, true, localPaginatedStorage, 10); writerExecutor = Executors.newCachedThreadPool(); } public void testLogSegmentCreation() throws Exception { List<Future<Void>> futures = new ArrayList<Future<Void>>(); for (int i = 0; i < 8; i++) { futures.add(writerExecutor.submit(new Writer())); } Thread.sleep(15 * 60 * 1000); stop = true; for (Future<Void> future : futures) future.get(); final Set<OOperationUnitId> operations = new HashSet<OOperationUnitId>(); writeAheadLog.close(); writeAheadLog = new ODiskWriteAheadLog(200, 500, 64 * 1024L * 1024L, null, true, localPaginatedStorage, 10); OLogSequenceNumber lsn = writeAheadLog.begin(); long segment = lsn.getSegment(); System.out.println("Segment : " + lsn.getSegment()); while (lsn != null) { OWALRecord record = writeAheadLog.read(lsn); if (record instanceof OAtomicUnitStartRecord) { OOperationUnitId operationUnitId = ((OAtomicUnitStartRecord) record).getOperationUnitId(); Assert.assertFalse(operations.contains(operationUnitId)); operations.add(operationUnitId); } else if (record instanceof OAtomicUnitEndRecord) { OOperationUnitId operationUnitId = ((OAtomicUnitEndRecord) record).getOperationUnitId(); Assert.assertTrue(operations.contains(operationUnitId)); operations.remove(operationUnitId); } else if (record instanceof OOperationUnitRecord) { OOperationUnitId operationUnitId = ((OOperationUnitRecord) record).getOperationUnitId(); Assert.assertTrue(operations.contains(operationUnitId)); } lsn = writeAheadLog.next(lsn); if (lsn != null && lsn.getSegment() != segment) { System.out.println("Segment : " + lsn.getSegment()); Assert.assertTrue(operations.isEmpty()); segment = lsn.getSegment(); } } Assert.assertTrue(operations.isEmpty()); } public class Writer implements Callable<Void> { @Override public Void call() throws Exception { while (!stop) { OOperationUnitId operationUnitId = OOperationUnitId.generateId(); writeAheadLog.logAtomicOperationStartRecord(true, operationUnitId); writeAheadLog.log(new TestRecordOne(100, operationUnitId)); writeAheadLog.log(new TestRecordOne(200, operationUnitId)); writeAheadLog.log(new TestRecordTwo(100)); writeAheadLog.log(new TestRecordOne(300, operationUnitId)); writeAheadLog.log(new TestRecordOne(200, operationUnitId)); writeAheadLog.log(new TestRecordTwo(200)); writeAheadLog.log(new TestRecordOne(100, operationUnitId)); writeAheadLog.logAtomicOperationEndRecord(operationUnitId, false, new OLogSequenceNumber(0, 0), null); writeAheadLog.log(new TestRecordTwo(100)); } return null; } } public static final class TestRecordOne extends OOperationUnitRecord { private byte[] data; public TestRecordOne() { } public TestRecordOne(int size, OOperationUnitId operationUnitId) { super(operationUnitId); Random random = new Random(); data = new byte[size - OIntegerSerializer.INT_SIZE - (OIntegerSerializer.INT_SIZE + 3) - 1]; random.nextBytes(data); } @Override public int toStream(byte[] content, int offset) { offset = super.toStream(content, offset); OIntegerSerializer.INSTANCE.serializeNative(data.length, content, offset); offset += OIntegerSerializer.INT_SIZE; System.arraycopy(data, 0, content, offset, data.length); offset += data.length; return offset; } @Override public int fromStream(byte[] content, int offset) { offset = super.fromStream(content, offset); int size = OIntegerSerializer.INSTANCE.deserializeNative(content, offset); offset += OIntegerSerializer.INT_SIZE; data = new byte[size]; System.arraycopy(content, offset, data, 0, data.length); offset += size; return offset; } @Override public int serializedSize() { return super.serializedSize() + OIntegerSerializer.INT_SIZE + data.length + 1; } @Override public boolean isUpdateMasterRecord() { return false; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TestRecordTwo that = (TestRecordTwo) o; if (!Arrays.equals(data, that.data)) return false; return true; } @Override public int hashCode() { return Arrays.hashCode(data); } @Override public String toString() { return "TestRecordOne {size: " + (data.length + OIntegerSerializer.INT_SIZE + 1 + (OIntegerSerializer.INT_SIZE + 3) + "}"); } } public static final class TestRecordTwo extends OAbstractWALRecord { private byte[] data; public TestRecordTwo() { } public TestRecordTwo(int size) { Random random = new Random(); data = new byte[size - OIntegerSerializer.INT_SIZE - (OIntegerSerializer.INT_SIZE + 3) - 1]; random.nextBytes(data); } @Override public int toStream(byte[] content, int offset) { OIntegerSerializer.INSTANCE.serializeNative(data.length, content, offset); offset += OIntegerSerializer.INT_SIZE; System.arraycopy(data, 0, content, offset, data.length); offset += data.length; return offset; } @Override public int fromStream(byte[] content, int offset) { int size = OIntegerSerializer.INSTANCE.deserializeNative(content, offset); offset += OIntegerSerializer.INT_SIZE; data = new byte[size]; System.arraycopy(content, offset, data, 0, data.length); offset += size; return offset; } @Override public int serializedSize() { return OIntegerSerializer.INT_SIZE + data.length + 1; } @Override public boolean isUpdateMasterRecord() { return false; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TestRecordTwo that = (TestRecordTwo) o; if (!Arrays.equals(data, that.data)) return false; return true; } @Override public int hashCode() { return Arrays.hashCode(data); } @Override public String toString() { return "TestRecordTwo {size: " + (data.length + OIntegerSerializer.INT_SIZE + 1 + (OIntegerSerializer.INT_SIZE + 3) + "}"); } } }