diff --git a/accession-commons-monotonic-generator-jpa/src/main/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGenerator.java b/accession-commons-monotonic-generator-jpa/src/main/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGenerator.java index 25cee15c..b8967c7c 100644 --- a/accession-commons-monotonic-generator-jpa/src/main/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGenerator.java +++ b/accession-commons-monotonic-generator-jpa/src/main/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGenerator.java @@ -195,6 +195,10 @@ public void shutDownAccessionGenerator(){ SHUTDOWN = Boolean.TRUE; } + /** + * Before doing any operation on Accession Generator, we need to make sure it has not been shut down. + * We should make the check by calling this method as the first thing in all public methods of this class + */ private void checkAccessionGeneratorNotShutDown(){ if(SHUTDOWN){ throw new AccessionGeneratorShutDownException("Accession Generator has been shut down and is no longer available"); diff --git a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/core/BasicMonotonicAccessioningWithAlternateRangesTest.java b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/core/BasicMonotonicAccessioningWithAlternateRangesTest.java index db207075..3c6e9a12 100644 --- a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/core/BasicMonotonicAccessioningWithAlternateRangesTest.java +++ b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/core/BasicMonotonicAccessioningWithAlternateRangesTest.java @@ -31,6 +31,7 @@ import uk.ac.ebi.ampt2d.commons.accession.generators.monotonic.MonotonicRangePriorityQueue; import uk.ac.ebi.ampt2d.commons.accession.hashing.SHA1HashingFunction; import uk.ac.ebi.ampt2d.commons.accession.persistence.jpa.monotonic.entities.ContiguousIdBlock; +import uk.ac.ebi.ampt2d.commons.accession.persistence.jpa.monotonic.repositories.ContiguousIdBlockRepository; import uk.ac.ebi.ampt2d.commons.accession.persistence.jpa.monotonic.service.ContiguousIdBlockService; import uk.ac.ebi.ampt2d.commons.accession.service.BasicSpringDataRepositoryMonotonicDatabaseService; import uk.ac.ebi.ampt2d.test.configuration.TestMonotonicDatabaseServiceTestConfiguration; @@ -102,7 +103,7 @@ public void testRecoverState() { // block-1 (100 to 109) : fully complete // block-2 (110 to 119) : fully complete // block-3 (120 to 124) : partially complete - assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(),categoryId, instanceId2).size()); + assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(), categoryId, instanceId2).size()); ContiguousIdBlock uncompletedBlock = getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(), categoryId, instanceId2).get(0); assertEquals(120l, uncompletedBlock.getFirstValue()); assertEquals(129l, uncompletedBlock.getLastValue()); @@ -127,7 +128,7 @@ public void testAlternateRangesWithDifferentGenerators() throws AccessionCouldNo assertEquals(0, evaAccessions.get(0).getAccession().longValue()); assertEquals(8, evaAccessions.get(8).getAccession().longValue()); //BlockSize of 10 was reserved but only 9 elements have been accessioned - assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(),categoryId, INSTANCE_ID) + assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(), categoryId, INSTANCE_ID) .size()); accService1.shutDownAccessioning(); @@ -157,7 +158,7 @@ public void testAlternateRangesWithDifferentGenerators() throws AccessionCouldNo assertNotEquals(80, evaAccessions.get(0).getAccession().longValue()); assertEquals(50, evaAccessions.get(0).getAccession().longValue()); assertEquals(58, evaAccessions.get(8).getAccession().longValue()); - assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(),categoryId, instanceId2).size()); + assertEquals(1, getUncompletedBlocksByCategoryIdAndApplicationInstanceIdOrderByEndAsc(contiguousIdBlockService.getRepository(), categoryId, instanceId2).size()); accService3.shutDownAccessioning(); //Get previous uncompleted service from instance1 and create accessions @@ -169,6 +170,49 @@ public void testAlternateRangesWithDifferentGenerators() throws AccessionCouldNo assertEquals(80, evaAccessions.get(1).getAccession().longValue()); } + @Test + public void testInitializeBlockManagerInMonotonicAccessionGenerator() { + String categoryId = "eva_2"; + String instanceId2 = "test-instance_2"; + ContiguousIdBlockRepository repository = contiguousIdBlockService.getRepository(); + + ContiguousIdBlock block = getUnreservedContiguousIdBlock(categoryId, instanceId2, 0, 10); + repository.save(block); + + // assert block is not full and not reserved + List blockInDBList = repository + .findAllByCategoryIdAndApplicationInstanceIdOrderByLastValueAsc(categoryId, instanceId2) + .collect(Collectors.toList()); + assertEquals(1, blockInDBList.size()); + List unreservedAndNotFullBlocks = blockInDBList.stream() + .filter(b -> b.isNotFull() && b.isNotReserved()) + .collect(Collectors.toList()); + assertEquals(1, unreservedAndNotFullBlocks.size()); + assertEquals(9, unreservedAndNotFullBlocks.get(0).getLastValue()); + assertEquals(-1, unreservedAndNotFullBlocks.get(0).getLastCommitted()); + assertEquals(Boolean.FALSE, unreservedAndNotFullBlocks.get(0).isReserved()); + + // this will run the recover state + BasicAccessioningService accService = getAccessioningService(categoryId, instanceId2); + + // assert block gets reserved after recover state + blockInDBList = repository + .findAllByCategoryIdAndApplicationInstanceIdOrderByLastValueAsc(categoryId, instanceId2) + .collect(Collectors.toList()); + assertEquals(1, blockInDBList.size()); + unreservedAndNotFullBlocks = blockInDBList.stream() + .filter(b -> b.isNotFull() && b.isNotReserved()) + .collect(Collectors.toList()); + assertEquals(0, unreservedAndNotFullBlocks.size()); + List reservedAndNotFullBlocks = blockInDBList.stream() + .filter(b -> b.isNotFull() && b.isReserved()) + .collect(Collectors.toList()); + assertEquals(1, reservedAndNotFullBlocks.size()); + assertEquals(9, reservedAndNotFullBlocks.get(0).getLastValue()); + assertEquals(-1, reservedAndNotFullBlocks.get(0).getLastCommitted()); + assertEquals(Boolean.TRUE, reservedAndNotFullBlocks.get(0).isReserved()); + } + private List getObjectsForAccessionsInRange(int startRange, int endRange) { return IntStream.range(startRange, endRange + 1).mapToObj(i -> TestModel.of("Test-" + i)).collect(Collectors .toList()); diff --git a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/BlockManagerTest.java b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/BlockManagerTest.java index 0ba9a4dd..29b4952a 100644 --- a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/BlockManagerTest.java +++ b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/BlockManagerTest.java @@ -153,4 +153,25 @@ public void commitAllValuesOnBlockManager() throws AccessionCouldNotBeGeneratedE manager.commit(accessions2); } + @Test + public void testGetAssignedBlocks(){ + BlockManager manager = new BlockManager(); + manager.addBlock(new ContiguousIdBlock(CATEGORY_ID, INSTANCE_ID, 0, 10)); + manager.addBlock(new ContiguousIdBlock(CATEGORY_ID, INSTANCE_ID, 10, 10)); + + assertEquals(2, manager.getAssignedBlocks().size()); + } + + @Test + public void testShutDownBlockManager(){ + BlockManager manager = new BlockManager(); + manager.addBlock(new ContiguousIdBlock(CATEGORY_ID, INSTANCE_ID, 0, 10)); + manager.addBlock(new ContiguousIdBlock(CATEGORY_ID, INSTANCE_ID, 10, 10)); + manager.shutDownBlockManager(); + + assertEquals(0, manager.getAssignedBlocks().size()); + assertEquals(0, manager.getAvailableRanges().size()); + + } + } diff --git a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGeneratorTest.java b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGeneratorTest.java index 12e74a7f..0e1218b7 100644 --- a/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGeneratorTest.java +++ b/accession-commons-monotonic-generator-jpa/src/test/java/uk/ac/ebi/ampt2d/commons/accession/generators/monotonic/MonotonicAccessionGeneratorTest.java @@ -26,6 +26,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; +import uk.ac.ebi.ampt2d.commons.accession.core.exceptions.AccessionGeneratorShutDownException; import uk.ac.ebi.ampt2d.commons.accession.core.exceptions.AccessionIsNotPendingException; import uk.ac.ebi.ampt2d.commons.accession.core.models.AccessionWrapper; import uk.ac.ebi.ampt2d.commons.accession.core.models.SaveResponse; @@ -40,6 +41,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; @@ -49,6 +51,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; +import static uk.ac.ebi.ampt2d.commons.accession.util.ContiguousIdBlockUtil.getUnreservedContiguousIdBlock; @RunWith(SpringRunner.class) @DataJpaTest @@ -454,4 +457,66 @@ public void assertAbortExecutionWhenDBConstraintExceptionThrown() { assertThrows(ExponentialBackOffMaxRetriesRuntimeException.class, () -> mockGenerator.generateAccessions(1)); assertEquals(0, repository.count()); } + + @Test + public void testInitializeBlockManager() { + ContiguousIdBlock block = getUnreservedContiguousIdBlock(CATEGORY_ID_2, INSTANCE_ID, 0, 10); + repository.save(block); + + // To start with Block is UnCompleted and UnReserved + List blockInDBList = repository + .findAllByCategoryIdAndApplicationInstanceIdOrderByLastValueAsc(CATEGORY_ID_2, INSTANCE_ID) + .collect(Collectors.toList()); + assertEquals(1, blockInDBList.size()); + List unreservedBlocks = blockInDBList.stream() + .filter(b -> b.isNotFull() && b.isNotReserved()) + .collect(Collectors.toList()); + assertEquals(1, unreservedBlocks.size()); + assertEquals(0, unreservedBlocks.get(0).getFirstValue()); + assertEquals(9, unreservedBlocks.get(0).getLastValue()); + assertEquals(-1, unreservedBlocks.get(0).getLastCommitted()); + assertEquals(Boolean.FALSE, unreservedBlocks.get(0).isReserved()); + + // Generator 1 starts and its recover state reserves the UnCompleted block + MonotonicAccessionGenerator generator1 = new MonotonicAccessionGenerator(CATEGORY_ID_2, INSTANCE_ID, service, new long[]{}); + assertEquals(1, generator1.getAvailableRanges().size()); + assertEquals(new MonotonicRange(0, 9), generator1.getAvailableRanges().peek()); + + // Block is currently reserved by Generator-1 + blockInDBList = repository + .findAllByCategoryIdAndApplicationInstanceIdOrderByLastValueAsc(CATEGORY_ID_2, INSTANCE_ID) + .collect(Collectors.toList()); + assertEquals(1, blockInDBList.size()); + List reservedBlocks = blockInDBList.stream() + .filter(b -> b.isNotFull() && b.isReserved()) + .collect(Collectors.toList()); + assertEquals(1, reservedBlocks.size()); + assertEquals(0, reservedBlocks.get(0).getFirstValue()); + assertEquals(9, reservedBlocks.get(0).getLastValue()); + assertEquals(-1, reservedBlocks.get(0).getLastCommitted()); + assertEquals(Boolean.TRUE, reservedBlocks.get(0).isReserved()); + + // Generator-2 will not be able to reserve the un-completed block as it is currently reserved by Generator-1 + MonotonicAccessionGenerator generator2 = new MonotonicAccessionGenerator(CATEGORY_ID_2, INSTANCE_ID, service, new long[]{}); + assertEquals(0, generator2.getAvailableRanges().size()); + + // Generator-3 can reserve the same Uncompleted block, once Generator-1 releases it + generator1.shutDownAccessionGenerator(); + MonotonicAccessionGenerator generator3 = new MonotonicAccessionGenerator(CATEGORY_ID_2, INSTANCE_ID, service, new long[]{}); + assertEquals(1, generator3.getAvailableRanges().size()); + assertEquals(new MonotonicRange(0, 9), generator3.getAvailableRanges().peek()); + } + + @Test + public void testShutDownAccessionGenerator() { + MonotonicAccessionGenerator generator = getMonotonicAccessionGeneratorForCategoryHavingBlockInterval(); + generator.shutDownAccessionGenerator(); + + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.generateAccessions(24)); + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.generateAccessions(new HashMap())); + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.commit()); + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.release()); + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.postSave(new SaveResponse<>())); + assertThrows(AccessionGeneratorShutDownException.class, () -> generator.getAvailableRanges()); + } }