org.apache.jackrabbit.oak.run.DebugCommand Maven / Gradle / Ivy
/*
* 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.run;
import static com.google.common.collect.Sets.newHashSet;
import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
import static org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.openReadOnlyFileStore;
import static org.apache.jackrabbit.oak.plugins.segment.RecordType.NODE;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
import org.apache.jackrabbit.oak.explorer.NodeStoreTree;
import org.apache.jackrabbit.oak.json.JsopDiff;
import org.apache.jackrabbit.oak.plugins.segment.PCMAnalyser;
import org.apache.jackrabbit.oak.plugins.segment.RecordId;
import org.apache.jackrabbit.oak.plugins.segment.RecordUsageAnalyser;
import org.apache.jackrabbit.oak.plugins.segment.Segment;
import org.apache.jackrabbit.oak.plugins.segment.SegmentId;
import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeState;
import org.apache.jackrabbit.oak.plugins.segment.SegmentTracker;
import org.apache.jackrabbit.oak.plugins.segment.file.FileStore;
import org.apache.jackrabbit.oak.spi.state.NodeState;
class DebugCommand implements Command {
private static void debugFileStore(FileStore store) {
Map> idmap = Maps.newHashMap();
int dataCount = 0;
long dataSize = 0;
int bulkCount = 0;
long bulkSize = 0;
((Logger) getLogger(SegmentTracker.class)).setLevel(Level.OFF);
RecordUsageAnalyser analyser = new RecordUsageAnalyser();
for (SegmentId id : store.getSegmentIds()) {
if (id.isDataSegmentId()) {
Segment segment = id.getSegment();
dataCount++;
dataSize += segment.size();
idmap.put(id, segment.getReferencedIds());
analyseSegment(segment, analyser);
} else if (id.isBulkSegmentId()) {
bulkCount++;
bulkSize += id.getSegment().size();
idmap.put(id, Collections.emptyList());
}
}
System.out.println("Total size:");
System.out.format(
"%s in %6d data segments%n",
byteCountToDisplaySize(dataSize), dataCount);
System.out.format(
"%s in %6d bulk segments%n",
byteCountToDisplaySize(bulkSize), bulkCount);
System.out.println(analyser.toString());
Set garbage = newHashSet(idmap.keySet());
Queue queue = Queues.newArrayDeque();
queue.add(store.getHead().getRecordId().getSegmentId());
while (!queue.isEmpty()) {
SegmentId id = queue.remove();
if (garbage.remove(id)) {
queue.addAll(idmap.get(id));
}
}
dataCount = 0;
dataSize = 0;
bulkCount = 0;
bulkSize = 0;
for (SegmentId id : garbage) {
if (id.isDataSegmentId()) {
dataCount++;
dataSize += id.getSegment().size();
} else if (id.isBulkSegmentId()) {
bulkCount++;
bulkSize += id.getSegment().size();
}
}
System.out.format("%nAvailable for garbage collection:%n");
System.out.format("%s in %6d data segments%n",
byteCountToDisplaySize(dataSize), dataCount);
System.out.format("%s in %6d bulk segments%n",
byteCountToDisplaySize(bulkSize), bulkCount);
System.out.format("%n%s", new PCMAnalyser(store).toString());
}
private static void analyseSegment(Segment segment, RecordUsageAnalyser analyser) {
for (int k = 0; k < segment.getRootCount(); k++) {
if (segment.getRootType(k) == NODE) {
RecordId nodeId = new RecordId(segment.getSegmentId(), segment.getRootOffset(k));
try {
analyser.analyseNode(nodeId);
} catch (Exception e) {
System.err.format("Error while processing node at %s", nodeId);
e.printStackTrace();
}
}
}
}
private static void debugTarFile(FileStore store, String[] args) {
File root = new File(args[0]);
for (int i = 1; i < args.length; i++) {
String f = args[i];
if (!f.endsWith(".tar")) {
System.out.println("skipping " + f);
continue;
}
File tar = new File(root, f);
if (!tar.exists()) {
System.out.println("file doesn't exist, skipping " + f);
continue;
}
System.out.println("Debug file " + tar + "(" + tar.length() + ")");
Set uuids = new HashSet();
boolean hasrefs = false;
for (Map.Entry> e : store.getTarReaderIndex()
.entrySet()) {
if (e.getKey().endsWith(f)) {
hasrefs = true;
uuids = e.getValue();
}
}
if (hasrefs) {
System.out.println("SegmentNodeState references to " + f);
List paths = new ArrayList();
NodeStoreTree.filterNodeStates(uuids, paths, store.getHead(),
"/");
for (String p : paths) {
System.out.println(" " + p);
}
} else {
System.out.println("No references to " + f);
}
try {
Map> graph = store.getTarGraph(f);
System.out.println();
System.out.println("Tar graph:");
for (Map.Entry> entry : graph.entrySet()) {
System.out.println("" + entry.getKey() + '=' + entry.getValue());
}
} catch (IOException e) {
System.out.println("Error getting tar graph:");
}
}
}
private static void debugSegment(FileStore store, String[] args) {
Pattern pattern = Pattern
.compile("([0-9a-f-]+)|(([0-9a-f-]+:[0-9a-f]+)(-([0-9a-f-]+:[0-9a-f]+))?)?(/.*)?");
for (int i = 1; i < args.length; i++) {
Matcher matcher = pattern.matcher(args[i]);
if (!matcher.matches()) {
System.err.println("Unknown argument: " + args[i]);
} else if (matcher.group(1) != null) {
UUID uuid = UUID.fromString(matcher.group(1));
SegmentId id = store.getTracker().getSegmentId(
uuid.getMostSignificantBits(),
uuid.getLeastSignificantBits());
System.out.println(id.getSegment());
} else {
RecordId id1 = store.getHead().getRecordId();
RecordId id2 = null;
if (matcher.group(2) != null) {
id1 = RecordId.fromString(store.getTracker(),
matcher.group(3));
if (matcher.group(4) != null) {
id2 = RecordId.fromString(store.getTracker(),
matcher.group(5));
}
}
String path = "/";
if (matcher.group(6) != null) {
path = matcher.group(6);
}
if (id2 == null) {
NodeState node = new SegmentNodeState(id1);
System.out.println("/ (" + id1 + ") -> " + node);
for (String name : PathUtils.elements(path)) {
node = node.getChildNode(name);
RecordId nid = null;
if (node instanceof SegmentNodeState) {
nid = ((SegmentNodeState) node).getRecordId();
}
System.out.println(" " + name + " (" + nid + ") -> "
+ node);
}
} else {
NodeState node1 = new SegmentNodeState(id1);
NodeState node2 = new SegmentNodeState(id2);
for (String name : PathUtils.elements(path)) {
node1 = node1.getChildNode(name);
node2 = node2.getChildNode(name);
}
System.out.println(JsopBuilder.prettyPrint(JsopDiff
.diffToJsop(node1, node2)));
}
}
}
}
@Override
public void execute(String... args) throws Exception {
if (args.length == 0) {
System.err.println("usage: debug [id...]");
System.exit(1);
} else {
// TODO: enable debug information for other node store implementations
File file = new File(args[0]);
System.out.println("Debug " + file);
FileStore store = openReadOnlyFileStore(file);
try {
if (args.length == 1) {
debugFileStore(store);
} else {
if (args[1].endsWith(".tar")) {
debugTarFile(store, args);
} else {
debugSegment(store, args);
}
}
} finally {
store.close();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy