HADOOP-1614 [hbase] HClient does not protect itself from simultaneous updates
git-svn-id: https://svn.apache.org/repos/asf/lucene/hadoop/trunk/src/contrib/hbase@556359 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4ed118700d
commit
5463de47b3
|
@ -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
|
||||||
|
|
|
@ -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 {
|
public synchronized long startUpdate(final Text row) throws IOException {
|
||||||
long lockid = -1;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue