rishabhdaim commented on code in PR #683: URL: https://github.com/apache/jackrabbit-oak/pull/683#discussion_r970462572
########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/Progress.java: ########## @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.util.concurrent.BlockingQueue; + +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.jetbrains.annotations.NotNull; + +/** + * <code>Progress</code>... + */ +public class Progress implements DocumentProcessor { + + private long numDocuments = 0; + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) + throws InterruptedException { + if (++numDocuments % 10000 == 0) { + results.put(newProgressResult(numDocuments, document.getPath())); + } + } + + protected Result newProgressResult(long numDocs, Path path) { + return new ProgressResult(numDocs, path); + } + + class ProgressResult implements Result { + + protected final String msg; + + public ProgressResult(long numDocs, Path path) { + this.msg = "Checked " + numDocs + " documents so far - " + path; + } + + @Override + public String toJson() { + StringBuilder sb = new StringBuilder("{"); Review Comment: Same as above, please use jsonobject ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/DocumentProcessor.java: ########## @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.util.concurrent.BlockingQueue; + +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.util.ISO8601; +import org.jetbrains.annotations.NotNull; + +/** + * <code>DocumentProcessor</code>... + */ +public interface DocumentProcessor { + + void processDocument(@NotNull NodeDocument document, Review Comment: Could you please add JavaDocs for this api. ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/Summary.java: ########## @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.util.concurrent.BlockingQueue; + +import com.google.common.base.Stopwatch; + +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.jetbrains.annotations.NotNull; + +/** + * <code>Summary</code>... + */ +public class Summary implements DocumentProcessor { + + private final int numThreads; + + private int numDocuments = 0; + + private final Stopwatch sw = Stopwatch.createStarted(); + + public Summary(int numThreads) { + this.numThreads = numThreads; + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + numDocuments++; + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + results.put(() -> "{\"summary\": \"Checked " + numDocuments + " documents in " + sw + ". Number of threads used: " + numThreads + "\"}"); Review Comment: Same as above ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/OrphanedNodeCheck.java: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.apache.jackrabbit.oak.plugins.document.RevisionVector; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * <code>OrphanedNodeCheck</code>... + */ +public class OrphanedNodeCheck implements DocumentProcessor, Closeable { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final ExecutorService executorService; + + public OrphanedNodeCheck(DocumentNodeStore ns, + RevisionVector headRevision, + int numThread) { + this.ns = ns; + this.headRevision = headRevision; + this.executorService = new ThreadPoolExecutor( + numThread, numThread, 1, TimeUnit.MINUTES, + new LinkedBlockingQueue<>(1000), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + if (!document.isSplitDocument()) { + executorService.submit(new CheckDocument(ns, headRevision, document, results)); + } + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) { + String msg = "Checks still not finished after the last one has been submitted 5 minutes ago"; + results.put(() -> { + StringBuilder sb = new StringBuilder("{"); + sb.append("\"time\": \"").append(nowAsISO8601()).append('"'); + sb.append(", \"info\": \"").append(msg).append('"'); + sb.append("}"); + return sb.toString(); + }); + } + } + + @Override + public void close() throws IOException { + new ExecutorCloser(executorService, 5, TimeUnit.MINUTES).close(); + } + + private static final class CheckDocument implements Callable<Void> { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final NodeDocument doc; + + private final BlockingQueue<Result> results; + + CheckDocument(DocumentNodeStore ns, + RevisionVector headRevision, + NodeDocument doc, + BlockingQueue<Result> results) { + this.ns = ns; + this.headRevision = headRevision; + this.doc = doc; + this.results = results; + } + + @Override + public Void call() throws Exception { Review Comment: ```suggestion public void run() { DocumentNodeState state = doc.getNodeAtRevision(ns, headRevision, null); if (state != null) { Path path = doc.getPath(); assertAncestorsExist(path.getParent()).ifPresent(missing -> results.put(new OrphanedNode(path, missing, state.getLastRevision()))); } } ``` ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/Progress.java: ########## @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.util.concurrent.BlockingQueue; + +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.jetbrains.annotations.NotNull; + +/** + * <code>Progress</code>... + */ +public class Progress implements DocumentProcessor { + + private long numDocuments = 0; + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) + throws InterruptedException { + if (++numDocuments % 10000 == 0) { + results.put(newProgressResult(numDocuments, document.getPath())); + } + } + + protected Result newProgressResult(long numDocs, Path path) { + return new ProgressResult(numDocs, path); + } + + class ProgressResult implements Result { + + protected final String msg; + + public ProgressResult(long numDocs, Path path) { + this.msg = "Checked " + numDocs + " documents so far - " + path; + } + + @Override + public String toJson() { + StringBuilder sb = new StringBuilder("{"); Review Comment: ```suggestion JsonObject json = new JsonObject(); json.getProperties().put("time", nowAsISO8601()); json.getProperties().put("info", msg); return json.toString(); ``` ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/OrphanedNodeCheck.java: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.apache.jackrabbit.oak.plugins.document.RevisionVector; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * <code>OrphanedNodeCheck</code>... + */ +public class OrphanedNodeCheck implements DocumentProcessor, Closeable { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final ExecutorService executorService; + + public OrphanedNodeCheck(DocumentNodeStore ns, + RevisionVector headRevision, + int numThread) { + this.ns = ns; + this.headRevision = headRevision; + this.executorService = new ThreadPoolExecutor( + numThread, numThread, 1, TimeUnit.MINUTES, + new LinkedBlockingQueue<>(1000), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + if (!document.isSplitDocument()) { + executorService.submit(new CheckDocument(ns, headRevision, document, results)); + } + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) { + String msg = "Checks still not finished after the last one has been submitted 5 minutes ago"; + results.put(() -> { + StringBuilder sb = new StringBuilder("{"); + sb.append("\"time\": \"").append(nowAsISO8601()).append('"'); + sb.append(", \"info\": \"").append(msg).append('"'); + sb.append("}"); + return sb.toString(); + }); + } + } + + @Override + public void close() throws IOException { + new ExecutorCloser(executorService, 5, TimeUnit.MINUTES).close(); + } + + private static final class CheckDocument implements Callable<Void> { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final NodeDocument doc; + + private final BlockingQueue<Result> results; + + CheckDocument(DocumentNodeStore ns, + RevisionVector headRevision, + NodeDocument doc, + BlockingQueue<Result> results) { + this.ns = ns; + this.headRevision = headRevision; + this.doc = doc; + this.results = results; + } + + @Override + public Void call() throws Exception { + DocumentNodeState state = doc.getNodeAtRevision(ns, headRevision, null); + if (state != null) { + Path path = doc.getPath(); + Path missing = assertAncestorsExist(path.getParent()); + if (missing != null) { + results.put(new OrphanedNode(path, missing, state.getLastRevision())); + } + } + return null; + } + + private Path assertAncestorsExist(Path path) { Review Comment: ```suggestion private Optional<Path> assertAncestorsExist(Path path) { if (path == null) { return Optional.empty(); } NodeState state = ns.getRoot(); Path p = Path.ROOT; for (String name : path.elements()) { p = new Path(p, name); state = state.getChildNode(name); if (!state.exists()) { return Optional.of(p); } } return Optional.empty(); } ``` ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/OrphanedNodeCheck.java: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.apache.jackrabbit.oak.plugins.document.RevisionVector; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * <code>OrphanedNodeCheck</code>... + */ +public class OrphanedNodeCheck implements DocumentProcessor, Closeable { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final ExecutorService executorService; + + public OrphanedNodeCheck(DocumentNodeStore ns, + RevisionVector headRevision, + int numThread) { + this.ns = ns; + this.headRevision = headRevision; + this.executorService = new ThreadPoolExecutor( + numThread, numThread, 1, TimeUnit.MINUTES, + new LinkedBlockingQueue<>(1000), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + if (!document.isSplitDocument()) { + executorService.submit(new CheckDocument(ns, headRevision, document, results)); + } + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) { + String msg = "Checks still not finished after the last one has been submitted 5 minutes ago"; + results.put(() -> { + StringBuilder sb = new StringBuilder("{"); + sb.append("\"time\": \"").append(nowAsISO8601()).append('"'); + sb.append(", \"info\": \"").append(msg).append('"'); + sb.append("}"); + return sb.toString(); + }); + } + } + + @Override + public void close() throws IOException { + new ExecutorCloser(executorService, 5, TimeUnit.MINUTES).close(); + } + + private static final class CheckDocument implements Callable<Void> { Review Comment: I would change to implement `Runnbale` since we are neither returning anything nor throwing any exceptions. ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/ProgressWithETA.java: ########## @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import org.apache.jackrabbit.oak.plugins.document.Path; + +/** + * <code>ProgressWithETA</code>... + */ +public class ProgressWithETA extends Progress { + + private final ETA eta; + + public ProgressWithETA(ETA eta) { + this.eta = eta; + } + + @Override + protected Result newProgressResult(long numDocs, Path path) { + return new ProgressResult(numDocs, path) { + @Override + public String toJson() { + StringBuilder sb = new StringBuilder("{"); + sb.append("\"time\": \"").append(nowAsISO8601()).append('"'); Review Comment: Same as above, please use jsonobject. ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/OrphanedNodeCheck.java: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.apache.jackrabbit.oak.plugins.document.RevisionVector; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * <code>OrphanedNodeCheck</code>... + */ +public class OrphanedNodeCheck implements DocumentProcessor, Closeable { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final ExecutorService executorService; + + public OrphanedNodeCheck(DocumentNodeStore ns, + RevisionVector headRevision, + int numThread) { + this.ns = ns; + this.headRevision = headRevision; + this.executorService = new ThreadPoolExecutor( + numThread, numThread, 1, TimeUnit.MINUTES, + new LinkedBlockingQueue<>(1000), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + if (!document.isSplitDocument()) { + executorService.submit(new CheckDocument(ns, headRevision, document, results)); + } + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) { + String msg = "Checks still not finished after the last one has been submitted 5 minutes ago"; + results.put(() -> { + StringBuilder sb = new StringBuilder("{"); + sb.append("\"time\": \"").append(nowAsISO8601()).append('"'); + sb.append(", \"info\": \"").append(msg).append('"'); + sb.append("}"); + return sb.toString(); + }); + } + } + + @Override + public void close() throws IOException { + new ExecutorCloser(executorService, 5, TimeUnit.MINUTES).close(); + } + + private static final class CheckDocument implements Callable<Void> { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final NodeDocument doc; + + private final BlockingQueue<Result> results; + + CheckDocument(DocumentNodeStore ns, + RevisionVector headRevision, + NodeDocument doc, + BlockingQueue<Result> results) { + this.ns = ns; + this.headRevision = headRevision; + this.doc = doc; + this.results = results; + } + + @Override + public Void call() throws Exception { + DocumentNodeState state = doc.getNodeAtRevision(ns, headRevision, null); + if (state != null) { + Path path = doc.getPath(); + Path missing = assertAncestorsExist(path.getParent()); + if (missing != null) { + results.put(new OrphanedNode(path, missing, state.getLastRevision())); + } + } + return null; + } + + private Path assertAncestorsExist(Path path) { + if (path == null) { + return null; + } + NodeState state = ns.getRoot(); + Path p = Path.ROOT; + for (String name : path.elements()) { + p = new Path(p, name); + state = state.getChildNode(name); + if (!state.exists()) { + return p; + } + } + return null; + } + } + + private static final class OrphanedNode implements Result { + + final Path orphaned; + + final Path missing; + + final RevisionVector revision; + + public OrphanedNode(Path orphaned, Path missing, RevisionVector revision) { + this.orphaned = orphaned; + this.missing = missing; + this.revision = revision; + } + + + @Override + public String toJson() { + return "{\"orphaned\": \"" + orphaned + "\", \"revision\": \"" + revision + "\", \"missing\": \"" + missing + "\"}"; Review Comment: Same as above, use Json lib to create json. ########## oak-run/src/main/java/org/apache/jackrabbit/oak/plugins/document/check/OrphanedNodeCheck.java: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.document.check; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.NodeDocument; +import org.apache.jackrabbit.oak.plugins.document.Path; +import org.apache.jackrabbit.oak.plugins.document.RevisionVector; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * <code>OrphanedNodeCheck</code>... + */ +public class OrphanedNodeCheck implements DocumentProcessor, Closeable { + + private final DocumentNodeStore ns; + + private final RevisionVector headRevision; + + private final ExecutorService executorService; + + public OrphanedNodeCheck(DocumentNodeStore ns, + RevisionVector headRevision, + int numThread) { + this.ns = ns; + this.headRevision = headRevision; + this.executorService = new ThreadPoolExecutor( + numThread, numThread, 1, TimeUnit.MINUTES, + new LinkedBlockingQueue<>(1000), + new ThreadPoolExecutor.CallerRunsPolicy() + ); + } + + @Override + public void processDocument(@NotNull NodeDocument document, + @NotNull BlockingQueue<Result> results) { + if (!document.isSplitDocument()) { + executorService.submit(new CheckDocument(ns, headRevision, document, results)); + } + } + + @Override + public void end(@NotNull BlockingQueue<Result> results) + throws InterruptedException { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) { + String msg = "Checks still not finished after the last one has been submitted 5 minutes ago"; + results.put(() -> { + StringBuilder sb = new StringBuilder("{"); Review Comment: Can we please use JsonObject to create JSON? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
