HBASE-834 'Major' compactions and upper bound on files we compact at any one time

git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@690423 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2008-08-29 23:36:02 +00:00
parent 93ab23183b
commit 99f695beda
5 changed files with 88 additions and 18 deletions

View File

@ -43,6 +43,8 @@ Release 0.18.0 - Unreleased
its migration first' is useless (Jean-Daniel Cryans via Jim its migration first' is useless (Jean-Daniel Cryans via Jim
Kellerman) Kellerman)
HBASE-826 Delete table followed by recreation results in honked table HBASE-826 Delete table followed by recreation results in honked table
HBASE-834 'Major' compactions and upper bound on files we compact at any
one time (Billy Pearson via Stack)
IMPROVEMENTS IMPROVEMENTS
HBASE-801 When a table haven't disable, shell could response in a "user HBASE-801 When a table haven't disable, shell could response in a "user

View File

@ -196,7 +196,7 @@ module HBase
end end
def getAllColumns def getAllColumns
htd = @table.getMetadata() htd = @table.getTableDescriptor()
result = [] result = []
for f in htd.getFamilies() for f in htd.getFamilies()
n = f.getNameAsString() n = f.getNameAsString()

View File

@ -250,6 +250,20 @@
<description>How often a region server runs the split/compaction check. <description>How often a region server runs the split/compaction check.
</description> </description>
</property> </property>
<property>
<name>hbase.hstore.compaction.max</name>
<value>10</value>
<description>Max number of HStoreFiles to compact per 'minor' compaction.
</description>
</property>
<property>
<name>hbase.hregion.majorcompaction</name>
<value>86400000</value>
<description>The time (in miliseconds) between 'major' compactions of all
HStoreFiles in a region. Default: 1 day.
</description>
</property>
<property>
<property> <property>
<name>hbase.regionserver.nbreservationblocks</name> <name>hbase.regionserver.nbreservationblocks</name>
<value>4</value> <value>4</value>

View File

