Quellcode durchsuchen

HADOOP-1614 [hbase] HClient does not protect itself from simultaneous updates

git-svn-id: https://svn.apache.org/repos/asf/lucene/hadoop/trunk@556359 13f79535-47bb-0310-9956-ffa450edef68
Jim Kellerman vor 18 Jahren
Ursprung
Commit
de6d403783

+ 1 - 0
src/contrib/hbase/CHANGES.txt

@@ -62,3 +62,4 @@ Trunk (unreleased changes)
  38. HADOOP-1574 Concurrent creates of a table named 'X' all succeed
  38. HADOOP-1574 Concurrent creates of a table named 'X' all succeed
  39. HADOOP-1581 Un-openable tablename bug
  39. HADOOP-1581 Un-openable tablename bug
  40. HADOOP-1607 [shell] Clear screen command (Edward Yoon via Stack)
  40. HADOOP-1607 [shell] Clear screen command (Edward Yoon via Stack)
+ 41. HADOOP-1614 [hbase] HClient does not protect itself from simultaneous updates

+ 27 - 4
src/contrib/hbase/src/java/org/apache/hadoop/hbase/HClient.java

@@ -59,6 +59,7 @@ public class HClient implements HConstants {
   int numRetries;
   int numRetries;
   private HMasterInterface master;
   private HMasterInterface master;
   private final Configuration conf;
   private final Configuration conf;
+  private long currentLockId;
   private Class<? extends HRegionInterface> serverInterfaceClass;
   private Class<? extends HRegionInterface> serverInterfaceClass;
   
   
   /*
   /*
@@ -120,6 +121,7 @@ public class HClient implements HConstants {
    */
    */
   public HClient(Configuration conf) {
   public HClient(Configuration conf) {
     this.conf = conf;
     this.conf = conf;
+    this.currentLockId = -1;
 
 
     this.pause = conf.getLong("hbase.client.pause", 30 * 1000);
     this.pause = conf.getLong("hbase.client.pause", 30 * 1000);
     this.numRetries = conf.getInt("hbase.client.retries.number", 5);
     this.numRetries = conf.getInt("hbase.client.retries.number", 5);
@@ -608,6 +610,9 @@ public class HClient implements HConstants {
     if(tableName == null || tableName.getLength() == 0) {
     if(tableName == null || tableName.getLength() == 0) {
       throw new IllegalArgumentException("table name cannot be null or zero length");
       throw new IllegalArgumentException("table name cannot be null or zero length");
     }
     }
+    if(this.currentLockId != -1) {
+      throw new IllegalStateException("update in progress");
+    }
     this.tableServers = getTableServers(tableName);
     this.tableServers = getTableServers(tableName);
   }
   }
   
   
@@ -1325,8 +1330,10 @@ public class HClient implements HConstants {
    * @return Row lockid.
    * @return Row lockid.
    * @throws IOException
    * @throws IOException
    */
    */
-  public long startUpdate(final Text row) throws IOException {
-    long lockid = -1;
+  public synchronized long startUpdate(final Text row) throws IOException {
+    if(this.currentLockId != -1) {
+      throw new IllegalStateException("update in progress");
+    }
     for(int tries = 0; tries < numRetries; tries++) {
     for(int tries = 0; tries < numRetries; tries++) {
       IOException e = null;
       IOException e = null;
       RegionLocation info = getRegionLocation(row);
       RegionLocation info = getRegionLocation(row);
@@ -1334,7 +1341,7 @@ public class HClient implements HConstants {
         currentServer = getHRegionConnection(info.serverAddress);
         currentServer = getHRegionConnection(info.serverAddress);
         currentRegion = info.regionInfo.regionName;
         currentRegion = info.regionInfo.regionName;
         clientid = rand.nextLong();
         clientid = rand.nextLong();
-        lockid = currentServer.startUpdate(currentRegion, clientid, row);
+        this.currentLockId = currentServer.startUpdate(currentRegion, clientid, row);
         break;
         break;
         
         
       } catch (IOException ex) {
       } catch (IOException ex) {
@@ -1359,7 +1366,7 @@ public class HClient implements HConstants {
         throw e;
         throw e;
       }
       }
     }
     }
-    return lockid;
+    return this.currentLockId;
   }
   }
   
   
   /** 
   /** 
@@ -1372,6 +1379,9 @@ public class HClient implements HConstants {
    * @throws IOException
    * @throws IOException
    */
    */
   public void put(long lockid, Text column, byte val[]) throws IOException {
   public void put(long lockid, Text column, byte val[]) throws IOException {
+    if(lockid != this.currentLockId) {
+      throw new IllegalArgumentException("invalid lockid");
+    }
     try {
     try {
       this.currentServer.put(this.currentRegion, this.clientid, lockid, column,
       this.currentServer.put(this.currentRegion, this.clientid, lockid, column,
         val);
         val);
@@ -1398,6 +1408,9 @@ public class HClient implements HConstants {
    * @throws IOException
    * @throws IOException
    */
    */
   public void delete(long lockid, Text column) throws IOException {
   public void delete(long lockid, Text column) throws IOException {
+    if(lockid != this.currentLockId) {
+      throw new IllegalArgumentException("invalid lockid");
+    }
     try {
     try {
       this.currentServer.delete(this.currentRegion, this.clientid, lockid,
       this.currentServer.delete(this.currentRegion, this.clientid, lockid,
         column);
         column);
@@ -1423,6 +1436,9 @@ public class HClient implements HConstants {
    * @throws IOException
    * @throws IOException
    */
    */
   public void abort(long lockid) throws IOException {
   public void abort(long lockid) throws IOException {
+    if(lockid != this.currentLockId) {
+      throw new IllegalArgumentException("invalid lockid");
+    }
     try {
     try {
       this.currentServer.abort(this.currentRegion, this.clientid, lockid);
       this.currentServer.abort(this.currentRegion, this.clientid, lockid);
     } catch(IOException e) {
     } catch(IOException e) {
@@ -1432,6 +1448,8 @@ public class HClient implements HConstants {
         e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
         e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
       }
       }
       throw e;
       throw e;
+    } finally {
+      this.currentLockId = -1;
     }
     }
   }
   }
   
   
@@ -1453,6 +1471,9 @@ public class HClient implements HConstants {
    * @throws IOException
    * @throws IOException
    */
    */
   public void commit(long lockid, long timestamp) throws IOException {
   public void commit(long lockid, long timestamp) throws IOException {
+    if(lockid != this.currentLockId) {
+      throw new IllegalArgumentException("invalid lockid");
+    }
     try {
     try {
       this.currentServer.commit(this.currentRegion, this.clientid, lockid,
       this.currentServer.commit(this.currentRegion, this.clientid, lockid,
           timestamp);
           timestamp);
@@ -1464,6 +1485,8 @@ public class HClient implements HConstants {
         e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
         e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
       }
       }
       throw e;
       throw e;
+    } finally {
+      this.currentLockId = -1;
     }
     }
   }
   }
   
   

+ 119 - 0
src/contrib/hbase/src/test/org/apache/hadoop/hbase/TestMultipleUpdates.java

@@ -0,0 +1,119 @@
+/**
+ * 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;
+
+import org.apache.hadoop.io.Text;
+
+/**
+ * Tests that HClient protects against multiple updates
+ */
+public class TestMultipleUpdates extends HBaseClusterTestCase {
+  private static final String CONTENTS_STR = "contents:";
+  private static final Text CONTENTS = new Text(CONTENTS_STR);
+  private static final byte[] value = { 1, 2, 3, 4 };
+
+  private HTableDescriptor desc = null;
+  private HClient client = null;
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    this.client = new HClient(conf);
+    this.desc = new HTableDescriptor("test");
+    desc.addFamily(new HColumnDescriptor(CONTENTS_STR));
+    try {
+      client.createTable(desc);
+      client.openTable(desc.getName());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  /** the test */
+  public void testMultipleUpdates() {
+    try {
+      long lockid = client.startUpdate(new Text("row1"));
+      
+      try {
+        long lockid2 = client.startUpdate(new Text("row2"));
+        throw new Exception("second startUpdate returned lock id " + lockid2);
+        
+      } catch (IllegalStateException i) {
+        // expected
+      }
+      
+      try {
+        client.openTable(HConstants.META_TABLE_NAME);
+        
+      } catch (IllegalStateException i) {
+        // expected
+      }
+      
+      long invalidid = 42;
+      
+      try {
+        client.put(invalidid, CONTENTS, value);
+        
+      } catch (IllegalArgumentException i) {
+        // expected
+      }
+      
+      try {
+        client.delete(invalidid, CONTENTS);
+        
+      } catch (IllegalArgumentException i) {
+        // expected
+      }
+      
+      try {
+        client.put(invalidid, CONTENTS, value);
+        
+      } catch (IllegalArgumentException i) {
+        // expected
+      }
+      
+      try {
+        client.abort(invalidid);
+        
+      } catch (IllegalArgumentException i) {
+        // expected
+      }
+      
+      try {
+        client.commit(invalidid);
+        
+      } catch (IllegalArgumentException i) {
+        // expected
+      }
+      
+      client.abort(lockid);
+      
+    } catch (Exception e) {
+      System.err.println("unexpected exception");
+      e.printStackTrace();
+      fail();
+    }
+  }
+}