HBASE-1484 commit log split writes files with newest edits first (since hbase-1430); should be other way round

git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@781905 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2009-06-05 03:54:23 +00:00
parent 4346eec59d
commit c72bd42fb4
3 changed files with 101 additions and 32 deletions

View File

@ -86,9 +86,7 @@ Release 0.20.0 - Unreleased
HBASE-1310 Off by one error in Bytes.vintToBytes HBASE-1310 Off by one error in Bytes.vintToBytes
HBASE-1202 getRow does not always work when specifying number of versions HBASE-1202 getRow does not always work when specifying number of versions
HBASE-1324 hbase-1234 broke testget2 unit test (and broke the build) HBASE-1324 hbase-1234 broke testget2 unit test (and broke the build)
HBASE-1321 hbase-1234 broke TestCompaction; fix and reenable HBASE-1321 hbase-1234 broke TestCompaction; fix and reenable HBASE-1330 binary keys broken on trunk (Ryan Rawson via Stack) HBASE-1332 regionserver carrying .META. starts sucking all cpu, drives load
HBASE-1330 binary keys broken on trunk (Ryan Rawson via Stack)
HBASE-1332 regionserver carrying .META. starts sucking all cpu, drives load
up - infinite loop? (Ryan Rawson via Stack) up - infinite loop? (Ryan Rawson via Stack)
HBASE-1334 .META. region running into hfile errors (Ryan Rawson via Stack) HBASE-1334 .META. region running into hfile errors (Ryan Rawson via Stack)
HBASE-1338 lost use of compaction.dir; we were compacting into live store HBASE-1338 lost use of compaction.dir; we were compacting into live store
@ -163,6 +161,8 @@ Release 0.20.0 - Unreleased
HBASE-1471 During cluster shutdown, deleting zookeeper regionserver nodes HBASE-1471 During cluster shutdown, deleting zookeeper regionserver nodes
causes exceptions causes exceptions
HBASE-1483 HLog split loses track of edits (Clint Morgan via Stack) HBASE-1483 HLog split loses track of edits (Clint Morgan via Stack)
HBASE-1484 commit log split writes files with newest edits first
(since hbase-1430); should be other way round
IMPROVEMENTS IMPROVEMENTS
HBASE-1089 Add count of regions on filesystem to master UI; add percentage HBASE-1089 Add count of regions on filesystem to master UI; add percentage

View File

