blob: c41f8a6890b890905f44b58ab012cc30384b5309 [file] [log] [blame]
/*
* 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.segment.file;
import org.apache.jackrabbit.oak.spi.gc.GCMonitor;
import org.jetbrains.annotations.NotNull;
/**
* Monitors the compaction cycle and keeps a compacted nodes counter, in order
* to provide a best effort progress log based on extrapolating the previous
* size and node count and current size to deduce current node count.
*/
public class GCNodeWriteMonitor {
public static final GCNodeWriteMonitor EMPTY = new GCNodeWriteMonitor(
-1, GCMonitor.EMPTY);
/**
* Number of nodes the monitor will log a message, -1 to disable
*/
private final long gcProgressLog;
private final GCMonitor gcMonitor;
/**
* Start timestamp of compaction (reset at each {@code init()} call).
*/
private long start = 0;
/**
* Estimated nodes to compact per cycle (reset at each {@code init()} call).
*/
private long estimated = -1;
/**
* Number of compacted nodes
*/
private long nodes;
/**
* Number of compacted properties
*/
private long properties;
/**
* Number of compacted binaries
*/
private long binaries;
private boolean running = false;
public GCNodeWriteMonitor(long gcProgressLog, @NotNull GCMonitor gcMonitor) {
this.gcProgressLog = gcProgressLog;
this.gcMonitor = gcMonitor;
}
/**
* @param prevSize
* size from latest successful compaction
* @param prevCompactedNodes
* number of nodes compacted during latest compaction operation
* @param currentSize
* current repository size
*/
public synchronized void init(long prevSize, long prevCompactedNodes, long currentSize) {
if (prevCompactedNodes > 0) {
estimated = (long) (((double) currentSize / prevSize) * prevCompactedNodes);
gcMonitor.info(
"estimated number of nodes to compact is {}, based on {} nodes compacted to {} bytes "
+ "on disk in previous compaction and current size of {} bytes on disk.",
estimated, prevCompactedNodes, prevSize, currentSize);
} else {
gcMonitor.info("unable to estimate number of nodes for compaction, missing gc history.");
}
nodes = 0;
start = System.currentTimeMillis();
running = true;
}
public synchronized void onNode() {
nodes++;
if (gcProgressLog > 0 && nodes % gcProgressLog == 0) {
gcMonitor.info("compacted {} nodes, {} properties, {} binaries in {} ms. {}",
nodes, properties, binaries, System.currentTimeMillis() - start, getPercentageDone());
}
}
public synchronized void onProperty() {
properties++;
}
public synchronized void onBinary() {
binaries++;
}
public synchronized void finished() {
running = false;
}
/**
* Compacted nodes in current cycle
*/
public synchronized long getCompactedNodes() {
return nodes;
}
/**
* Estimated nodes to compact in current cycle. Can be {@code -1} if the
* estimation could not be performed.
*/
public synchronized long getEstimatedTotal() {
return estimated;
}
@NotNull
private String getPercentageDone() {
return estimated > 0
? getEstimatedPercentage() + "% complete."
: "";
}
/**
* Estimated completion percentage. Can be {@code -1} if the estimation
* could not be performed.
*/
public synchronized int getEstimatedPercentage() {
if (estimated > 0) {
if (!running) {
return 100;
} else {
return Math.min((int) (100 * ((double) nodes / estimated)), 99);
}
}
return -1;
}
public synchronized boolean isCompactionRunning() {
return running;
}
public long getGcProgressLog() {
return gcProgressLog;
}
}