/**
* 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.hive.ql.lockmgr;
import static org.mockito.Mockito.*;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.api.FieldSchema;
import org.apache.hadoop.hive.ql.Context;
import org.apache.hadoop.hive.ql.ErrorMsg;
import org.apache.hadoop.hive.ql.Driver.DriverState;
import org.apache.hadoop.hive.ql.Driver.LockedDriverState;
import org.apache.hadoop.hive.ql.QueryPlan;
import org.apache.hadoop.hive.ql.hooks.ReadEntity;
import org.apache.hadoop.hive.ql.hooks.WriteEntity;
import org.apache.hadoop.hive.ql.lockmgr.HiveLockObject.HiveLockObjectData;
import org.apache.hadoop.hive.ql.lockmgr.zookeeper.ZooKeeperHiveLock;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.session.SessionState;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class TestDummyTxnManager {
private final HiveConf conf = new HiveConf();
private HiveTxnManager txnMgr;
private Context ctx;
private int nextInput = 1;
@Mock
HiveLockManager mockLockManager;
@Mock
QueryPlan mockQueryPlan;
@Before
public void setUp() throws Exception {
conf.setBoolVar(HiveConf.ConfVars.HIVE_SUPPORT_CONCURRENCY, true);
conf.setVar(HiveConf.ConfVars.HIVE_TXN_MANAGER, DummyTxnManager.class.getName());
conf
.setVar(HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER,
"org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory");
SessionState.start(conf);
ctx = new Context(conf);
txnMgr = TxnManagerFactory.getTxnManagerFactory().getTxnManager(conf);
Assert.assertTrue(txnMgr instanceof DummyTxnManager);
// Use reflection to set LockManager since creating the object using the
// relection in DummyTxnManager won't take Mocked object
Field field = DummyTxnManager.class.getDeclaredField("lockMgr");
field.setAccessible(true);
field.set(txnMgr, mockLockManager);
}
@After
public void tearDown() throws Exception {
if (txnMgr != null) txnMgr.closeTxnManager();
}
/**
* Verifies the current database object is not locked if the table read is against different database
* @throws Exception
*/
@Test
public void testSingleReadTable() throws Exception {
// Setup
SessionState.get().setCurrentDatabase("db1");
List<HiveLock> expectedLocks = new ArrayList<HiveLock>();
expectedLocks.add(new ZooKeeperHiveLock("default", new HiveLockObject(), HiveLockMode.SHARED));
expectedLocks.add(new ZooKeeperHiveLock("default.table1", new HiveLockObject(), HiveLockMode.SHARED));
LockedDriverState lDrvState = new LockedDriverState();
LockedDriverState lDrvInp = new LockedDriverState();
lDrvInp.driverState = DriverState.INTERRUPT;
LockException lEx = new LockException(ErrorMsg.LOCK_ACQUIRE_CANCELLED.getMsg());
when(mockLockManager.lock(anyListOf(HiveLockObj.class), eq(false), eq(lDrvState))).thenReturn(expectedLocks);
when(mockLockManager.lock(anyListOf(HiveLockObj.class), eq(false), eq(lDrvInp))).thenThrow(lEx);
doNothing().when(mockLockManager).setContext(any(HiveLockManagerCtx.class));
doNothing().when(mockLockManager).close();
ArgumentCaptor<List> lockObjsCaptor = ArgumentCaptor.forClass(List.class);
when(mockQueryPlan.getInputs()).thenReturn(createReadEntities());
when(mockQueryPlan.getOutputs()).thenReturn(new HashSet<WriteEntity>());
// Execute
txnMgr.acquireLocks(mockQueryPlan, ctx, "fred", lDrvState);
// Verify
Assert.assertEquals("db1", SessionState.get().getCurrentDatabase());
List<HiveLock> resultLocks = ctx.getHiveLocks();
Assert.assertEquals(expectedLocks.size(), resultLocks.size());
Assert.assertEquals(expectedLocks.get(0).getHiveLockMode(), resultLocks.get(0).getHiveLockMode());
Assert.assertEquals(expectedLocks.get(0).getHiveLockObject().getName(), resultLocks.get(0).getHiveLockObject().getName());
Assert.assertEquals(expectedLocks.get(1).getHiveLockMode(), resultLocks.get(1).getHiveLockMode());
Assert.assertEquals(expectedLocks.get(0).getHiveLockObject().getName(), resultLocks.get(0).getHiveLockObject().getName());
verify(mockLockManager).lock(lockObjsCaptor.capture(), eq(false), eq(lDrvState));
List<HiveLockObj> lockObjs = lockObjsCaptor.getValue();
Assert.assertEquals(2, lockObjs.size());
Assert.assertEquals("default", lockObjs.get(0).getName());
Assert.assertEquals(HiveLockMode.SHARED, lockObjs.get(0).mode);
Assert.assertEquals("default/table1", lockObjs.get(1).getName());
Assert.assertEquals(HiveLockMode.SHARED, lockObjs.get(1).mode);
// Execute
try {
txnMgr.acquireLocks(mockQueryPlan, ctx, "fred", lDrvInp);
Assert.fail();
} catch(LockException le) {
Assert.assertEquals(le.getMessage(), ErrorMsg.LOCK_ACQUIRE_CANCELLED.getMsg());
}
}
@Test
public void testDedupLockObjects() {
List<HiveLockObj> lockObjs = new ArrayList<HiveLockObj>();
String path1 = "path1";
String path2 = "path2";
HiveLockObjectData lockData1 = new HiveLockObjectData(
"query1", "1", "IMPLICIT", "drop table table1", conf);
HiveLockObjectData lockData2 = new HiveLockObjectData(
"query1", "1", "IMPLICIT", "drop table table1", conf);
// Start with the following locks:
// [path1, shared]
// [path1, exclusive]
// [path2, shared]
// [path2, shared]
// [path2, shared]
lockObjs.add(new HiveLockObj(new HiveLockObject(path1, lockData1), HiveLockMode.SHARED));
String name1 = lockObjs.get(lockObjs.size() - 1).getName();
lockObjs.add(new HiveLockObj(new HiveLockObject(path1, lockData1), HiveLockMode.EXCLUSIVE));
lockObjs.add(new HiveLockObj(new HiveLockObject(path2, lockData2), HiveLockMode.SHARED));
String name2 = lockObjs.get(lockObjs.size() - 1).getName();
lockObjs.add(new HiveLockObj(new HiveLockObject(path2, lockData2), HiveLockMode.SHARED));
lockObjs.add(new HiveLockObj(new HiveLockObject(path2, lockData2), HiveLockMode.SHARED));
DummyTxnManager.dedupLockObjects(lockObjs);
// After dedup we should be left with 2 locks:
// [path1, exclusive]
// [path2, shared]
Assert.assertEquals("Locks should be deduped", 2, lockObjs.size());
Comparator<HiveLockObj> cmp = new Comparator<HiveLockObj>() {
@Override
public int compare(HiveLockObj lock1, HiveLockObj lock2) {
return lock1.getName().compareTo(lock2.getName());
}
};
Collections.sort(lockObjs, cmp);
HiveLockObj lockObj = lockObjs.get(0);
Assert.assertEquals(name1, lockObj.getName());
Assert.assertEquals(HiveLockMode.EXCLUSIVE, lockObj.getMode());
lockObj = lockObjs.get(1);
Assert.assertEquals(name2, lockObj.getName());
Assert.assertEquals(HiveLockMode.SHARED, lockObj.getMode());
}
private HashSet<ReadEntity> createReadEntities() {
HashSet<ReadEntity> readEntities = new HashSet<ReadEntity>();
ReadEntity re = new ReadEntity(newTable(false));
readEntities.add(re);
return readEntities;
}
private Table newTable(boolean isPartitioned) {
Table t = new Table("default", "table" + Integer.toString(nextInput++));
if (isPartitioned) {
FieldSchema fs = new FieldSchema();
fs.setName("version");
fs.setType("String");
List<FieldSchema> partCols = new ArrayList<FieldSchema>(1);
partCols.add(fs);
t.setPartCols(partCols);
}
return t;
}
}