PurgeOldIndexVersion { public void execute(Options opts, long purgeThresholdMillis, List<String> indexPaths) throws Exception { boolean isReadWriteRepository = opts.getCommonOpts().isReadWrite(); if (!isReadWriteRepository) { LOG.info("Repository connected in read-only mode. Use '--read-write' for write operations"); } try (NodeStoreFixture fixture = NodeStoreFixtureProvider.create(opts)) { NodeStore nodeStore = fixture.getStore(); List<String> sanitisedIndexPaths = sanitiseUserIndexPaths(indexPaths); Set<String> indexPathSet = filterIndexPaths(getRepositoryIndexPaths(nodeStore), sanitisedIndexPaths); Map<String, Set<String>> segregateIndexes = segregateIndexes(indexPathSet); for (Map.Entry<String, Set<String>> entry : segregateIndexes.entrySet()) { String baseIndexPath = entry.getKey(); String parentPath = PathUtils.getParentPath(entry.getKey()); List<IndexName> indexNameObjectList = getIndexNameObjectList(entry.getValue()); NodeState indexDefParentNode = NodeStateUtils.getNode(nodeStore.getRoot(), parentPath); List<IndexVersionOperation> toDeleteIndexNameObjectList = IndexVersionOperation.generateIndexVersionOperationList(indexDefParentNode, indexNameObjectList, purgeThresholdMillis); if (isReadWriteRepository && !toDeleteIndexNameObjectList.isEmpty()) { purgeOldIndexVersion(nodeStore, toDeleteIndexNameObjectList); } else { LOG.info("Repository is opened in read-only mode: IndexOperations" + " for index at path {} are : {}", baseIndexPath, toDeleteIndexNameObjectList); } } } }  void execute(Options opts, long purgeThresholdMillis, List<String> indexPaths);  }
@Test public void deleteOldIndexCompletely() throws Exception { createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 0, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); fixture.getAsyncIndexUpdate("async").run(); fixture.close(); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath(), "--read-write", "--threshold=1" }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); Assert.assertFalse("Index:" + "fooIndex-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists()); Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists()); Assert.assertFalse("Index:" + "fooIndex" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists()); Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING), "disabled"); Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4"))); Assert.assertFalse("Index:" + "fooIndex-4-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists()); Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists()); }
@Test public void invalidIndexOperationVersion() throws Exception { LogCustomizer custom = LogCustomizer .forLogger( "org.apache.jackrabbit.oak.indexversion.IndexVersionOperation") .enable(Level.INFO).create(); try { custom.starting(); createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); fixture.getAsyncIndexUpdate("async").run(); fixture.close(); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath(), "--read-write", "--threshold=1" }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); List<String> logs = custom.getLogs(); assertTrue(logs.size() == 1); assertThat("custom fooIndex don't have product version ", logs.toString(), containsString("IndexVersionOperation List is not valid for index")); } finally { custom.finished(); } }
@Test public void deleteOldIndexPartially() throws Exception { createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 0, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); fixture.getAsyncIndexUpdate("async").run(); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); PurgeOldVersionUtils.recursiveDeleteHiddenChildNodes(fixture.getNodeStore(), "/oak:index/fooIndex-4-custom-2"); PurgeOldVersionUtils.recursiveDeleteHiddenChildNodes(fixture.getNodeStore(), "/oak:index/fooIndex-3-custom-2"); fixture.close(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath(), "--read-write", "--threshold=1" }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); Assert.assertFalse("Index:" + "fooIndex-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists()); Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists()); Assert.assertFalse("Index:" + "fooIndex" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists()); Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING), "disabled"); Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4"))); Assert.assertTrue("Index:" + "fooIndex-4-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists()); Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists()); }
@Test public void donotDeleteDisabledIndexes() throws Exception { createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 0, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); NodeStore store = fixture.getNodeStore(); NodeBuilder rootBuilder = store.getRoot().builder(); NodeBuilder nodeBuilder = rootBuilder.getChildNode("oak:index") .getChildNode("fooIndex-4-custom-1").setProperty("type", "disabled"); store.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY); fixture.close(); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath(), "--read-write", "--threshold=1", "--index-paths=/oak:index/fooIndex,/oak:index" }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); Assert.assertFalse("Index:" + "fooIndex-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists()); Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists()); Assert.assertFalse("Index:" + "fooIndex" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists()); Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING), "disabled"); Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4"))); Assert.assertTrue("Index:" + "fooIndex-4-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists()); Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists()); }
@Test public void onlyDeleteVersionIndexesMentionedUnderIndexPaths() throws Exception { createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 0, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); createCustomIndex(FOO1_INDEX_PATH, 2, 1, false); createCustomIndex(FOO1_INDEX_PATH, 2, 2, false); createCustomIndex(FOO1_INDEX_PATH, 3, 0, false); createCustomIndex(FOO1_INDEX_PATH, 3, 1, false); createCustomIndex(FOO1_INDEX_PATH, 3, 2, false); fixture.getAsyncIndexUpdate("async").run(); fixture.close(); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath(), "--read-write", "--threshold=1", "--index-paths=/oak:index/fooIndex" }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); Assert.assertFalse("Index:" + "fooIndex-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2").exists()); Assert.assertFalse("Index:" + "fooIndex-2-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-2-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-1").exists()); Assert.assertFalse("Index:" + "fooIndex-3-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-3-custom-2").exists()); Assert.assertFalse("Index:" + "fooIndex" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex").exists()); Assert.assertEquals(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4").getProperty("type").getValue(Type.STRING), "disabled"); Assert.assertFalse(isHiddenChildNodePresent(fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4"))); Assert.assertFalse("Index:" + "fooIndex-4-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-1").exists()); Assert.assertTrue("Index:" + "fooIndex-4-custom-2" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex-4-custom-2").exists()); Assert.assertTrue("Index:" + "fooIndex1-3-custom-1" + " deleted", fixture.getNodeStore().getRoot().getChildNode("oak:index").getChildNode("fooIndex1-3-custom-1").exists()); }
@Test public void donotDeleteNonReadWriteMode() throws Exception { LogCustomizer custom = LogCustomizer .forLogger( "org.apache.jackrabbit.oak.indexversion.PurgeOldIndexVersion") .enable(Level.INFO).create(); try { custom.starting(); createTestData(false); createCustomIndex(TEST_INDEX_PATH, 2, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 0, false); createCustomIndex(TEST_INDEX_PATH, 3, 1, false); createCustomIndex(TEST_INDEX_PATH, 3, 2, false); createCustomIndex(TEST_INDEX_PATH, 4, 0, false); createCustomIndex(TEST_INDEX_PATH, 4, 1, false); createCustomIndex(TEST_INDEX_PATH, 4, 2, false); fixture.getAsyncIndexUpdate("async").run(); fixture.close(); PurgeOldIndexVersionCommand command = new PurgeOldIndexVersionCommand(); File storeDir = fixture.getDir(); String[] args = { storeDir.getAbsolutePath() }; command.execute(args); fixture = new RepositoryFixture(storeDir); fixture.close(); List<String> logs = custom.getLogs(); assertThat("repository is opened in read only mode ", logs.toString(), containsString("Repository is opened in read-only mode")); } finally { custom.finished(); } }