Browse Source
A compaction of reftables is just copying the results of a MergedReftable into a ReftableWriter. Wrap this up into a utility. Change-Id: I6f5677d923e9628993a2d8b4b007a9b8662c9045stable-4.9
Shawn Pearce
7 years ago
2 changed files with 250 additions and 0 deletions
@ -0,0 +1,223 @@
|
||||
/* |
||||
* Copyright (C) 2017, Google Inc. |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package org.eclipse.jgit.internal.storage.reftable; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.util.ArrayDeque; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.eclipse.jgit.lib.PersonIdent; |
||||
import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats; |
||||
import org.eclipse.jgit.lib.ReflogEntry; |
||||
|
||||
/** |
||||
* Merges reftables and compacts them into a single output. |
||||
* <p> |
||||
* For a partial compaction callers should {@link #setIncludeDeletes(boolean)} |
||||
* to {@code true} to ensure the new reftable continues to use a delete marker |
||||
* to shadow any lower reftable that may have the reference present. |
||||
* <p> |
||||
* By default all log entries within the range defined by |
||||
* {@link #setMinUpdateIndex(long)} and {@link #setMaxUpdateIndex(long)} are |
||||
* copied, even if no references in the output file match the log records. |
||||
* Callers may truncate the log to a more recent time horizon with |
||||
* {@link #setOldestReflogTimeMillis(long)}, or disable the log altogether with |
||||
* {@code setOldestReflogTimeMillis(Long.MAX_VALUE)}. |
||||
*/ |
||||
public class ReftableCompactor { |
||||
private final ReftableWriter writer = new ReftableWriter(); |
||||
private final ArrayDeque<Reftable> tables = new ArrayDeque<>(); |
||||
|
||||
private boolean includeDeletes; |
||||
private long minUpdateIndex; |
||||
private long maxUpdateIndex; |
||||
private long oldestReflogTimeMillis; |
||||
private Stats stats; |
||||
|
||||
/** |
||||
* @param cfg |
||||
* configuration for the reftable. |
||||
* @return {@code this} |
||||
*/ |
||||
public ReftableCompactor setConfig(ReftableConfig cfg) { |
||||
writer.setConfig(cfg); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* @param deletes |
||||
* {@code true} to include deletions in the output, which may be |
||||
* necessary for partial compaction. |
||||
* @return {@code this} |
||||
*/ |
||||
public ReftableCompactor setIncludeDeletes(boolean deletes) { |
||||
includeDeletes = deletes; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* @param min |
||||
* the minimum update index for log entries that appear in the |
||||
* compacted reftable. This should be 1 higher than the prior |
||||
* reftable's {@code maxUpdateIndex} if this table will be used |
||||
* in a stack. |
||||
* @return {@code this} |
||||
*/ |
||||
public ReftableCompactor setMinUpdateIndex(long min) { |
||||
minUpdateIndex = min; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* @param max |
||||
* the maximum update index for log entries that appear in the |
||||
* compacted reftable. This should be at least 1 higher than the |
||||
* prior reftable's {@code maxUpdateIndex} if this table will be |
||||
* used in a stack. |
||||
* @return {@code this} |
||||
*/ |
||||
public ReftableCompactor setMaxUpdateIndex(long max) { |
||||
maxUpdateIndex = max; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* @param timeMillis |
||||
* oldest log time to preserve. Entries whose timestamps are |
||||
* {@code >= timeMillis} will be copied into the output file. Log |
||||
* entries that predate {@code timeMillis} will be discarded. |
||||
* Specified in Java standard milliseconds since the epoch. |
||||
* @return {@code this} |
||||
*/ |
||||
public ReftableCompactor setOldestReflogTimeMillis(long timeMillis) { |
||||
oldestReflogTimeMillis = timeMillis; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add all of the tables, in the specified order. |
||||
* |
||||
* @param readers |
||||
* tables to compact. Tables should be ordered oldest first/most |
||||
* recent last so that the more recent tables can shadow the |
||||
* older results. Caller is responsible for closing the readers. |
||||
*/ |
||||
public void addAll(List<? extends Reftable> readers) { |
||||
tables.addAll(readers); |
||||
} |
||||
|
||||
/** |
||||
* Write a compaction to {@code out}. |
||||
* |
||||
* @param out |
||||
* stream to write the compacted tables to. Caller is responsible |
||||
* for closing {@code out}. |
||||
* @throws IOException |
||||
* if tables cannot be read, or cannot be written. |
||||
*/ |
||||
public void compact(OutputStream out) throws IOException { |
||||
MergedReftable mr = new MergedReftable(new ArrayList<>(tables)); |
||||
mr.setIncludeDeletes(includeDeletes); |
||||
|
||||
writer.setMinUpdateIndex(minUpdateIndex); |
||||
writer.setMaxUpdateIndex(maxUpdateIndex); |
||||
writer.begin(out); |
||||
mergeRefs(mr); |
||||
mergeLogs(mr); |
||||
writer.finish(); |
||||
stats = writer.getStats(); |
||||
} |
||||
|
||||
/** @return statistics of the last written reftable. */ |
||||
public Stats getStats() { |
||||
return stats; |
||||
} |
||||
|
||||
private void mergeRefs(MergedReftable mr) throws IOException { |
||||
try (RefCursor rc = mr.allRefs()) { |
||||
while (rc.next()) { |
||||
writer.writeRef(rc.getRef()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void mergeLogs(MergedReftable mr) throws IOException { |
||||
if (oldestReflogTimeMillis == Long.MAX_VALUE) { |
||||
return; |
||||
} |
||||
|
||||
try (LogCursor lc = mr.allLogs()) { |
||||
while (lc.next()) { |
||||
long updateIndex = lc.getUpdateIndex(); |
||||
if (updateIndex < minUpdateIndex |
||||
|| updateIndex > maxUpdateIndex) { |
||||
// Cannot merge log records outside the header's range.
|
||||
continue; |
||||
} |
||||
|
||||
String refName = lc.getRefName(); |
||||
ReflogEntry log = lc.getReflogEntry(); |
||||
if (log == null) { |
||||
if (includeDeletes) { |
||||
writer.deleteLog(refName, updateIndex); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
PersonIdent who = log.getWho(); |
||||
if (who.getWhen().getTime() >= oldestReflogTimeMillis) { |
||||
writer.writeLog( |
||||
refName, |
||||
updateIndex, |
||||
who, |
||||
log.getOldId(), |
||||
log.getNewId(), |
||||
log.getComment()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue