private void repopulateAllIndexes() throws IOException { final IndexRule[] rules = getIndexesNeedingPopulation(); final IndexPopulator[] populators = new IndexPopulator[rules.length]; // the store is uncontended at this point, so creating a local LockService is safe. LockService locks = new ReentrantLockService(); IndexStoreView storeView = new NeoStoreIndexStoreView(locks, neoStore); final int[] labelIds = new int[rules.length]; final int[] propertyKeyIds = new int[rules.length]; for (int i = 0; i < labelIds.length; i++) { IndexRule rule = rules[i]; labelIds[i] = rule.getLabel(); propertyKeyIds[i] = rule.getPropertyKey(); populators[i] = schemaIndexProviders .apply(rule.getProviderDescriptor()) .getPopulator(rule.getId(), new IndexConfiguration(rule.isConstraintIndex())); populators[i].create(); } Visitor<NodePropertyUpdate, IOException> propertyUpdateVisitor = new Visitor<NodePropertyUpdate, IOException>() { @Override public boolean visit(NodePropertyUpdate update) throws IOException { // Do a lookup from which property has changed to a list of indexes worried about that // property. int propertyKeyInQuestion = update.getPropertyKeyId(); for (int i = 0; i < propertyKeyIds.length; i++) { if (propertyKeyIds[i] == propertyKeyInQuestion) { if (update.forLabel(labelIds[i])) { try { populators[i].add(update.getNodeId(), update.getValueAfter()); } catch (IndexEntryConflictException conflict) { throw conflict.notAllowed(rules[i].getLabel(), rules[i].getPropertyKey()); } } } } return true; } }; NodeLabelUpdateVisitor labelUpdateVisitor = new NodeLabelUpdateVisitor(); StoreScan<IOException> storeScan = storeView.visitNodes(labelIds, propertyKeyIds, propertyUpdateVisitor, labelUpdateVisitor); storeScan.run(); for (IndexPopulator populator : populators) { populator.close(true); } labelUpdateVisitor.close(); }
@Test public void shouldDeliverUpdatesThatOccurDuringPopulationToPopulator() throws Exception { // given when(populator.newPopulatingUpdater()).thenReturn(updater); CountDownLatch latch = new CountDownLatch(1); doAnswer(afterAwaiting(latch)).when(populator).add(anyLong(), any()); IndexingService indexingService = newIndexingServiceWithMockedDependencies(populator, accessor, withData(add(1, "value1"))); life.start(); // when indexingService.createIndex(indexRule(0, labelId, propertyKeyId, PROVIDER_DESCRIPTOR)); IndexProxy proxy = indexingService.getProxyForRule(0); assertEquals(InternalIndexState.POPULATING, proxy.getState()); try (IndexUpdater updater = proxy.newUpdater(IndexUpdateMode.ONLINE)) { updater.process(add(2, "value2")); } latch.countDown(); verify(populator, timeout(1000)).close(true); // then assertEquals(InternalIndexState.ONLINE, proxy.getState()); InOrder order = inOrder(populator, accessor, updater); order.verify(populator).create(); order.verify(populator).add(1, "value1"); // this is invoked from indexAllNodes(), // empty because the id we added (2) is bigger than the one we indexed (1) order.verify(populator).newPopulatingUpdater(); order.verify(updater).close(); order.verify(populator).newPopulatingUpdater(); order.verify(updater).process(add(2, "value2")); order.verify(updater).close(); order.verify(populator).close(true); verifyNoMoreInteractions(updater); verifyNoMoreInteractions(populator); verifyZeroInteractions(accessor); }