View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.zookeeper;
22  
23  
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertTrue;
26  
27  import java.util.LinkedList;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.Abortable;
33  import org.apache.hadoop.hbase.HBaseTestingUtility;
34  import org.apache.hadoop.hbase.testclassification.MediumTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp;
37  import org.apache.zookeeper.KeeperException;
38  import org.junit.AfterClass;
39  import org.junit.BeforeClass;
40  import org.junit.Test;
41  import org.junit.experimental.categories.Category;
42  
43  /**
44   * Test ZooKeeper multi-update functionality
45   */
46  @Category(MediumTests.class)
47  public class TestZKMulti {
48    private static final Log LOG = LogFactory.getLog(TestZKMulti.class);
49    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
50    private static ZooKeeperWatcher zkw = null;
51  
52    @BeforeClass
53    public static void setUpBeforeClass() throws Exception {
54      TEST_UTIL.startMiniZKCluster();
55      Configuration conf = TEST_UTIL.getConfiguration();
56      conf.setBoolean("hbase.zookeeper.useMulti", true);
57      Abortable abortable = new Abortable() {
58        @Override
59        public void abort(String why, Throwable e) {
60          LOG.info(why, e);
61        }
62  
63        @Override
64        public boolean isAborted() {
65          return false;
66        }
67      };
68      zkw = new ZooKeeperWatcher(conf,
69        "TestZKMulti", abortable, true);
70    }
71  
72    @AfterClass
73    public static void tearDownAfterClass() throws Exception {
74      TEST_UTIL.shutdownMiniZKCluster();
75    }
76  
77    @Test
78    public void testSimpleMulti() throws Exception {
79      // null multi
80      ZKUtil.multiOrSequential(zkw, null, false);
81  
82      // empty multi
83      ZKUtil.multiOrSequential(zkw, new LinkedList<ZKUtilOp>(), false);
84  
85      // single create
86      String path = ZKUtil.joinZNode(zkw.baseZNode, "testSimpleMulti");
87      LinkedList<ZKUtilOp> singleCreate = new LinkedList<ZKUtilOp>();
88      singleCreate.add(ZKUtilOp.createAndFailSilent(path, new byte[0]));
89      ZKUtil.multiOrSequential(zkw, singleCreate, false);
90      assertTrue(ZKUtil.checkExists(zkw, path) != -1);
91  
92      // single setdata
93      LinkedList<ZKUtilOp> singleSetData = new LinkedList<ZKUtilOp>();
94      byte [] data = Bytes.toBytes("foobar");
95      singleSetData.add(ZKUtilOp.setData(path, data));
96      ZKUtil.multiOrSequential(zkw, singleSetData, false);
97      assertTrue(Bytes.equals(ZKUtil.getData(zkw, path), data));
98  
99      // single delete
100     LinkedList<ZKUtilOp> singleDelete = new LinkedList<ZKUtilOp>();
101     singleDelete.add(ZKUtilOp.deleteNodeFailSilent(path));
102     ZKUtil.multiOrSequential(zkw, singleDelete, false);
103     assertTrue(ZKUtil.checkExists(zkw, path) == -1);
104   }
105 
106   @Test
107   public void testComplexMulti() throws Exception {
108     String path1 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti1");
109     String path2 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti2");
110     String path3 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti3");
111     String path4 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti4");
112     String path5 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti5");
113     String path6 = ZKUtil.joinZNode(zkw.baseZNode, "testComplexMulti6");
114     // create 4 nodes that we'll setData on or delete later
115     LinkedList<ZKUtilOp> create4Nodes = new LinkedList<ZKUtilOp>();
116     create4Nodes.add(ZKUtilOp.createAndFailSilent(path1, Bytes.toBytes(path1)));
117     create4Nodes.add(ZKUtilOp.createAndFailSilent(path2, Bytes.toBytes(path2)));
118     create4Nodes.add(ZKUtilOp.createAndFailSilent(path3, Bytes.toBytes(path3)));
119     create4Nodes.add(ZKUtilOp.createAndFailSilent(path4, Bytes.toBytes(path4)));
120     ZKUtil.multiOrSequential(zkw, create4Nodes, false);
121     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1), Bytes.toBytes(path1)));
122     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path2), Bytes.toBytes(path2)));
123     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path3), Bytes.toBytes(path3)));
124     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path4), Bytes.toBytes(path4)));
125 
126     // do multiple of each operation (setData, delete, create)
127     LinkedList<ZKUtilOp> ops = new LinkedList<ZKUtilOp>();
128     // setData
129     ops.add(ZKUtilOp.setData(path1, Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1))));
130     ops.add(ZKUtilOp.setData(path2, Bytes.add(Bytes.toBytes(path2), Bytes.toBytes(path2))));
131     // delete
132     ops.add(ZKUtilOp.deleteNodeFailSilent(path3));
133     ops.add(ZKUtilOp.deleteNodeFailSilent(path4));
134     // create
135     ops.add(ZKUtilOp.createAndFailSilent(path5, Bytes.toBytes(path5)));
136     ops.add(ZKUtilOp.createAndFailSilent(path6, Bytes.toBytes(path6)));
137     ZKUtil.multiOrSequential(zkw, ops, false);
138     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1),
139       Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1))));
140     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path2),
141       Bytes.add(Bytes.toBytes(path2), Bytes.toBytes(path2))));
142     assertTrue(ZKUtil.checkExists(zkw, path3) == -1);
143     assertTrue(ZKUtil.checkExists(zkw, path4) == -1);
144     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path5), Bytes.toBytes(path5)));
145     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path6), Bytes.toBytes(path6)));
146   }
147 
148   @Test
149   public void testSingleFailure() throws Exception {
150     // try to delete a node that doesn't exist
151     boolean caughtNoNode = false;
152     String path = ZKUtil.joinZNode(zkw.baseZNode, "testSingleFailureZ");
153     LinkedList<ZKUtilOp> ops = new LinkedList<ZKUtilOp>();
154     ops.add(ZKUtilOp.deleteNodeFailSilent(path));
155     try {
156       ZKUtil.multiOrSequential(zkw, ops, false);
157     } catch (KeeperException.NoNodeException nne) {
158       caughtNoNode = true;
159     }
160     assertTrue(caughtNoNode);
161 
162     // try to setData on a node that doesn't exist
163     caughtNoNode = false;
164     ops = new LinkedList<ZKUtilOp>();
165     ops.add(ZKUtilOp.setData(path, Bytes.toBytes(path)));
166     try {
167       ZKUtil.multiOrSequential(zkw, ops, false);
168     } catch (KeeperException.NoNodeException nne) {
169       caughtNoNode = true;
170     }
171     assertTrue(caughtNoNode);
172 
173     // try to create on a node that already exists
174     boolean caughtNodeExists = false;
175     ops = new LinkedList<ZKUtilOp>();
176     ops.add(ZKUtilOp.createAndFailSilent(path, Bytes.toBytes(path)));
177     ZKUtil.multiOrSequential(zkw, ops, false);
178     try {
179       ZKUtil.multiOrSequential(zkw, ops, false);
180     } catch (KeeperException.NodeExistsException nee) {
181       caughtNodeExists = true;
182     }
183     assertTrue(caughtNodeExists);
184   }
185 
186   @Test
187   public void testSingleFailureInMulti() throws Exception {
188     // try a multi where all but one operation succeeds
189     String pathA = ZKUtil.joinZNode(zkw.baseZNode, "testSingleFailureInMultiA");
190     String pathB = ZKUtil.joinZNode(zkw.baseZNode, "testSingleFailureInMultiB");
191     String pathC = ZKUtil.joinZNode(zkw.baseZNode, "testSingleFailureInMultiC");
192     LinkedList<ZKUtilOp> ops = new LinkedList<ZKUtilOp>();
193     ops.add(ZKUtilOp.createAndFailSilent(pathA, Bytes.toBytes(pathA)));
194     ops.add(ZKUtilOp.createAndFailSilent(pathB, Bytes.toBytes(pathB)));
195     ops.add(ZKUtilOp.deleteNodeFailSilent(pathC));
196     boolean caughtNoNode = false;
197     try {
198       ZKUtil.multiOrSequential(zkw, ops, false);
199     } catch (KeeperException.NoNodeException nne) {
200       caughtNoNode = true;
201     }
202     assertTrue(caughtNoNode);
203     // assert that none of the operations succeeded
204     assertTrue(ZKUtil.checkExists(zkw, pathA) == -1);
205     assertTrue(ZKUtil.checkExists(zkw, pathB) == -1);
206     assertTrue(ZKUtil.checkExists(zkw, pathC) == -1);
207   }
208 
209   @Test
210   public void testMultiFailure() throws Exception {
211     String pathX = ZKUtil.joinZNode(zkw.baseZNode, "testMultiFailureX");
212     String pathY = ZKUtil.joinZNode(zkw.baseZNode, "testMultiFailureY");
213     String pathZ = ZKUtil.joinZNode(zkw.baseZNode, "testMultiFailureZ");
214     // create X that we will use to fail create later
215     LinkedList<ZKUtilOp> ops = new LinkedList<ZKUtilOp>();
216     ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX)));
217     ZKUtil.multiOrSequential(zkw, ops, false);
218 
219     // fail one of each create ,setData, delete
220     String pathV = ZKUtil.joinZNode(zkw.baseZNode, "testMultiFailureV");
221     String pathW = ZKUtil.joinZNode(zkw.baseZNode, "testMultiFailureW");
222     ops = new LinkedList<ZKUtilOp>();
223     ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX))); // fail  -- already exists
224     ops.add(ZKUtilOp.setData(pathY, Bytes.toBytes(pathY))); // fail -- doesn't exist
225     ops.add(ZKUtilOp.deleteNodeFailSilent(pathZ)); // fail -- doesn't exist
226     ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathV))); // pass
227     ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathW))); // pass
228     boolean caughtNodeExists = false;
229     try {
230       ZKUtil.multiOrSequential(zkw, ops, false);
231     } catch (KeeperException.NodeExistsException nee) {
232       // check first operation that fails throws exception
233       caughtNodeExists = true;
234     }
235     assertTrue(caughtNodeExists);
236     // check that no modifications were made
237     assertFalse(ZKUtil.checkExists(zkw, pathX) == -1);
238     assertTrue(ZKUtil.checkExists(zkw, pathY) == -1);
239     assertTrue(ZKUtil.checkExists(zkw, pathZ) == -1);
240     assertTrue(ZKUtil.checkExists(zkw, pathW) == -1);
241     assertTrue(ZKUtil.checkExists(zkw, pathV) == -1);
242 
243     // test that with multiple failures, throws an exception corresponding to first failure in list
244     ops = new LinkedList<ZKUtilOp>();
245     ops.add(ZKUtilOp.setData(pathY, Bytes.toBytes(pathY))); // fail -- doesn't exist
246     ops.add(ZKUtilOp.createAndFailSilent(pathX, Bytes.toBytes(pathX))); // fail -- exists
247     boolean caughtNoNode = false;
248     try {
249       ZKUtil.multiOrSequential(zkw, ops, false);
250     } catch (KeeperException.NoNodeException nne) {
251       // check first operation that fails throws exception
252       caughtNoNode = true;
253     }
254     assertTrue(caughtNoNode);
255     // check that no modifications were made
256     assertFalse(ZKUtil.checkExists(zkw, pathX) == -1);
257     assertTrue(ZKUtil.checkExists(zkw, pathY) == -1);
258     assertTrue(ZKUtil.checkExists(zkw, pathZ) == -1);
259     assertTrue(ZKUtil.checkExists(zkw, pathW) == -1);
260     assertTrue(ZKUtil.checkExists(zkw, pathV) == -1);
261   }
262 
263   @Test
264   public void testRunSequentialOnMultiFailure() throws Exception {
265     String path1 = ZKUtil.joinZNode(zkw.baseZNode, "runSequential1");
266     String path2 = ZKUtil.joinZNode(zkw.baseZNode, "runSequential2");
267     String path3 = ZKUtil.joinZNode(zkw.baseZNode, "runSequential3");
268     String path4 = ZKUtil.joinZNode(zkw.baseZNode, "runSequential4");
269 
270     // create some nodes that we will use later
271     LinkedList<ZKUtilOp> ops = new LinkedList<ZKUtilOp>();
272     ops.add(ZKUtilOp.createAndFailSilent(path1, Bytes.toBytes(path1)));
273     ops.add(ZKUtilOp.createAndFailSilent(path2, Bytes.toBytes(path2)));
274     ZKUtil.multiOrSequential(zkw, ops, false);
275 
276     // test that, even with operations that fail, the ones that would pass will pass
277     // with runSequentialOnMultiFailure
278     ops = new LinkedList<ZKUtilOp>();
279     ops.add(ZKUtilOp.setData(path1, Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1)))); // pass
280     ops.add(ZKUtilOp.deleteNodeFailSilent(path2)); // pass
281     ops.add(ZKUtilOp.deleteNodeFailSilent(path3)); // fail -- node doesn't exist
282     ops.add(ZKUtilOp.createAndFailSilent(path4,
283       Bytes.add(Bytes.toBytes(path4), Bytes.toBytes(path4)))); // pass
284     ZKUtil.multiOrSequential(zkw, ops, true);
285     assertTrue(Bytes.equals(ZKUtil.getData(zkw, path1),
286       Bytes.add(Bytes.toBytes(path1), Bytes.toBytes(path1))));
287     assertTrue(ZKUtil.checkExists(zkw, path2) == -1);
288     assertTrue(ZKUtil.checkExists(zkw, path3) == -1);
289     assertFalse(ZKUtil.checkExists(zkw, path4) == -1);
290   }
291 }