@ -23,9 +23,11 @@ import java.io.EOFException;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
@ -96,7 +98,7 @@ import org.apache.hadoop.io.compress.DefaultCodec;
* *
*/ */
public class HLog implements HConstants, Syncable { public class HLog implements HConstants, Syncable {
private static final Log LOG = LogFactory.getLog(HLog.class); static final Log LOG = LogFactory.getLog(HLog.class);
private static final String HLOG_DATFILE = "hlog.dat."; private static final String HLOG_DATFILE = "hlog.dat.";
static final byte [] METACOLUMN = Bytes.toBytes("METACOLUMN:"); static final byte [] METACOLUMN = Bytes.toBytes("METACOLUMN:");
static final byte [] METAROW = Bytes.toBytes("METAROW"); static final byte [] METAROW = Bytes.toBytes("METAROW");
@ -224,7 +226,7 @@ public class HLog implements HConstants, Syncable {
* @param c Configuration to use. * @param c Configuration to use.
* @return the kind of compression to use * @return the kind of compression to use
*/ */
private static CompressionType getCompressionType(final Configuration c) { static CompressionType getCompressionType(final Configuration c) {
// Compression makes no sense for commit log. Always return NONE. // Compression makes no sense for commit log. Always return NONE.
return CompressionType.NONE; return CompressionType.NONE;
} }
@ -551,6 +553,7 @@ public class HLog implements HConstants, Syncable {
for (KeyValue kv: edits) { for (KeyValue kv: edits) {
HLogKey logKey = HLogKey logKey =
new HLogKey(regionName, tableName, seqNum[counter++], now); new HLogKey(regionName, tableName, seqNum[counter++], now);
System.out.println("REMOVE " + logKey);
doWrite(logKey, kv, sync, now); doWrite(logKey, kv, sync, now);
this.numEntries.incrementAndGet(); this.numEntries.incrementAndGet();
} }
@ -733,22 +736,23 @@ public class HLog implements HConstants, Syncable {
* @param conf HBaseConfiguration * @param conf HBaseConfiguration
* @throws IOException * @throws IOException
*/ */
public static void splitLog(final Path rootDir, final Path srcDir, public static List<Path> splitLog(final Path rootDir, final Path srcDir,
final FileSystem fs, final Configuration conf) final FileSystem fs, final Configuration conf)
throws IOException { throws IOException {
long millis = System.currentTimeMillis(); long millis = System.currentTimeMillis();
List<Path> splits = null;
if (!fs.exists(srcDir)) { if (!fs.exists(srcDir)) {
// Nothing to do // Nothing to do
return; return splits;
} }
FileStatus [] logfiles = fs.listStatus(srcDir); FileStatus [] logfiles = fs.listStatus(srcDir);
if (logfiles == null || logfiles.length == 0) { if (logfiles == null || logfiles.length == 0) {
// Nothing to do // Nothing to do
return; return splits;
} }
LOG.info("Splitting " + logfiles.length + " hlog(s) in " + LOG.info("Splitting " + logfiles.length + " hlog(s) in " +
srcDir.toString()); srcDir.toString());
splitLog(rootDir, logfiles, fs, conf); splits = splitLog(rootDir, logfiles, fs, conf);
try { try {
fs.delete(srcDir, true); fs.delete(srcDir, true);
} catch (IOException e) { } catch (IOException e) {
@ -760,21 +764,33 @@ public class HLog implements HConstants, Syncable {
long endMillis = System.currentTimeMillis(); long endMillis = System.currentTimeMillis();
LOG.info("hlog file splitting completed in " + (endMillis - millis) + LOG.info("hlog file splitting completed in " + (endMillis - millis) +
" millis for " + srcDir.toString()); " millis for " + srcDir.toString());
return splits;
} }
// Private immutable datastructure to hold Writer and its Path.
private final static class WriterAndPath {
final Path p;
final SequenceFile.Writer w;
WriterAndPath(final Path p, final SequenceFile.Writer w) {
this.p = p;
this.w = w;
}
}
/* /*
* @param rootDir * @param rootDir
* @param logfiles * @param logfiles
* @param fs * @param fs
* @param conf * @param conf
* @throws IOException * @throws IOException
* @return List of splits made.
*/ */
private static void splitLog(final Path rootDir, final FileStatus [] logfiles, private static List<Path> splitLog(final Path rootDir,
final FileSystem fs, final Configuration conf) final FileStatus [] logfiles, final FileSystem fs, final Configuration conf)
throws IOException { throws IOException {
final Map<byte [], SequenceFile.Writer> logWriters = final Map<byte [], WriterAndPath> logWriters =
new TreeMap<byte [], SequenceFile.Writer>(Bytes.BYTES_COMPARATOR); new TreeMap<byte [], WriterAndPath>(Bytes.BYTES_COMPARATOR);
List<Path> splits = null;
try { try {
int maxSteps = Double.valueOf(Math.ceil((logfiles.length * 1.0) / int maxSteps = Double.valueOf(Math.ceil((logfiles.length * 1.0) /
DEFAULT_NUMBER_CONCURRENT_LOG_READS)).intValue(); DEFAULT_NUMBER_CONCURRENT_LOG_READS)).intValue();
@ -796,7 +812,7 @@ public class HLog implements HConstants, Syncable {
// HADOOP-4751 is committed. // HADOOP-4751 is committed.
long length = logfiles[i].getLen(); long length = logfiles[i].getLen();
SequenceFile.Reader in = null; SequenceFile.Reader in = null;
int count = 0; int count = 0;
try { try {
in = new SequenceFile.Reader(fs, logfiles[i].getPath(), conf); in = new SequenceFile.Reader(fs, logfiles[i].getPath(), conf);
try { try {
@ -810,7 +826,9 @@ public class HLog implements HConstants, Syncable {
LOG.debug("Adding queue for " + Bytes.toString(regionName)); LOG.debug("Adding queue for " + Bytes.toString(regionName));
logEntries.put(regionName, queue); logEntries.put(regionName, queue);
} }
queue.push(new HLogEntry(val, key)); HLogEntry hle = new HLogEntry(val, key);
System.out.println("REMOVE !! " + hle);
queue.push(hle);
count++; count++;
// Make the key and value new each time; otherwise same instance // Make the key and value new each time; otherwise same instance
// is used over and over. // is used over and over.
@ -853,7 +871,6 @@ public class HLog implements HConstants, Syncable {
ExecutorService threadPool = ExecutorService threadPool =
Executors.newFixedThreadPool(DEFAULT_NUMBER_LOG_WRITER_THREAD); Executors.newFixedThreadPool(DEFAULT_NUMBER_LOG_WRITER_THREAD);
for (final byte[] key : logEntries.keySet()) { for (final byte[] key : logEntries.keySet()) {
Thread thread = new Thread(Bytes.toString(key)) { Thread thread = new Thread(Bytes.toString(key)) {
public void run() { public void run() {
LinkedList<HLogEntry> entries = logEntries.get(key); LinkedList<HLogEntry> entries = logEntries.get(key);
@ -861,9 +878,14 @@ public class HLog implements HConstants, Syncable {
long threadTime = System.currentTimeMillis(); long threadTime = System.currentTimeMillis();
try { try {
int count = 0; int count = 0;
for (HLogEntry logEntry : entries) { // Items were added to the linkedlist oldest first. Pull them
SequenceFile.Writer w = logWriters.get(key); // out in that order.
if (w == null) { for (ListIterator<HLogEntry> i =
entries.listIterator(entries.size());
i.hasPrevious();) {
HLogEntry logEntry = i.previous();
WriterAndPath wap = logWriters.get(key);
if (wap == null) {
Path logfile = new Path(HRegion.getRegionDir(HTableDescriptor Path logfile = new Path(HRegion.getRegionDir(HTableDescriptor
.getTableDir(rootDir, logEntry.getKey().getTablename()), .getTableDir(rootDir, logEntry.getKey().getTablename()),
HRegionInfo.encodeRegionName(key)), HRegionInfo.encodeRegionName(key)),
@ -877,9 +899,11 @@ public class HLog implements HConstants, Syncable {
fs.rename(logfile, oldlogfile); fs.rename(logfile, oldlogfile);
old = new SequenceFile.Reader(fs, oldlogfile, conf); old = new SequenceFile.Reader(fs, oldlogfile, conf);
} }
w = SequenceFile.createWriter(fs, conf, logfile, SequenceFile.Writer w =
SequenceFile.createWriter(fs, conf, logfile,
HLogKey.class, KeyValue.class, getCompressionType(conf)); HLogKey.class, KeyValue.class, getCompressionType(conf));
logWriters.put(key, w); wap = new WriterAndPath(logfile, w);
logWriters.put(key, wap);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Creating new hlog file writer for path " LOG.debug("Creating new hlog file writer for path "
+ logfile + " and region " + Bytes.toString(key)); + logfile + " and region " + Bytes.toString(key));
@ -900,7 +924,10 @@ public class HLog implements HConstants, Syncable {
fs.delete(oldlogfile, true); fs.delete(oldlogfile, true);
} }
} }
w.append(logEntry.getKey(), logEntry.getEdit()); if (wap == null) {
throw new NullPointerException();
}
wap.w.append(logEntry.getKey(), logEntry.getEdit());
count++; count++;
} }
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
@ -929,12 +956,15 @@ public class HLog implements HConstants, Syncable {
} }
} }
} finally { } finally {
for (SequenceFile.Writer w : logWriters.values()) { splits = new ArrayList<Path>(logWriters.size());
w.close(); for (WriterAndPath wap : logWriters.values()) {
wap.w.close();
splits.add(wap.p);
} }
} }
return splits;
} }
/** /**
* Utility class that lets us keep track of the edit with it's key * Utility class that lets us keep track of the edit with it's key
* Only used when splitting logs * Only used when splitting logs
@ -967,6 +997,9 @@ public class HLog implements HConstants, Syncable {
return key; return key;
} }
public String toString() {
return this.key + "=" + this.edit;
}
} }
/** /**

View File

@ -32,6 +32,7 @@ import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.io.SequenceFile; import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.Reader; import org.apache.hadoop.io.SequenceFile.Reader;
/** JUnit test case for HLog */ /** JUnit test case for HLog */
public class TestHLog extends HBaseTestCase implements HConstants { public class TestHLog extends HBaseTestCase implements HConstants {
private Path dir; private Path dir;
@ -68,22 +69,26 @@ public class TestHLog extends HBaseTestCase implements HConstants {
final byte [] tableName = Bytes.toBytes(getName()); final byte [] tableName = Bytes.toBytes(getName());
final byte [] rowName = tableName; final byte [] rowName = tableName;
HLog log = new HLog(this.fs, this.dir, this.conf, null); HLog log = new HLog(this.fs, this.dir, this.conf, null);
final int howmany = 3;
// Add edits for three regions. // Add edits for three regions.
try { try {
for (int ii = 0; ii < 3; ii++) { for (int ii = 0; ii < howmany; ii++) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < howmany; i++) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < howmany; j++) {
List<KeyValue> edit = new ArrayList<KeyValue>(); List<KeyValue> edit = new ArrayList<KeyValue>();
byte [] column = Bytes.toBytes("column:" + Integer.toString(j)); byte [] column = Bytes.toBytes("column:" + Integer.toString(j));
edit.add(new KeyValue(rowName, column, System.currentTimeMillis(), edit.add(new KeyValue(rowName, column, System.currentTimeMillis(),
column)); column));
log.append(Bytes.toBytes(Integer.toString(i)), tableName, edit, System.out.println("Region " + i + ": " + edit);
log.append(Bytes.toBytes("" + i), tableName, edit,
false, System.currentTimeMillis()); false, System.currentTimeMillis());
} }
} }
log.rollWriter(); log.rollWriter();
} }
HLog.splitLog(this.testDir, this.dir, this.fs, this.conf); List<Path> splits =
HLog.splitLog(this.testDir, this.dir, this.fs, this.conf);
verifySplits(splits, howmany);
log = null; log = null;
} finally { } finally {
if (log != null) { if (log != null) {
@ -92,6 +97,37 @@ public class TestHLog extends HBaseTestCase implements HConstants {
} }
} }
private void verifySplits(List<Path> splits, final int howmany)
throws IOException {
assertEquals(howmany, splits.size());
for (int i = 0; i < splits.size(); i++) {
SequenceFile.Reader r =
new SequenceFile.Reader(this.fs, splits.get(i), this.conf);
try {
HLogKey key = new HLogKey();
KeyValue kv = new KeyValue();
int count = 0;
String previousRegion = null;
long seqno = -1;
while(r.next(key, kv)) {
String region = Bytes.toString(key.getRegionName());
// Assert that all edits are for same region.
if (previousRegion != null) {
assertEquals(previousRegion, region);
}
assertTrue(seqno < key.getLogSeqNum());
seqno = key.getLogSeqNum();
previousRegion = region;
System.out.println(key + " " + kv);
count++;
}
assertEquals(howmany * howmany, count);
} finally {
r.close();
}
}
}
/** /**
* @throws IOException * @throws IOException
*/ */