@Test public void shouldProvideIndexStatisticsWhenIndexIsBuiltViaPopulationAndConcurrentAdditionsAndDeletions() throws Exception { // given some initial data long[] nodes = repeatCreateNamedPeopleFor(NAMES.length * CREATION_MULTIPLIER); int initialNodes = nodes.length; // when populating while creating IndexDescriptor index = createIndex("Person", "name"); UpdatesTracker updatesTracker = executeCreationsAndDeletions(nodes, index, CREATION_MULTIPLIER); awaitOnline(index); // then int seenWhilePopulating = initialNodes + updatesTracker.createdDuringPopulation() - updatesTracker.deletedDuringPopulation(); double expectedSelectivity = UNIQUE_NAMES / (seenWhilePopulating); assertCorrectIndexSelectivity(expectedSelectivity, indexSelectivity(index)); assertCorrectIndexSize(seenWhilePopulating, indexSize(index)); int expectedIndexUpdates = updatesTracker.deletedAfterPopulation() + updatesTracker.createdAfterPopulation(); assertCorrectIndexUpdates(expectedIndexUpdates, indexUpdates(index)); }
@Test public void shouldWorkWhileHavingHeavyConcurrentUpdates() throws Exception { // given some initial data final long[] nodes = repeatCreateNamedPeopleFor(NAMES.length * CREATION_MULTIPLIER); int initialNodes = nodes.length; int threads = 5; ExecutorService executorService = Executors.newFixedThreadPool(threads); // when populating while creating final IndexDescriptor index = createIndex("Person", "name"); final Collection<Callable<UpdatesTracker>> jobs = new ArrayList<>(threads); for (int i = 0; i < threads; i++) { jobs.add( new Callable<UpdatesTracker>() { @Override public UpdatesTracker call() throws Exception { return executeCreationsDeletionsAndUpdates(nodes, index, CREATION_MULTIPLIER); } }); } List<Future<UpdatesTracker>> futures = executorService.invokeAll(jobs); // sum result into empty result UpdatesTracker result = new UpdatesTracker(); result.notifyPopulationCompleted(); for (Future<UpdatesTracker> future : futures) { result.add(future.get()); } awaitOnline(index); executorService.awaitTermination(1, TimeUnit.SECONDS); executorService.shutdown(); // then int tolerance = MISSED_UPDATES_TOLERANCE * threads; double doubleTolerance = DOUBLE_ERROR_TOLERANCE * threads; int seenWhilePopulating = initialNodes + result.createdDuringPopulation() - result.deletedDuringPopulation(); double expectedSelectivity = UNIQUE_NAMES / (seenWhilePopulating); assertCorrectIndexSelectivity(expectedSelectivity, indexSelectivity(index), doubleTolerance); assertCorrectIndexSize( "Tracker had " + result, seenWhilePopulating, indexSize(index), tolerance); int expectedIndexUpdates = result.deletedAfterPopulation() + result.createdAfterPopulation(); assertCorrectIndexUpdates( "Tracker had " + result, expectedIndexUpdates, indexUpdates(index), tolerance); }
private UpdatesTracker internalExecuteCreationsDeletionsAndUpdates( long[] nodes, IndexDescriptor index, int numberOfCreations, boolean allowDeletions, boolean allowUpdates) throws KernelException { Random random = ThreadLocalRandom.current(); UpdatesTracker updatesTracker = new UpdatesTracker(); int offset = 0; while (updatesTracker.created() < numberOfCreations) { int created = createNamedPeople(nodes, offset); offset += created; updatesTracker.increaseCreated(created); // check index online if (!updatesTracker.isPopulationCompleted() && indexOnlineMonitor.isIndexOnline(index)) { updatesTracker.notifyPopulationCompleted(); } // delete if allowed if (allowDeletions && updatesTracker.created() % 5 == 0) { long nodeId = nodes[random.nextInt(nodes.length)]; try { deleteNode(nodeId); updatesTracker.increaseDeleted(1); } catch (EntityNotFoundException ex) { // ignore } // check again index online if (!updatesTracker.isPopulationCompleted() && indexOnlineMonitor.isIndexOnline(index)) { updatesTracker.notifyPopulationCompleted(); } } // update if allowed if (allowUpdates && updatesTracker.created() % 5 == 0) { int randomIndex = random.nextInt(nodes.length); try { changeName(nodes[randomIndex], "name", NAMES[randomIndex % NAMES.length]); } catch (EntityNotFoundException ex) { // ignore } // check again index online if (!updatesTracker.isPopulationCompleted() && indexOnlineMonitor.isIndexOnline(index)) { updatesTracker.notifyPopulationCompleted(); } } } // make sure population complete has been notified updatesTracker.notifyPopulationCompleted(); return updatesTracker; }