001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.zookeeper; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNotEquals; 022import static org.junit.Assert.assertTrue; 023 024import java.util.ArrayList; 025import java.util.LinkedList; 026import java.util.List; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.Abortable; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseZKTestingUtility; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.testclassification.ZKTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp; 035import org.apache.zookeeper.CreateMode; 036import org.apache.zookeeper.KeeperException; 037import org.apache.zookeeper.Op; 038import org.apache.zookeeper.ZooDefs.Ids; 039import org.junit.AfterClass; 040import org.junit.BeforeClass; 041import org.junit.ClassRule; 042import org.junit.Test; 043import org.junit.experimental.categories.Category; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047/** 048 * Test ZooKeeper multi-update functionality. 049 */ 050@Category({ ZKTests.class, MediumTests.class }) 051public class TestZKMulti { 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestZKMulti.class); 055 056 private static final Logger LOG = LoggerFactory.getLogger(TestZKMulti.class); 057 private final static HBaseZKTestingUtility TEST_UTIL = new HBaseZKTestingUtility(); 058 private static ZKWatcher zkw = null; 059 060 @BeforeClass 061 public static void setUpBeforeClass() throws Exception { 062 TEST_UTIL.startMiniZKCluster(); 063 Configuration conf = TEST_UTIL.getConfiguration(); 064 Abortable abortable = new Abortable() { 065 @Override 066 public void abort(String why, Throwable e) { 067 LOG.info(why, e); 068 } 069 070 @Override 071 public boolean isAborted() { 072 return false; 073 } 074 }; 075 zkw = new ZKWatcher(conf, 076 "TestZKMulti", abortable, true); 077 } 078 079 @AfterClass 080 public static void tearDownAfterClass() throws Exception { 081 TEST_UTIL.shutdownMiniZKCluster(); 082 } 083 084 @Test 085 public void testSimpleMulti() throws Exception { 086 // null multi 087 ZKUtil.multiOrSequential(zkw, null, false); 088 089 // empty multi 090 ZKUtil.multiOrSequential(zkw, new LinkedList<>(), false); 091 092 // single create 093 String path = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testSimpleMulti"); 094 LinkedList<ZKUtilOp> singleCreate = new LinkedList<>(); 095 singleCreate.add(ZKUtilOp.createAndFailSilent(path, new byte[0])); 096 ZKUtil.multiOrSequential(zkw, singleCreate, false); 097 assertTrue(ZKUtil.checkExists(zkw, path) != -1); 098 099 // single setdata 100 LinkedList<ZKUtilOp> singleSetData = new LinkedList<>(); 101 byte [] data = Bytes.toBytes("foobar"); 102 singleSetData.add(ZKUtilOp.setData(path, data)); 103 ZKUtil.multiOrSequential(zkw, singleSetData, false); 104 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path), data)); 105 106 // single delete 107 LinkedList<ZKUtilOp> singleDelete = new LinkedList<>(); 108 singleDelete.add(ZKUtilOp.deleteNodeFailSilent(path)); 109 ZKUtil.multiOrSequential(zkw, singleDelete, false); 110 assertEquals(-1, ZKUtil.checkExists(zkw, path)); 111 } 112 113 @Test 114 public void testComplexMulti() throws Exception { 115 String path1 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti1"); 116 String path2 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti2"); 117 String path3 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti3"); 118 String path4 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti4"); 119 String path5 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti5"); 120 String path6 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testComplexMulti6"); 121 // create 4 nodes that we'll setData on or delete later 122 LinkedList<ZKUtilOp> create4Nodes = new LinkedList<>(); 123 create4Nodes.add(ZKUtilOp.createAndFailSilent(path1, Bytes.toBytes(path1))); 124 create4Nodes.add(ZKUtilOp.createAndFailSilent(path2, Bytes.toBytes(path2))); 125 create4Nodes.add(ZKUtilOp.createAndFailSilent(path3, Bytes.toBytes(path3))); 126 create4Nodes.add(ZKUtilOp.createAndFailSilent(path4, Bytes.toBytes(path4))); 127 ZKUtil.multiOrSequential(zkw, create4Nodes, false); 128 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1), Bytes.toBytes(path1))); 129 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path2), Bytes.toBytes(path2))); 130 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path3), Bytes.toBytes(path3))); 131 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path4), Bytes.toBytes(path4))); 132 133 // do multiple of each operation (setData, delete, create) 134 LinkedList<ZKUtilOp> ops = new LinkedList<>(); 135 // setData 136 ops.add(ZKUtilOp.setData(path1, Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1)))); 137 ops.add(ZKUtilOp.setData(path2, Bytes.add(Bytes.toBytes(path2), Bytes.toBytes(path2)))); 138 // delete 139 ops.add(ZKUtilOp.deleteNodeFailSilent(path3)); 140 ops.add(ZKUtilOp.deleteNodeFailSilent(path4)); 141 // create 142 ops.add(ZKUtilOp.createAndFailSilent(path5, Bytes.toBytes(path5))); 143 ops.add(ZKUtilOp.createAndFailSilent(path6, Bytes.toBytes(path6))); 144 ZKUtil.multiOrSequential(zkw, ops, false); 145 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1), 146 Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1)))); 147 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path2), 148 Bytes.add(Bytes.toBytes(path2), Bytes.toBytes(path2)))); 149 assertEquals(-1, ZKUtil.checkExists(zkw, path3)); 150 assertEquals(-1, ZKUtil.checkExists(zkw, path4)); 151 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path5), Bytes.toBytes(path5))); 152 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path6), Bytes.toBytes(path6))); 153 } 154 155 @Test 156 public void testSingleFailure() throws Exception { 157 // try to delete a node that doesn't exist 158 boolean caughtNoNode = false; 159 String path = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testSingleFailureZ"); 160 LinkedList<ZKUtilOp> ops = new LinkedList<>(); 161 ops.add(ZKUtilOp.deleteNodeFailSilent(path)); 162 try { 163 ZKUtil.multiOrSequential(zkw, ops, false); 164 } catch (KeeperException.NoNodeException nne) { 165 caughtNoNode = true; 166 } 167 assertTrue(caughtNoNode); 168 169 // try to setData on a node that doesn't exist 170 caughtNoNode = false; 171 ops = new LinkedList<>(); 172 ops.add(ZKUtilOp.setData(path, Bytes.toBytes(path))); 173 try { 174 ZKUtil.multiOrSequential(zkw, ops, false); 175 } catch (KeeperException.NoNodeException nne) { 176 caughtNoNode = true; 177 } 178 assertTrue(caughtNoNode); 179 180 // try to create on a node that already exists 181 boolean caughtNodeExists = false; 182 ops = new LinkedList<>(); 183 ops.add(ZKUtilOp.createAndFailSilent(path, Bytes.toBytes(path))); 184 ZKUtil.multiOrSequential(zkw, ops, false); 185 try { 186 ZKUtil.multiOrSequential(zkw, ops, false); 187 } catch (KeeperException.NodeExistsException nee) { 188 caughtNodeExists = true; 189 } 190 assertTrue(caughtNodeExists); 191 } 192 193 @Test 194 public void testSingleFailureInMulti() throws Exception { 195 // try a multi where all but one operation succeeds 196 String pathA = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testSingleFailureInMultiA"); 197 String pathB = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testSingleFailureInMultiB"); 198 String pathC = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testSingleFailureInMultiC"); 199 LinkedList<ZKUtilOp> ops = new LinkedList<>(); 200 ops.add(ZKUtilOp.createAndFailSilent(pathA, Bytes.toBytes(pathA))); 201 ops.add(ZKUtilOp.createAndFailSilent(pathB, Bytes.toBytes(pathB))); 202 ops.add(ZKUtilOp.deleteNodeFailSilent(pathC)); 203 boolean caughtNoNode = false; 204 try { 205 ZKUtil.multiOrSequential(zkw, ops, false); 206 } catch (KeeperException.NoNodeException nne) { 207 caughtNoNode = true; 208 } 209 assertTrue(caughtNoNode); 210 // assert that none of the operations succeeded 211 assertEquals(-1, ZKUtil.checkExists(zkw, pathA)); 212 assertEquals(-1, ZKUtil.checkExists(zkw, pathB)); 213 assertEquals(-1, ZKUtil.checkExists(zkw, pathC)); 214 } 215 216 @Test 217 public void testMultiFailure() throws Exception { 218 String pathX = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testMultiFailureX"); 219 String pathY = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testMultiFailureY"); 220 String pathZ = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testMultiFailureZ"); 221 // create X that we will use to fail create later 222 LinkedList<ZKUtilOp> ops = new LinkedList<>(); 223 ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX))); 224 ZKUtil.multiOrSequential(zkw, ops, false); 225 226 // fail one of each create ,setData, delete 227 String pathV = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testMultiFailureV"); 228 String pathW = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "testMultiFailureW"); 229 ops = new LinkedList<>(); 230 ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX))); // fail -- already exists 231 ops.add(ZKUtilOp.setData(pathY, Bytes.toBytes(pathY))); // fail -- doesn't exist 232 ops.add(ZKUtilOp.deleteNodeFailSilent(pathZ)); // fail -- doesn't exist 233 ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathV))); // pass 234 ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathW))); // pass 235 boolean caughtNodeExists = false; 236 try { 237 ZKUtil.multiOrSequential(zkw, ops, false); 238 } catch (KeeperException.NodeExistsException nee) { 239 // check first operation that fails throws exception 240 caughtNodeExists = true; 241 } 242 assertTrue(caughtNodeExists); 243 // check that no modifications were made 244 assertNotEquals(-1, ZKUtil.checkExists(zkw, pathX)); 245 assertEquals(-1, ZKUtil.checkExists(zkw, pathY)); 246 assertEquals(-1, ZKUtil.checkExists(zkw, pathZ)); 247 assertEquals(-1, ZKUtil.checkExists(zkw, pathW)); 248 assertEquals(-1, ZKUtil.checkExists(zkw, pathV)); 249 250 // test that with multiple failures, throws an exception corresponding to first failure in list 251 ops = new LinkedList<>(); 252 ops.add(ZKUtilOp.setData(pathY, Bytes.toBytes(pathY))); // fail -- doesn't exist 253 ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX))); // fail -- exists 254 boolean caughtNoNode = false; 255 try { 256 ZKUtil.multiOrSequential(zkw, ops, false); 257 } catch (KeeperException.NoNodeException nne) { 258 // check first operation that fails throws exception 259 caughtNoNode = true; 260 } 261 assertTrue(caughtNoNode); 262 // check that no modifications were made 263 assertNotEquals(-1, ZKUtil.checkExists(zkw, pathX)); 264 assertEquals(-1, ZKUtil.checkExists(zkw, pathY)); 265 assertEquals(-1, ZKUtil.checkExists(zkw, pathZ)); 266 assertEquals(-1, ZKUtil.checkExists(zkw, pathW)); 267 assertEquals(-1, ZKUtil.checkExists(zkw, pathV)); 268 } 269 270 @Test 271 public void testRunSequentialOnMultiFailure() throws Exception { 272 String path1 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "runSequential1"); 273 String path2 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "runSequential2"); 274 String path3 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "runSequential3"); 275 String path4 = ZNodePaths.joinZNode(zkw.getZNodePaths().baseZNode, "runSequential4"); 276 277 // create some nodes that we will use later 278 LinkedList<ZKUtilOp> ops = new LinkedList<>(); 279 ops.add(ZKUtilOp.createAndFailSilent(path1, Bytes.toBytes(path1))); 280 ops.add(ZKUtilOp.createAndFailSilent(path2, Bytes.toBytes(path2))); 281 ZKUtil.multiOrSequential(zkw, ops, false); 282 283 // test that, even with operations that fail, the ones that would pass will pass 284 // with runSequentialOnMultiFailure 285 ops = new LinkedList<>(); 286 ops.add(ZKUtilOp.setData(path1, Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1)))); // pass 287 ops.add(ZKUtilOp.deleteNodeFailSilent(path2)); // pass 288 ops.add(ZKUtilOp.deleteNodeFailSilent(path3)); // fail -- node doesn't exist 289 ops.add(ZKUtilOp.createAndFailSilent(path4, 290 Bytes.add(Bytes.toBytes(path4), Bytes.toBytes(path4)))); // pass 291 ZKUtil.multiOrSequential(zkw, ops, true); 292 assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1), 293 Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1)))); 294 assertEquals(-1, ZKUtil.checkExists(zkw, path2)); 295 assertEquals(-1, ZKUtil.checkExists(zkw, path3)); 296 assertNotEquals(-1, ZKUtil.checkExists(zkw, path4)); 297 } 298 299 /** 300 * Verifies that for the given root node, it should delete all the child nodes 301 * recursively using multi-update api. 302 */ 303 @Test 304 public void testdeleteChildrenRecursivelyMulti() throws Exception { 305 String parentZNode = "/testRootMulti"; 306 createZNodeTree(parentZNode); 307 308 ZKUtil.deleteChildrenRecursivelyMultiOrSequential(zkw, true, parentZNode); 309 310 assertTrue("Wrongly deleted parent znode!", 311 ZKUtil.checkExists(zkw, parentZNode) > -1); 312 List<String> children = zkw.getRecoverableZooKeeper().getChildren( 313 parentZNode, false); 314 assertEquals("Failed to delete child znodes!", 0, children.size()); 315 } 316 317 /** 318 * Verifies that for the given root node, it should delete all the nodes recursively using 319 * multi-update api. 320 */ 321 @Test 322 public void testDeleteNodeRecursivelyMulti() throws Exception { 323 String parentZNode = "/testdeleteNodeRecursivelyMulti"; 324 createZNodeTree(parentZNode); 325 326 ZKUtil.deleteNodeRecursively(zkw, parentZNode); 327 assertEquals("Parent znode should be deleted.", -1, ZKUtil.checkExists(zkw, parentZNode)); 328 } 329 330 @Test 331 public void testDeleteNodeRecursivelyMultiOrSequential() throws Exception { 332 String parentZNode1 = "/testdeleteNode1"; 333 String parentZNode2 = "/testdeleteNode2"; 334 String parentZNode3 = "/testdeleteNode3"; 335 createZNodeTree(parentZNode1); 336 createZNodeTree(parentZNode2); 337 createZNodeTree(parentZNode3); 338 339 ZKUtil.deleteNodeRecursivelyMultiOrSequential(zkw, false, parentZNode1, parentZNode2, 340 parentZNode3); 341 assertEquals("Parent znode 1 should be deleted.", -1, ZKUtil.checkExists(zkw, parentZNode1)); 342 assertEquals("Parent znode 2 should be deleted.", -1, ZKUtil.checkExists(zkw, parentZNode2)); 343 assertEquals("Parent znode 3 should be deleted.", -1, ZKUtil.checkExists(zkw, parentZNode3)); 344 } 345 346 @Test 347 public void testDeleteChildrenRecursivelyMultiOrSequential() throws Exception { 348 String parentZNode1 = "/testdeleteChildren1"; 349 String parentZNode2 = "/testdeleteChildren2"; 350 String parentZNode3 = "/testdeleteChildren3"; 351 createZNodeTree(parentZNode1); 352 createZNodeTree(parentZNode2); 353 createZNodeTree(parentZNode3); 354 355 ZKUtil.deleteChildrenRecursivelyMultiOrSequential(zkw, true, parentZNode1, parentZNode2, 356 parentZNode3); 357 358 assertTrue("Wrongly deleted parent znode 1!", ZKUtil.checkExists(zkw, parentZNode1) > -1); 359 List<String> children = zkw.getRecoverableZooKeeper().getChildren(parentZNode1, false); 360 assertEquals("Failed to delete child znodes of parent znode 1!", 0, children.size()); 361 362 assertTrue("Wrongly deleted parent znode 2!", ZKUtil.checkExists(zkw, parentZNode2) > -1); 363 children = zkw.getRecoverableZooKeeper().getChildren(parentZNode2, false); 364 assertEquals("Failed to delete child znodes of parent znode 1!", 0, children.size()); 365 366 assertTrue("Wrongly deleted parent znode 3!", ZKUtil.checkExists(zkw, parentZNode3) > -1); 367 children = zkw.getRecoverableZooKeeper().getChildren(parentZNode3, false); 368 assertEquals("Failed to delete child znodes of parent znode 1!", 0, children.size()); 369 } 370 371 private void createZNodeTree(String rootZNode) throws KeeperException, 372 InterruptedException { 373 List<Op> opList = new ArrayList<>(); 374 opList.add(Op.create(rootZNode, new byte[0], Ids.OPEN_ACL_UNSAFE, 375 CreateMode.PERSISTENT)); 376 int level = 0; 377 String parentZNode = rootZNode; 378 while (level < 10) { 379 // define parent node 380 parentZNode = parentZNode + "/" + level; 381 opList.add(Op.create(parentZNode, new byte[0], Ids.OPEN_ACL_UNSAFE, 382 CreateMode.PERSISTENT)); 383 int elements = 0; 384 // add elements to the parent node 385 while (elements < level) { 386 opList.add(Op.create(parentZNode + "/" + elements, new byte[0], 387 Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)); 388 elements++; 389 } 390 level++; 391 } 392 zkw.getRecoverableZooKeeper().multi(opList); 393 } 394}