Author: stack
Date: Tue Jul 21 21:18:52 2009
New Revision: 796542

URL: http://svn.apache.org/viewvc?rev=796542&view=rev
Log:
HBASE-1215 part 5 of migration; adds a migration test to unit suite with 
verification that migration worked

Added:
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMigration.java
Removed:
    hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/MigrationTest.java
Modified:
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HConstants.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/util/Migrate.java

Modified: 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java?rev=796542&r1=796541&r2=796542&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java 
(original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java 
Tue Jul 21 21:18:52 2009
@@ -391,7 +391,8 @@
   /** @return compression type being used for the column family */
   @TOJSON
   public Compression.Algorithm getCompression() {
-    return Compression.Algorithm.valueOf(getValue(COMPRESSION));
+    String n = getValue(COMPRESSION);
+    return Compression.Algorithm.valueOf(n.toUpperCase());
   }
   
   /** @return maximum number of versions */

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HConstants.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HConstants.java?rev=796542&r1=796541&r2=796542&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HConstants.java 
(original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HConstants.java Tue Jul 
21 21:18:52 2009
@@ -49,8 +49,8 @@
    * Version 6 enables blockcaching on catalog tables.
    * Version 7 introduces hfile -- hbase 0.19 to 0.20..
    */
-  public static final String FILE_SYSTEM_VERSION = "6";
-  // public static final String FILE_SYSTEM_VERSION = "7";
+  // public static final String FILE_SYSTEM_VERSION = "6";
+  public static final String FILE_SYSTEM_VERSION = "7";
   
   // Configuration parameters
   

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/util/Migrate.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/util/Migrate.java?rev=796542&r1=796541&r2=796542&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/util/Migrate.java 
(original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/util/Migrate.java Tue 
Jul 21 21:18:52 2009
@@ -21,6 +21,8 @@
 package org.apache.hadoop.hbase.util;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.commons.cli.Options;
 import org.apache.commons.logging.Log;
@@ -29,6 +31,7 @@
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathFilter;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
@@ -40,6 +43,7 @@
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.io.hfile.HFile;
+import org.apache.hadoop.hbase.io.hfile.Compression.Algorithm;
 import org.apache.hadoop.hbase.migration.nineteen.io.BloomFilterMapFile;
 import org.apache.hadoop.hbase.migration.nineteen.regionserver.HStoreFile;
 import org.apache.hadoop.hbase.regionserver.HRegion;
@@ -249,6 +253,7 @@
     }
     // TOOD: Verify all has been brought over from old to new layout.
     final MetaUtils utils = new MetaUtils(this.conf);
+    final List<HRegionInfo> metas = new ArrayList<HRegionInfo>();
     try {
       rewriteHRegionInfo(utils.getRootRegion().getRegionInfo());
       // Scan the root region
@@ -259,29 +264,53 @@
             migrationNeeded = true;
             return false;
           }
+          metas.add(info);
           rewriteHRegionInfo(utils.getRootRegion(), info);
           return true;
         }
       });
-      LOG.info("TODO: Note on make sure not using old hbase-default.xml");
-      /*
-       * hbase.master / hbase.master.hostname are obsolete, that's replaced by
-hbase.cluster.distributed. This config must be set to "true" to have a
-fully-distributed cluster and the server lines in zoo.cfg must not
-point to "localhost".
-
-The clients must have a valid zoo.cfg in their classpath since we
-don't provide the master address.
-
-hbase.master.dns.interface and hbase.master.dns.nameserver should be
-set to control the master's address (not mandatory).
-       */
-      LOG.info("TODO: Note on zookeeper config. before starting:");
+      // Scan meta.
+      for (HRegionInfo hri: metas) {
+        final HRegionInfo metahri = hri;
+        utils.scanMetaRegion(hri, new MetaUtils.ScannerListener() {
+          public boolean processRow(HRegionInfo info) throws IOException {
+            if (readOnly && !migrationNeeded) {
+              migrationNeeded = true;
+              return false;
+            }
+            rewriteHRegionInfo(utils.getMetaRegion(metahri), info);
+            return true;
+          }
+        });
+      }
+      cleanOldLogFiles(hbaseRootDir);
     } finally {
       utils.shutdown();
     }
   }
-  
+
+  /*
+   * Remove old log files.
+   * @param fs
+   * @param hbaseRootDir
+   * @throws IOException
+   */
+  private void cleanOldLogFiles(final Path hbaseRootDir)
+  throws IOException {
+    FileStatus [] oldlogfiles = fs.listStatus(hbaseRootDir, new PathFilter () {
+      public boolean accept(Path p) {
+        return p.getName().startsWith("log_");
+      }
+    });
+    // Return if nothing to do.
+    if (oldlogfiles.length <= 0) return;
+    LOG.info("Removing " + oldlogfiles.length + " old logs file clutter");
+    for (int i = 0; i < oldlogfiles.length; i++) {
+      fs.delete(oldlogfiles[i].getPath(), true);
+      LOG.info("Deleted: " + oldlogfiles[i].getPath());
+    }
+  }
+
   /*
    * Rewrite all under hbase root dir.
    * Presumes that {...@link FSUtils#isMajorCompactedPre020(FileSystem, Path)}
@@ -390,7 +419,6 @@
     put.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER, 
         Writables.getBytes(oldHri));
     mr.put(put);
-    LOG.info("Enabled blockcache on " + oldHri.getRegionNameAsString());
   }
 
   /*
@@ -399,26 +427,25 @@
    */
   private boolean rewriteHRegionInfo(final HRegionInfo hri) {
     boolean result = false;
+    // Set flush size at 32k if a catalog table.
+    int catalogMemStoreFlushSize = 32 * 1024;
+    if (hri.isMetaRegion() &&
+        hri.getTableDesc().getMemStoreFlushSize() != catalogMemStoreFlushSize) 
{
+      hri.getTableDesc().setMemStoreFlushSize(catalogMemStoreFlushSize);
+      result = true;
+    }
     HColumnDescriptor hcd =
       hri.getTableDesc().getFamily(HConstants.CATALOG_FAMILY);
     if (hcd == null) {
       LOG.info("No info family in: " + hri.getRegionNameAsString());
       return result;
     }
-    // Set blockcache enabled.
+    // Set block cache on all tables.
     hcd.setBlockCacheEnabled(true);
+    // Set compression to none.  Previous was 'none'.  Needs to be upper-case.
+    // Any other compression we are turning off.  Have user enable it.
+    hcd.setCompressionType(Algorithm.NONE);
     return true;
-    
-    // TODO: Rewrite MEMCACHE_FLUSHSIZE as MEMSTORE_FLUSHSIZE – name has 
changed. 
-    // TODO: Remove tableindexer 'index' attribute index from TableDescriptor 
(See HBASE-1586) 
-    // TODO: TODO: Move of in-memory parameter from table to column family 
(from HTD to HCD). 
-    // TODO: Purge isInMemory, etc., methods from HTD as part of migration. 
-    
-
-    // TODO: Set the .META. and -ROOT- to flush at 16k?  32k?
-    // TODO: Enable block cache on all tables
-
-    // TODO: Clean up old region log files (HBASE-698) 
   }
 
 

Added: 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMigration.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMigration.java?rev=796542&view=auto
==============================================================================
--- hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMigration.java 
(added)
+++ hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/util/TestMigration.java 
Tue Jul 21 21:18:52 2009
@@ -0,0 +1,253 @@
+/**
+ * Copyright 2007 The Apache Software Foundation
+ *
+ * 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.hadoop.hbase.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseTestCase;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.MiniHBaseCluster;
+import org.apache.hadoop.hbase.MiniZooKeeperCluster;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HConnectionManager;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+
+/**
+ * Runs migration of filesystem from hbase 0.19 to hbase 0.20.
+ * Not part of general test suite because takes time.
+ */
+public class TestMigration extends HBaseTestCase {
+  private static final Log LOG = LogFactory.getLog(TestMigration.class);
+
+  // Expected count of rows in migrated table.
+  private static final int EXPECTED_COUNT = 3;
+
+  /**
+   * Test migration.
+   * @throws IOException 
+   * @throws InterruptedException 
+   */
+  public void testMigration() throws IOException, InterruptedException {
+    Path rootdir = getUnitTestdir(getName());
+    Path hbasedir = loadTestData(fs, rootdir);
+    assertTrue(fs.exists(hbasedir));
+    Migrate migrator = new Migrate(this.conf);
+    Path qualified = fs.makeQualified(hbasedir);
+    String uri = qualified.toString();
+    this.conf.set("hbase.rootdir", uri);
+    int result = migrator.run(new String [] {"upgrade"});
+    assertEquals(0, result);
+    verify();
+  }
+  
+  /*
+   * Load up test data.
+   * @param dfs
+   * @param rootDir
+   * @throws IOException
+   */
+  private Path loadTestData(final FileSystem dfs, final Path rootDir)
+  throws IOException {
+    String hbasedir = "hbase-0.19-two-small-tables";
+    InputStream is = this.getClass().getClassLoader().
+      getResourceAsStream("data/" + hbasedir + ".zip");
+    ZipInputStream zip = new ZipInputStream(is);
+    try {
+      unzip(zip, dfs, rootDir);
+    } finally {
+      zip.close();
+    }
+    return new Path(rootDir, hbasedir);
+  }
+
+  /*
+   * Verify can read the migrated table.
+   * @throws IOException
+   */
+  private void verify() throws IOException, InterruptedException {
+    // Delete any cached connections.  Need to do this because connection was
+    // created earlier when no master was around.  The fact that there was no
+    // master gets cached.  Need to delete so we go get master afresh.
+    HConnectionManager.deleteConnectionInfo(conf, false);
+    LOG.info("Start a cluster against migrated FS");
+    // Up number of retries.  Needed while cluster starts up. Its been set to 1
+    // above.
+    final int retries = 5;
+    this.conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER_KEY, retries);
+    // Note that this is done before we create the MiniHBaseCluster because we
+    // need to edit the config to add the ZooKeeper servers.
+    MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster();
+    int clientPort =
+      zooKeeperCluster.startup(new java.io.File(this.testDir.toString()));
+    conf.set("hbase.zookeeper.property.clientPort",
+      Integer.toString(clientPort));
+    MiniHBaseCluster cluster = new MiniHBaseCluster(this.conf, 1);
+    try {
+      HBaseAdmin hb = new HBaseAdmin(this.conf);
+      assertTrue(hb.isMasterRunning());
+      HTableDescriptor [] tables = hb.listTables();
+      assertEquals(2, tables.length);
+      boolean foundTable = false;
+      // Just look at table 'a'.
+      final String tablenameStr = "a";
+      final byte [] tablename = Bytes.toBytes(tablenameStr);
+      for (int i = 0; i < tables.length; i++) {
+        byte [] tableName = tables[i].getName();
+        if (Bytes.equals(tablename, tables[i].getName())) {
+          foundTable = true;
+          break;
+        }
+      }
+      assertTrue(foundTable);
+      LOG.info(tablenameStr + " exists.  Now waiting till startcode " +
+        "changes before opening a scanner");
+      waitOnStartCodeChange(retries);
+      // Delete again so we go get it all fresh.
+      HConnectionManager.deleteConnectionInfo(conf, false);
+      HTable t = new HTable(this.conf, tablename);
+      int count = 0;
+      LOG.info("OPENING SCANNER");
+      Scan scan = new Scan();
+      ResultScanner s = t.getScanner(scan);
+      try {
+        for (Result r: s) {
+          if (r == null || r.size() == 0) {
+            break;
+          }
+          count++;
+        }
+        assertEquals(EXPECTED_COUNT, count);
+      } finally {
+        s.close();
+      }
+    } finally {
+      HConnectionManager.deleteConnectionInfo(conf, false);
+      cluster.shutdown();
+      try {
+        zooKeeperCluster.shutdown();
+      } catch (IOException e) {
+        LOG.warn("Shutting down ZooKeeper cluster", e);
+      }
+    }
+  }
+
+  /*
+   * Wait till the startcode changes before we put up a scanner.  Otherwise
+   * we tend to hang, at least on hudson and I've had it time to time on
+   * my laptop.  The hang is down in RPC Client doing its call.  It
+   * never returns though the socket has a read timeout of 60 seconds by
+   * default. St.Ack
+   * @param retries How many retries to run.
+   * @throws IOException
+   */
+  private void waitOnStartCodeChange(final int retries) throws IOException {
+    HTable m = new HTable(this.conf, HConstants.META_TABLE_NAME);
+    // This is the start code that is in the old data.
+    long oldStartCode = 1199736332062L;
+    // This is the first row for the TestTable that is in the old data.
+    byte [] row = Bytes.toBytes("TestUpgrade,,1199736362468");
+    long pause = conf.getLong("hbase.client.pause", 5 * 1000);
+    long startcode = -1;
+    boolean changed = false;
+    for (int i = 0; i < retries; i++) {
+      Get get = new Get(row);
+      get.addColumn(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER);
+      Result res = m.get(get);
+      KeyValue [] kvs = res.raw();
+      if(kvs.length <= 0){
+        return;
+      }
+      byte [] value = kvs[0].getValue();
+      startcode = Bytes.toLong(value);
+      if (startcode != oldStartCode) {
+        changed = true;
+        break;
+      }
+      if ((i + 1) != retries) {
+        try {
+          Thread.sleep(pause);
+        } catch (InterruptedException e) {
+          // continue
+        }
+      }
+    }
+    // If after all attempts startcode has not changed, fail.
+    if (!changed) {
+      throw new IOException("Startcode didn't change after " + retries +
+        " attempts");
+    }
+  }
+
+  private void unzip(ZipInputStream zip, FileSystem dfs, Path rootDir)
+  throws IOException {
+    ZipEntry e = null;
+    while ((e = zip.getNextEntry()) != null)  {
+      if (e.isDirectory()) {
+        dfs.mkdirs(new Path(rootDir, e.getName()));
+      } else {
+        FSDataOutputStream out = dfs.create(new Path(rootDir, e.getName()));
+        byte[] buffer = new byte[4096];
+        int len;
+        do {
+          len = zip.read(buffer);
+          if (len > 0) {
+            out.write(buffer, 0, len);
+          }
+        } while (len > 0);
+        out.close();
+      }
+      zip.closeEntry();
+    }
+  }
+  
+  @SuppressWarnings("unused")
+  private void listPaths(FileSystem filesystem, Path dir, int rootdirlength)
+  throws IOException {
+    FileStatus[] stats = filesystem.listStatus(dir);
+    if (stats == null || stats.length == 0) {
+      return;
+    }
+    for (int i = 0; i < stats.length; i++) {
+      String path = stats[i].getPath().toString();
+      if (stats[i].isDir()) {
+        System.out.println("d " + path);
+        listPaths(filesystem, stats[i].getPath(), rootdirlength);
+      } else {
+        System.out.println("f " + path + " size=" + stats[i].getLen());
+      }
+    }
+  }
+}
\ No newline at end of file


Reply via email to