@ -869,12 +869,11 @@ public class HRegion implements HConstants {
* conflicts with a region split, and that cannot happen because the region * conflicts with a region split, and that cannot happen because the region
* server does them sequentially and not in parallel. * server does them sequentially and not in parallel.
* *
* @param force True to force a compaction regardless of thresholds (Needed * @param majorCompaction True to force a major compaction regardless of thresholds
* by merge).
* @return mid key if split is needed * @return mid key if split is needed
* @throws IOException * @throws IOException
*/ */
private byte [] compactStores(final boolean force) throws IOException { private byte [] compactStores(final boolean majorCompaction) throws IOException {
splitsAndClosesLock.readLock().lock(); splitsAndClosesLock.readLock().lock();
try { try {
byte [] midKey = null; byte [] midKey = null;
@ -897,7 +896,7 @@ public class HRegion implements HConstants {
doRegionCompactionPrep(); doRegionCompactionPrep();
long maxSize = -1; long maxSize = -1;
for (HStore store: stores.values()) { for (HStore store: stores.values()) {
final HStore.StoreSize size = store.compact(force); final HStore.StoreSize size = store.compact(majorCompaction);
if (size != null && size.getSize() > maxSize) { if (size != null && size.getSize() > maxSize) {
maxSize = size.getSize(); maxSize = size.getSize();
midKey = size.getKey(); midKey = size.getKey();
@ -1528,6 +1527,7 @@ public class HRegion implements HConstants {
List<HStoreKey> keys = store.getKeys(new HStoreKey(row, ts), List<HStoreKey> keys = store.getKeys(new HStoreKey(row, ts),
ALL_VERSIONS, now); ALL_VERSIONS, now);
TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>(); TreeMap<HStoreKey, byte []> edits = new TreeMap<HStoreKey, byte []>();
LOG.info("GETKEYS REMOVE " + keys);
for (HStoreKey key: keys) { for (HStoreKey key: keys) {
edits.put(key, HLogEdit.deleteBytes.get()); edits.put(key, HLogEdit.deleteBytes.get());
} }

View File

@ -86,7 +86,8 @@ public class HStore implements HConstants {
final FileSystem fs; final FileSystem fs;
private final HBaseConfiguration conf; private final HBaseConfiguration conf;
protected long ttl; protected long ttl;
private long majorCompactionTime;
private int maxFilesToCompact;
private final long desiredMaxFileSize; private final long desiredMaxFileSize;
private volatile long storeSize; private volatile long storeSize;
@ -187,6 +188,8 @@ public class HStore implements HConstants {
} }
this.desiredMaxFileSize = maxFileSize; this.desiredMaxFileSize = maxFileSize;
this.majorCompactionTime = conf.getLong("hbase.hregion.majorcompaction", 86400000);
this.maxFilesToCompact = conf.getInt("hbase.hstore.compaction.max", 10);
this.storeSize = 0L; this.storeSize = 0L;
if (family.getCompression() == HColumnDescriptor.CompressionType.BLOCK) { if (family.getCompression() == HColumnDescriptor.CompressionType.BLOCK) {
@ -709,6 +712,28 @@ public class HStore implements HConstants {
return false; return false;
} }
/*
* Gets lowest timestamp from files in a dir
*
* @param fs
* @param dir
* @throws IOException
*/
private static long getLowestTimestamp(FileSystem fs, Path dir) throws IOException {
FileStatus[] stats = fs.listStatus(dir);
if (stats == null || stats.length == 0) {
return 0l;
}
long lowTimestamp = Long.MAX_VALUE;
for (int i = 0; i < stats.length; i++) {
long timestamp = stats[i].getModificationTime();
if (timestamp < lowTimestamp){
lowTimestamp = timestamp;
}
}
return lowTimestamp;
}
/** /**
* Compact the back-HStores. This method may take some time, so the calling * Compact the back-HStores. This method may take some time, so the calling
* thread must be able to block for long periods. * thread must be able to block for long periods.
@ -725,12 +750,12 @@ public class HStore implements HConstants {
* We don't want to hold the structureLock for the whole time, as a compact() * We don't want to hold the structureLock for the whole time, as a compact()
* can be lengthy and we want to allow cache-flushes during this period. * can be lengthy and we want to allow cache-flushes during this period.
* *
* @param force True to force a compaction regardless of thresholds (Needed * @param majorCompaction True to force a major compaction regardless of
* by merge). * thresholds
* @return mid key if a split is needed, null otherwise * @return mid key if a split is needed, null otherwise
* @throws IOException * @throws IOException
*/ */
StoreSize compact(final boolean force) throws IOException { StoreSize compact(boolean majorCompaction) throws IOException {
synchronized (compactLock) { synchronized (compactLock) {
long maxId = -1; long maxId = -1;
int nrows = -1; int nrows = -1;
@ -746,7 +771,29 @@ public class HStore implements HConstants {
// last key of storefiles. // last key of storefiles.
maxId = this.storefiles.lastKey().longValue(); maxId = this.storefiles.lastKey().longValue();
} }
if (!force && !hasReferences(filesToCompact) && // Check to see if we need to do a major compaction on this region.
// If so, change majorCompaction to true to skip the incremental compacting below.
// Only check if majorCompaction is not true.
long lastMajorCompaction = 0L;
if (!majorCompaction) {
Path mapdir = HStoreFile.getMapDir(basedir, info.getEncodedName(), family.getName());
long lowTimestamp = getLowestTimestamp(fs, mapdir);
if (LOG.isDebugEnabled() && lowTimestamp > 0l) {
LOG.debug("Time since last major compaction on store " + this.storeNameStr +
": " + ((System.currentTimeMillis() - lowTimestamp)/1000) + " seconds");
}
lastMajorCompaction = System.currentTimeMillis() - lowTimestamp;
if (lowTimestamp < (System.currentTimeMillis() - majorCompactionTime) &&
lowTimestamp > 0l) {
if (LOG.isDebugEnabled()) {
LOG.debug("Major compaction triggered on store: " + this.storeNameStr +
". Time since last major compaction: " +
((System.currentTimeMillis() - lowTimestamp)/1000) + " seconds");
}
majorCompaction = true;
}
}
if (!majorCompaction && !hasReferences(filesToCompact) &&
filesToCompact.size() < compactionThreshold) { filesToCompact.size() < compactionThreshold) {
return checkSplit(); return checkSplit();
} }
@ -772,13 +819,13 @@ public class HStore implements HConstants {
fileSizes[i] = len; fileSizes[i] = len;
totalSize += len; totalSize += len;
} }
if (!force && !hasReferences(filesToCompact)) { if (!majorCompaction && !hasReferences(filesToCompact)) {
// Here we select files for incremental compaction. // Here we select files for incremental compaction.
// The rule is: if the largest(oldest) one is more than twice the // The rule is: if the largest(oldest) one is more than twice the
// size of the second, skip the largest, and continue to next..., // size of the second, skip the largest, and continue to next...,
// until we meet the compactionThreshold limit. // until we meet the compactionThreshold limit.
for (point = 0; point < compactionThreshold - 1; point++) { for (point = 0; point < compactionThreshold - 1; point++) {
if (fileSizes[point] < fileSizes[point + 1] * 2) { if (fileSizes[point] < fileSizes[point + 1] * 2 && maxFilesToCompact < (countOfFiles - point)) {
break; break;
} }
skipped += fileSizes[point]; skipped += fileSizes[point];
@ -839,7 +886,7 @@ public class HStore implements HConstants {
this.compression, this.family.isBloomfilter(), nrows); this.compression, this.family.isBloomfilter(), nrows);
writer.setIndexInterval(family.getMapFileIndexInterval()); writer.setIndexInterval(family.getMapFileIndexInterval());
try { try {
compact(writer, rdrs); compact(writer, rdrs, majorCompaction);
} finally { } finally {
writer.close(); writer.close();
} }
@ -851,7 +898,9 @@ public class HStore implements HConstants {
completeCompaction(filesToCompact, compactedOutputFile); completeCompaction(filesToCompact, compactedOutputFile);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Completed compaction of " + this.storeNameStr + LOG.debug("Completed compaction of " + this.storeNameStr +
" store size is " + StringUtils.humanReadableInt(storeSize)); " store size is " + StringUtils.humanReadableInt(storeSize) +
(majorCompaction? "": "; time since last major compaction: " +
(lastMajorCompaction/1000) + " seconds"));
} }
} }
return checkSplit(); return checkSplit();
@ -865,10 +914,12 @@ public class HStore implements HConstants {
* by timestamp. * by timestamp.
* @param compactedOut Where to write compaction. * @param compactedOut Where to write compaction.
* @param pReaders List of readers sorted oldest to newest. * @param pReaders List of readers sorted oldest to newest.
* @param majorCompaction True to force a major compaction regardless of
* thresholds
* @throws IOException * @throws IOException
*/ */
private void compact(final MapFile.Writer compactedOut, private void compact(final MapFile.Writer compactedOut,
final List<MapFile.Reader> pReaders) final List<MapFile.Reader> pReaders, final boolean majorCompaction)
throws IOException { throws IOException {
// Reverse order so we newest is first. // Reverse order so we newest is first.
List<MapFile.Reader> copy = new ArrayList<MapFile.Reader>(pReaders); List<MapFile.Reader> copy = new ArrayList<MapFile.Reader>(pReaders);
@ -926,7 +977,10 @@ public class HStore implements HConstants {
timesSeen = 0; timesSeen = 0;
} }
if (timesSeen <= family.getMaxVersions()) { // Added majorCompaction here to make sure all versions make it to
// the major compaction so we do not remove the wrong last versions
// this effected HBASE-826
if (timesSeen <= family.getMaxVersions() || !majorCompaction) {
// Keep old versions until we have maxVersions worth. // Keep old versions until we have maxVersions worth.
// Then just skip them. // Then just skip them.
if (sk.getRow().length != 0 && sk.getColumn().length != 0) { if (sk.getRow().length != 0 && sk.getColumn().length != 0) {