package com.orientechnologies.orient.core.metadata.sequence; import com.orientechnologies.orient.core.db.document.ODatabaseDocument; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.exception.OConcurrentModificationException; import com.orientechnologies.orient.core.exception.OSequenceException; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExternalResource; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; /** * Created by frank on 22/04/2016. */ public class OSequenceTest { private ODatabaseDocument db; @Rule public ExternalResource resource = new ExternalResource() { @Override protected void before() throws Throwable { db = new ODatabaseDocumentTx("memory:" + OSequenceTest.class.getName()); db.create(); } @Override protected void after() { db.drop(); } }; private OSequenceLibrary sequences; @Before public void setUp() throws Exception { sequences = db.getMetadata().getSequenceLibrary(); } @Test public void shouldCreateSeqWithGivenAttribute() { sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, new OSequence.CreateParams().setDefaults()); assertThat(sequences.getSequenceCount()).isEqualTo(1); assertThat(sequences.getSequenceNames()).contains("MYSEQ"); OSequence myseq = sequences.getSequence("MYSEQ"); assertThat(myseq.getSequenceType()).isEqualTo(OSequence.SEQUENCE_TYPE.ORDERED); assertThat(myseq.getMaxRetry()).isEqualTo(100); } @Test public void shouldGivesValuesOrdered() throws Exception { sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, new OSequence.CreateParams().setDefaults()); OSequence myseq = sequences.getSequence("MYSEQ"); assertThat(myseq.current()).isEqualTo(0); assertThat(myseq.next()).isEqualTo(1); assertThat(myseq.current()).isEqualTo(1); assertThat(myseq.next()).isEqualTo(2); assertThat(myseq.current()).isEqualTo(2); } @Test public void shouldGivesValuesWithIncrement() throws Exception { OSequence.CreateParams params = new OSequence.CreateParams().setDefaults().setIncrement(30); assertThat(params.increment).isEqualTo(30); sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, params); OSequence myseq = sequences.getSequence("MYSEQ"); assertThat(myseq.current()).isEqualTo(0); assertThat(myseq.next()).isEqualTo(30); assertThat(myseq.current()).isEqualTo(30); assertThat(myseq.next()).isEqualTo(60); } @Test public void shouldCache() throws Exception { OSequence.CreateParams params = new OSequence.CreateParams().setDefaults().setCacheSize(100).setIncrement(30); assertThat(params.increment).isEqualTo(30); sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.CACHED, params); OSequence myseq = sequences.getSequence("MYSEQ"); assertThat(myseq).isInstanceOf(OSequenceCached.class); assertThat(myseq.current()).isEqualTo(0); assertThat(myseq.next()).isEqualTo(30); assertThat(myseq.current()).isEqualTo(30); assertThat(myseq.next()).isEqualTo(60); assertThat(myseq.current()).isEqualTo(60); assertThat(myseq.next()).isEqualTo(90); assertThat(myseq.current()).isEqualTo(90); assertThat(myseq.next()).isEqualTo(120); assertThat(myseq.current()).isEqualTo(120); } @Test(expected = OSequenceException.class) public void shouldThrowExceptionOnDuplicateSeqDefinition() throws Exception { sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, null); sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, null); } @Test public void shouldDropSequence() throws Exception { sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, null); sequences.dropSequence("MYSEQ"); assertThat(sequences.getSequenceCount()).isEqualTo(0); // IDEMPOTENT sequences.dropSequence("MYSEQ"); assertThat(sequences.getSequenceCount()).isEqualTo(0); } @Test public void testCreateSequenceWithoutExplicitDefaults() throws Exception { // issue #6484 OSequence.CreateParams params = new OSequence.CreateParams().setStart(0L); sequences.createSequence("mySeq", OSequence.SEQUENCE_TYPE.ORDERED, params); OSequence myseq = sequences.getSequence("MYSEQ"); assertThat(myseq.current()).isEqualTo(0); assertThat(myseq.next()).isEqualTo(1); } @Test @Ignore public void shouldSequenceMTNoTx() throws Exception { OSequence.CreateParams params = new OSequence.CreateParams().setStart(0L); OSequence mtSeq = sequences.createSequence("mtSeq", OSequence.SEQUENCE_TYPE.ORDERED, params); mtSeq.setMaxRetry(1000); final int count = 1000; final int threads = 2; final CountDownLatch latch = new CountDownLatch(count); final AtomicInteger errors = new AtomicInteger(0); final AtomicInteger success = new AtomicInteger(0); ExecutorService service = Executors.newFixedThreadPool(threads); for (int i = 0; i < threads; i++) { service.execute(new Runnable() { @Override public void run() { ODatabaseDocument databaseDocument = new ODatabaseDocumentTx("memory:" + OSequenceTest.class.getName()); databaseDocument.open("admin", "admin"); OSequence mtSeq1 = databaseDocument.getMetadata().getSequenceLibrary().getSequence("mtSeq"); for (int j = 0; j < count / threads; j++) { try { mtSeq1.next(); success.incrementAndGet(); } catch (Exception e) { e.printStackTrace(); errors.incrementAndGet(); } latch.countDown(); } } }); } latch.await(); assertThat(errors.get()).isEqualTo(0); assertThat(success.get()).isEqualTo(1000); mtSeq.reloadSequence(); // assertThat(mtSeq.getDocument().getVersion()).isEqualTo(1001); assertThat(mtSeq.current()).isEqualTo(1000); } @Test @Ignore public void shouldSequenceMTTx() throws Exception { OSequence.CreateParams params = new OSequence.CreateParams().setStart(0L); OSequence mtSeq = sequences.createSequence("mtSeq", OSequence.SEQUENCE_TYPE.ORDERED, params); final int count = 1000; final int threads = 2; final CountDownLatch latch = new CountDownLatch(count); final AtomicInteger errors = new AtomicInteger(0); final AtomicInteger success = new AtomicInteger(0); ExecutorService service = Executors.newFixedThreadPool(threads); for (int i = 0; i < threads; i++) { service.execute(new Runnable() { @Override public void run() { ODatabaseDocument databaseDocument = new ODatabaseDocumentTx("memory:" + OSequenceTest.class.getName()); databaseDocument.open("admin", "admin"); OSequence mtSeq1 = databaseDocument.getMetadata().getSequenceLibrary().getSequence("mtSeq"); for (int j = 0; j < count / threads; j++) { for (int retry = 0; retry < 10; ++retry) { try { databaseDocument.begin(); mtSeq1.next(); databaseDocument.commit(); success.incrementAndGet(); break; } catch (OConcurrentModificationException e) { if (retry >= 10) { e.printStackTrace(); errors.incrementAndGet(); break; } // RETRY try { Thread.sleep(10 + new Random().nextInt(100)); } catch (InterruptedException e1) { } mtSeq1.reloadSequence(); continue; } catch (Exception e) { e.printStackTrace(); errors.incrementAndGet(); } } latch.countDown(); } } }); } latch.await(); assertThat(errors.get()).isEqualTo(0); assertThat(success.get()).isEqualTo(1000); mtSeq.reloadSequence(); assertThat(mtSeq.getDocument().getVersion()).isEqualTo(1001); assertThat(mtSeq.current()).isEqualTo(1000); } }