Added: zookeeper/trunk/src/java/test/org/apache/zookeeper/test/MultiTransactionTest.java URL: http://svn.apache.org/viewvc/zookeeper/trunk/src/java/test/org/apache/zookeeper/test/MultiTransactionTest.java?rev=1141746&view=auto ============================================================================== --- zookeeper/trunk/src/java/test/org/apache/zookeeper/test/MultiTransactionTest.java (added) +++ zookeeper/trunk/src/java/test/org/apache/zookeeper/test/MultiTransactionTest.java Thu Jun 30 22:53:28 2011 @@ -0,0 +1,230 @@ +/* + * 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.zookeeper.test; + +import org.apache.log4j.Logger; +import org.apache.zookeeper.*; +import org.apache.zookeeper.ZooDefs.Ids; +import org.apache.zookeeper.server.ServerCnxnFactory; +import org.apache.zookeeper.server.SyncRequestProcessor; +import org.apache.zookeeper.server.ZooKeeperServer; +import org.apache.zookeeper.OpResult.ErrorResult; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; + +import org.apache.zookeeper.data.Stat; + +import static org.apache.zookeeper.test.ClientBase.CONNECTION_TIMEOUT; + +public class MultiTransactionTest extends ZKTestCase implements Watcher { + private static final Logger LOG = Logger.getLogger(MultiTransactionTest.class); + + private static final String HOSTPORT = "127.0.0.1:" + PortAssignment.unique(); + + private ZooKeeper zk; + private ServerCnxnFactory serverFactory; + + @Override + public void process(WatchedEvent event) { + // ignore + } + + @Before + public void setupZk() throws Exception { + File tmpDir = ClientBase.createTmpDir(); + ClientBase.setupTestEnv(); + ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000); + SyncRequestProcessor.setSnapCount(150); + final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]); + serverFactory = ServerCnxnFactory.createFactory(PORT, -1); + serverFactory.startup(zks); + LOG.info("starting up the zookeeper server .. waiting"); + Assert.assertTrue("waiting for server being up", + ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT)); + zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this); + } + + @After + public void shutdownServer() throws Exception { + zk.close(); + serverFactory.shutdown(); + } + + @Test + public void testCreate() throws Exception { + List<OpResult> results = new ArrayList<OpResult>(); + + results = zk.multi(Arrays.asList( + Op.create("/multi0", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.create("/multi1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.create("/multi2", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) + )); + zk.getData("/multi0", false, null); + zk.getData("/multi1", false, null); + zk.getData("/multi2", false, null); + } + + @Test + public void testCreateDelete() throws Exception { + + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.delete("/multi", 0) + )); + + // '/multi' should have been deleted + Assert.assertNull(zk.exists("/multi", null)); + } + + @Test + public void testInvalidVersion() throws Exception { + + try { + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.delete("/multi", 1) + )); + Assert.fail("delete /multi should have failed"); + } catch (KeeperException e) { + /* PASS */ + } + } + + @Test + public void testNestedCreate() throws Exception { + + zk.multi(Arrays.asList( + /* Create */ + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.create("/multi/a", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.create("/multi/a/1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + + /* Delete */ + Op.delete("/multi/a/1", 0), + Op.delete("/multi/a", 0), + Op.delete("/multi", 0) + )); + + //Verify tree deleted + Assert.assertNull(zk.exists("/multi/a/1", null)); + Assert.assertNull(zk.exists("/multi/a", null)); + Assert.assertNull(zk.exists("/multi", null)); + } + + @Test + public void testSetData() throws Exception { + + String[] names = {"/multi0", "/multi1", "/multi2"}; + List<Op> ops = new ArrayList<Op>(); + + for (int i = 0; i < names.length; i++) { + ops.add(Op.create(names[i], new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)); + ops.add(Op.setData(names[i], names[i].getBytes(), 0)); + } + + zk.multi(ops) ; + + for (int i = 0; i < names.length; i++) { + Assert.assertArrayEquals(names[i].getBytes(), zk.getData(names[i], false, null)); + } + } + + @Test + public void testUpdateConflict() throws Exception { + + Assert.assertNull(zk.exists("/multi", null)); + + try { + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.setData("/multi", "X".getBytes(), 0), + Op.setData("/multi", "Y".getBytes(), 0) + )); + Assert.fail("Should have thrown a KeeperException for invalid version"); + } catch (KeeperException e) { + //PASS + LOG.error("STACKTRACE: " + e); + } + + Assert.assertNull(zk.exists("/multi", null)); + + //Updating version solves conflict -- order matters + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.setData("/multi", "X".getBytes(), 0), + Op.setData("/multi", "Y".getBytes(), 1) + )); + + Assert.assertArrayEquals(zk.getData("/multi", false, null), "Y".getBytes()); + } + + @Test + public void TestDeleteUpdateConflict() throws Exception { + + /* Delete of a node folowed by an update of the (now) deleted node */ + try { + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.delete("/multi", 0), + Op.setData("/multi", "Y".getBytes(), 0) + )); + Assert.fail("/multi should have been deleted so setData should have failed"); + } catch (KeeperException e) { + /* PASS */ + } + + // '/multi' should never have been created as entire op should fail + Assert.assertNull(zk.exists("/multi", null)) ; + } + + @Test + public void TestGetResults() throws Exception { + /* Delete of a node folowed by an update of the (now) deleted node */ + try { + zk.multi(Arrays.asList( + Op.create("/multi", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT), + Op.delete("/multi", 0), + Op.setData("/multi", "Y".getBytes(), 0), + Op.create("/foo", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT) + )); + Assert.fail("/multi should have been deleted so setData should have failed"); + } catch (KeeperException e) { + // '/multi' should never have been created as entire op should fail + Assert.assertNull(zk.exists("/multi", null)); + + for (OpResult r : e.getResults()) { + LOG.info("RESULT==> " + r); + if (r instanceof ErrorResult) { + ErrorResult er = (ErrorResult) r; + LOG.info("ERROR RESULT: " + er + " ERR=>" + KeeperException.Code.get(er.getErr())); + } + } + } + } + + + +}
Modified: zookeeper/trunk/src/zookeeper.jute URL: http://svn.apache.org/viewvc/zookeeper/trunk/src/zookeeper.jute?rev=1141746&r1=1141745&r2=1141746&view=diff ============================================================================== --- zookeeper/trunk/src/zookeeper.jute (original) +++ zookeeper/trunk/src/zookeeper.jute Thu Jun 30 22:53:28 2011 @@ -21,7 +21,7 @@ module org.apache.zookeeper.data { ustring scheme; ustring id; } - class ACL { + class ACL { int perms; Id id; } @@ -66,12 +66,6 @@ module org.apache.zookeeper.data { } module org.apache.zookeeper.proto { - class op_result_t { - int rc; - int op; - buffer response; - } - class ConnectRequest { int protocolVersion; long lastZxidSeen; @@ -95,6 +89,11 @@ module org.apache.zookeeper.proto { int xid; int type; } + class MultiHeader { + int type; + boolean done; + int err; + } class AuthPacket { int type; ustring scheme; @@ -135,6 +134,10 @@ module org.apache.zookeeper.proto { ustring path; boolean watch; } + class CheckVersionRequest { + ustring path; + int version; + } class GetMaxChildrenRequest { ustring path; } @@ -167,7 +170,9 @@ module org.apache.zookeeper.proto { int state; // state of the Keeper client runtime ustring path; } - + class ErrorResponse { + int err; + } class CreateResponse { ustring path; } @@ -245,6 +250,10 @@ module org.apache.zookeeper.txn { buffer data; int version; } + class CheckVersionTxn { + ustring path; + int version; + } class SetACLTxn { ustring path; vector<org.apache.zookeeper.data.ACL> acl; @@ -260,4 +269,11 @@ module org.apache.zookeeper.txn { class ErrorTxn { int err; } + class Txn { + int type; + buffer data; + } + class MultiTxn { + vector<org.apache.zookeeper.txn.Txn> txns; + } }
